57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
import * as Sentry from "@sentry/nextjs";
|
|
import { NextResponse } from "next/server";
|
|
import { requireClient, unauthorizedJson, UnauthorizedError } from "@/lib/nextcloud-session";
|
|
import { normalizePath } from "@/lib/paths";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
function json<T>(data: T, init?: { status?: number } & ResponseInit) {
|
|
return NextResponse.json(data, init);
|
|
}
|
|
|
|
export async function POST(req: Request) {
|
|
try {
|
|
const body = (await req.json().catch(() => ({}))) as {
|
|
from?: string;
|
|
to?: string;
|
|
};
|
|
|
|
if (!body?.from || !body?.to) {
|
|
return json({ error: "from and to are required" }, { status: 400 });
|
|
}
|
|
|
|
const from = normalizePath(body.from);
|
|
const to = normalizePath(body.to);
|
|
|
|
let client;
|
|
try {
|
|
client = await requireClient(req);
|
|
} catch (err) {
|
|
if (err instanceof UnauthorizedError) return unauthorizedJson();
|
|
throw err;
|
|
}
|
|
|
|
const result = await Sentry.startSpan(
|
|
{ op: "function", name: "api.files.copy" },
|
|
async (span) => {
|
|
span.setAttribute("path_from", from);
|
|
span.setAttribute("path_to", to);
|
|
const res = await client.copyFile(from, to);
|
|
return res;
|
|
},
|
|
);
|
|
|
|
return json(result);
|
|
} catch (error: unknown) {
|
|
Sentry.captureException(error);
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
const status = /409|conflict/i.test(message)
|
|
? 409
|
|
: /423|locked/i.test(message)
|
|
? 423
|
|
: 500;
|
|
return json({ error: "Failed to copy file", message }, { status });
|
|
}
|
|
}
|