diff --git a/src/app/api/admin/lesson-files/route.ts b/src/app/api/admin/lesson-files/route.ts index f4469ef..c515f98 100644 --- a/src/app/api/admin/lesson-files/route.ts +++ b/src/app/api/admin/lesson-files/route.ts @@ -5,14 +5,14 @@ import { prisma } from "@/lib/prisma"; import { uploadFile, deleteFile } from "@/lib/s3"; import { randomUUID } from "crypto"; -async function requireAdmin(req: NextRequest) { +async function requireAdmin() { const session = await auth.api.getSession({ headers: await headers() }); if (!session || session.user.role !== "admin") return null; return session; } export async function POST(req: NextRequest) { - if (!await requireAdmin(req)) { + if (!await requireAdmin()) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } @@ -22,20 +22,32 @@ export async function POST(req: NextRequest) { const label = (form.get("label") as string | null)?.trim() || null; if (!file || !lessonId) return NextResponse.json({ error: "Missing fields" }, { status: 400 }); + const name = label ?? file.name; + const existing = await prisma.lessonFile.findFirst({ where: { lessonId, name } }); + const ext = file.name.split(".").pop() ?? "bin"; const key = `lessons/${lessonId}/${randomUUID()}.${ext}`; const buffer = Buffer.from(await file.arrayBuffer()); const url = await uploadFile(key, buffer, file.type); - const lessonFile = await prisma.lessonFile.create({ - data: { lessonId, name: label ?? file.name, url, size: file.size }, - }); + if (existing) { + const oldKey = existing.url.split(`/${process.env.S3_BUCKET}/`)[1]; + if (oldKey) await deleteFile(oldKey).catch(() => {}); + const lessonFile = await prisma.lessonFile.update({ + where: { id: existing.id }, + data: { url, size: file.size }, + }); + return NextResponse.json(lessonFile); + } + const lessonFile = await prisma.lessonFile.create({ + data: { lessonId, name, url, size: file.size }, + }); return NextResponse.json(lessonFile); } export async function PATCH(req: NextRequest) { - if (!await requireAdmin(req)) { + if (!await requireAdmin()) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } @@ -51,12 +63,15 @@ export async function PATCH(req: NextRequest) { } export async function DELETE(req: NextRequest) { - if (!await requireAdmin(req)) { + if (!await requireAdmin()) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } - const { fileId, key } = await req.json(); - if (key) await deleteFile(key).catch(() => {}); + const { fileId, url } = await req.json(); + if (url) { + const key = (url as string).split(`/${process.env.S3_BUCKET}/`)[1]; + if (key) await deleteFile(key).catch(() => {}); + } await prisma.lessonFile.delete({ where: { id: fileId } }); return NextResponse.json({ ok: true }); } diff --git a/src/components/admin/lesson-files-manager.tsx b/src/components/admin/lesson-files-manager.tsx index c4685d9..8d6f5f8 100644 --- a/src/components/admin/lesson-files-manager.tsx +++ b/src/components/admin/lesson-files-manager.tsx @@ -36,12 +36,12 @@ export function LessonFilesManager({ lessonId, initialFiles }: { lessonId: strin e.target.value = ""; } - async function handleDelete(fileId: string) { + async function handleDelete(fileId: string, url: string) { if (!confirm("Удалить файл?")) return; await fetch("/api/admin/lesson-files", { method: "DELETE", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ fileId }), + body: JSON.stringify({ fileId, url }), }); setFiles((prev) => prev.filter((f) => f.id !== fileId)); } @@ -122,7 +122,7 @@ export function LessonFilesManager({ lessonId, initialFiles }: { lessonId: strin