Add labeled file materials with format badge

- Store human-readable label in LessonFile.name via optional label field on upload
- Add PATCH endpoint to rename existing files inline
- Admin: label input before upload, click-to-edit inline rename
- Student: colored format badge (PDF/DOCX/XLSX/ZIP/etc) replaces paperclip emoji

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 11:55:07 +05:00
parent 15df731e37
commit 39d84a3db2
4 changed files with 182 additions and 19 deletions
+26 -5
View File
@@ -5,15 +5,21 @@ import { prisma } from "@/lib/prisma";
import { uploadFile, deleteFile } from "@/lib/s3";
import { randomUUID } from "crypto";
export async function POST(req: NextRequest) {
async function requireAdmin(req: NextRequest) {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") {
if (!session || session.user.role !== "admin") return null;
return session;
}
export async function POST(req: NextRequest) {
if (!await requireAdmin(req)) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const form = await req.formData();
const file = form.get("file") as File | null;
const lessonId = form.get("lessonId") as string | null;
const label = (form.get("label") as string | null)?.trim() || null;
if (!file || !lessonId) return NextResponse.json({ error: "Missing fields" }, { status: 400 });
const ext = file.name.split(".").pop() ?? "bin";
@@ -22,15 +28,30 @@ export async function POST(req: NextRequest) {
const url = await uploadFile(key, buffer, file.type);
const lessonFile = await prisma.lessonFile.create({
data: { lessonId, name: file.name, url, size: file.size },
data: { lessonId, name: label ?? file.name, url, size: file.size },
});
return NextResponse.json(lessonFile);
}
export async function PATCH(req: NextRequest) {
if (!await requireAdmin(req)) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const { fileId, label } = await req.json();
if (!fileId || typeof label !== "string") {
return NextResponse.json({ error: "Missing fields" }, { status: 400 });
}
const updated = await prisma.lessonFile.update({
where: { id: fileId },
data: { name: label.trim() || undefined },
});
return NextResponse.json(updated);
}
export async function DELETE(req: NextRequest) {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") {
if (!await requireAdmin(req)) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}