import { NextResponse } from "next/server"; import { writeFile, mkdir, unlink } from "fs/promises"; import { auth } from "@/lib/auth"; import path from "path"; import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); export const config = { api: { bodyParser: { sizeLimit: '50mb', }, }, }; export async function POST(req: Request) { try { const session = await auth(); if (!session?.user) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const type = new URL(req.url).searchParams.get('type') as "music" | "avatar" | "background"; if (!type) { return NextResponse.json({ error: "Type is required" }, { status: 400 }); } const contentType = req.headers.get("content-type"); if (!contentType) { return NextResponse.json({ error: "Content-Type is required" }, { status: 400 }); } const buffer = await req.arrayBuffer(); const fileSize = buffer.byteLength; // Validate file size const maxSize = type === "music" ? 52428800 : 8388608; // 50MB for music, 8MB for images if (fileSize > maxSize) { return NextResponse.json({ error: `File too large. Max size is ${maxSize === 52428800 ? "50MB" : "8MB"}` }, { status: 400 }); } // Get user's current files const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { profileImage: true, backgroundImage: true, backgroundMusic: true, } }); // Delete existing file if present const existingPath = type === "music" ? user?.backgroundMusic : type === "avatar" ? user?.profileImage : user?.backgroundImage; if (existingPath) { const fullPath = path.join(process.cwd(), "public", existingPath); try { await unlink(fullPath); } catch (error) { console.error("Failed to delete existing file:", error); } } // Create user directories if they don't exist const userDir = path.join(process.cwd(), "public", "assets", session.user.id); const typeDir = path.join(userDir, type === "music" ? "music" : "images"); await mkdir(userDir, { recursive: true }); await mkdir(typeDir, { recursive: true }); // Generate unique filename with proper extension based on content type const ext = contentType.split('/')[1] || 'bin'; const filename = `${type}_${Date.now()}.${ext}`; const filepath = path.join(typeDir, filename); // Write file await writeFile(filepath, Buffer.from(buffer)); // Return the relative path for client usage const relativePath = `/assets/${session.user.id}/${type === "music" ? "music" : "images"}/${filename}`; // Update user record const updateData = type === "music" ? { backgroundMusic: relativePath } : type === "avatar" ? { profileImage: relativePath } : { backgroundImage: relativePath }; await prisma.user.update({ where: { id: session.user.id }, data: updateData }); // Log the activity await prisma.activityLog.create({ data: { userId: session.user.id, action: "FILE_UPLOAD", details: { type: type, path: relativePath } } }); return NextResponse.json({ path: relativePath }); } catch (error) { console.error("Upload error:", error); return NextResponse.json({ error: "Upload failed" }, { status: 500 }); } }