'use server'; import { auth } from "@/auth"; import { getFreshAccessToken } from "@/lib/auth-utils"; import { prisma } from "@/lib/prisma"; import { revalidatePath } from "next/cache"; export async function uploadFileAction(formData: FormData) { const session = await auth(); if (!session?.user?.id) throw new Error("Unauthorized"); const file = formData.get("file") as File; if (!file) throw new Error("No file selected"); const accessToken = await getFreshAccessToken(session.user.id); const folderName = "WebCalibre"; // --- 1. CHECK/CREATE THE WEBCALIBRE FOLDER --- // We check if the folder exists at the root of the user's OneDrive const folderCheckUrl = `https://graph.microsoft.com/v1.0/me/drive/root:/${folderName}`; const folderCheck = await fetch(folderCheckUrl, { headers: { Authorization: `Bearer ${accessToken}` } }); if (folderCheck.status === 404) { console.log(`📂 Folder '${folderName}' not found. Creating it...`); const createFolderRes = await fetch(`https://graph.microsoft.com/v1.0/me/drive/root/children`, { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify({ name: folderName, folder: {}, // Empty object tells Graph to create a folder "@microsoft.graph.conflictBehavior": "fail" }) }); if (!createFolderRes.ok) { const errorData = await createFolderRes.json(); console.error("❌ Folder Creation Error:", errorData); throw new Error("Could not create WebCalibre folder on OneDrive."); } } // --- 2. CREATE UPLOAD SESSION --- // encodeURIComponent is vital for filenames with spaces or special characters const sessionUrl = `https://graph.microsoft.com/v1.0/me/drive/root:/${folderName}/${encodeURIComponent(file.name)}:/createUploadSession`; const sessionRes = await fetch(sessionUrl, { method: "POST", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify({ item: { "@microsoft.graph.conflictBehavior": "rename", // If file exists, name it "Book 1.pdf" name: file.name } }) }); const sessionData = await sessionRes.json(); if (!sessionRes.ok) { console.error("❌ Session Error:", sessionData); throw new Error(sessionData.error?.message || "OneDrive session failed"); } const { uploadUrl } = sessionData; // --- 3. UPLOAD THE DATA BYTES --- const buffer = Buffer.from(await file.arrayBuffer()); const uploadRes = await fetch(uploadUrl, { method: "PUT", headers: { "Content-Length": `${file.size}`, "Content-Range": `bytes 0-${file.size - 1}/${file.size}` }, body: buffer }); if (!uploadRes.ok) { const uploadError = await uploadRes.json(); console.error("❌ Upload Error:", uploadError); throw new Error("Chunk upload failed"); } const driveItem = await uploadRes.json(); // --- 4. RECORD IN POSTGRESQL (PRISMA) --- await prisma.fileNode.create({ data: { oneDriveId: driveItem.id, name: file.name, size: BigInt(file.size), isFolder: false, path: `/${folderName}/${file.name}`, ownerId: session.user.id, metadata: { type: file.name.split('.').pop()?.toUpperCase() || "UNKNOWN", mimeType: file.type } } }); // Revalidate ensures the dashboard list updates immediately revalidatePath("/dashboard"); return { success: true }; }