41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
|
|
/**
|
||
|
|
* Admin-triggered storage migration. Same code path as `scripts/migrate-storage.ts`
|
||
|
|
* (both delegate to `runMigration()` in `@/lib/storage/migrate`). Body:
|
||
|
|
* { from: 's3'|'filesystem', to: 's3'|'filesystem', dryRun?: boolean }
|
||
|
|
*
|
||
|
|
* Super-admin only. The `/[portSlug]/admin` segment is already gated; this
|
||
|
|
* route enforces the same constraint defensively.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { NextResponse } from 'next/server';
|
||
|
|
import { z } from 'zod';
|
||
|
|
|
||
|
|
import { withAuth } from '@/lib/api/helpers';
|
||
|
|
import { parseBody } from '@/lib/api/route-helpers';
|
||
|
|
import { errorResponse, ForbiddenError } from '@/lib/errors';
|
||
|
|
import { runMigration } from '@/lib/storage/migrate';
|
||
|
|
|
||
|
|
const schema = z.object({
|
||
|
|
from: z.enum(['s3', 'filesystem']),
|
||
|
|
to: z.enum(['s3', 'filesystem']),
|
||
|
|
dryRun: z.boolean().default(false),
|
||
|
|
});
|
||
|
|
|
||
|
|
export const runtime = 'nodejs';
|
||
|
|
|
||
|
|
export const POST = withAuth(async (req, ctx) => {
|
||
|
|
try {
|
||
|
|
if (!ctx.isSuperAdmin) {
|
||
|
|
throw new ForbiddenError('Super admin only');
|
||
|
|
}
|
||
|
|
const body = await parseBody(req, schema);
|
||
|
|
if (body.from === body.to) {
|
||
|
|
return NextResponse.json({ error: 'from and to must differ' }, { status: 400 });
|
||
|
|
}
|
||
|
|
const result = await runMigration({ ...body, userId: ctx.userId });
|
||
|
|
return NextResponse.json({ data: result });
|
||
|
|
} catch (error) {
|
||
|
|
return errorResponse(error);
|
||
|
|
}
|
||
|
|
});
|