'use server'; import { auth } from "@/auth"; import { prisma } from "@/lib/prisma"; import { revalidatePath } from "next/cache"; import { getFreshAccessToken } from "@/lib/auth-utils"; /** * 1. FETCH: Get all file nodes */ export async function getFileNodes() { try { const nodes = await prisma.fileNode.findMany({ orderBy: { updatedAt: 'desc', }, }); return nodes; } catch (error) { console.error("Error fetching file nodes:", error); return []; } } /** * 2. DELETE: Remove from OneDrive and Database */ export async function deleteFileAction(fileId: string) { const session = await auth(); if (!session?.user?.id) throw new Error("Unauthorized"); const node = await prisma.fileNode.findUnique({ where: { id: fileId }, }); if (!node) { revalidatePath("/dashboard"); return { success: true, message: "Item already removed from database" }; } // @ts-ignore const isAdmin = session.user.role === "ADMIN"; const isOwner = node.ownerId === session.user.id; if (!isAdmin && !isOwner) { throw new Error("Permission Denied."); } try { const accessToken = await getFreshAccessToken(session.user.id); if (accessToken) { const rootFolder = "WebCalibre"; const onedrivePath = `https://graph.microsoft.com/v1.0/me/drive/root:/${rootFolder}/${node.id}`; const onedriveRes = await fetch(onedrivePath, { method: "DELETE", headers: { Authorization: `Bearer ${accessToken}` }, }); if (!onedriveRes.ok && onedriveRes.status !== 404) { console.warn("OneDrive Deletion Warning: Cloud record might still exist."); } } } catch (cloudError) { console.error("Cloud cleanup failed:", cloudError); } try { await prisma.fileNode.delete({ where: { id: fileId } }); revalidatePath("/dashboard"); revalidatePath("/upload"); return { success: true }; } catch (dbError) { throw new Error("Failed to remove the record from the database."); } } /** * 3. MOVE: Assign file to folder or folder to another folder */ export async function moveNodeAction(nodeId: string, newParentId: string | null) { const session = await auth(); if (!session?.user?.id) throw new Error("Unauthorized"); if (nodeId === newParentId) throw new Error("Cannot move to self."); try { await prisma.fileNode.update({ where: { id: nodeId }, data: { parentId: newParentId } }); revalidatePath("/dashboard"); return { success: true }; } catch (error) { throw new Error("Move failed."); } } /** * 4. UPDATE & REPLACE: Full update of metadata and OneDrive content * Uses FormData to handle the binary file upload and text fields. */ export async function updateFileFullAction(formData: FormData) { const session = await auth(); if (!session?.user?.id) throw new Error("Unauthorized"); const id = formData.get("id") as string; const name = formData.get("name") as string; const description = formData.get("description") as string; const parentIdRaw = formData.get("parentId") as string; const metadataStr = formData.get("metadata") as string; const newFile = formData.get("file") as File | null; // Handle the "root" placeholder back to null for Prisma const parentId = parentIdRaw === "root" ? null : parentIdRaw; let metadata = JSON.parse(metadataStr); try { const accessToken = await getFreshAccessToken(session.user.id); if (!accessToken) throw new Error("Access token expired."); // 1. OneDrive Overwrite (if file is provided) if (newFile && newFile.size > 0) { const rootFolder = "WebCalibre"; // PUT request to the specific file ID path overwrites content const onedrivePath = `https://graph.microsoft.com/v1.0/me/drive/root:/${rootFolder}/${id}:/content`; const uploadRes = await fetch(onedrivePath, { method: "PUT", headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": newFile.type }, body: Buffer.from(await newFile.arrayBuffer()), }); if (!uploadRes.ok) { const err = await uploadRes.json(); throw new Error(`OneDrive error: ${err.error?.message}`); } // Update metadata with new file properties metadata.type = newFile.name.split('.').pop()?.toUpperCase() || 'UNKNOWN'; metadata.mimeType = newFile.type; } // 2. Database Update await prisma.fileNode.update({ where: { id }, data: { name, description, parentId, metadata, // If file changed, update size; otherwise keep existing size: newFile ? BigInt(newFile.size) : undefined, updatedAt: new Date(), } }); revalidatePath("/dashboard"); return { success: true }; } catch (error: any) { console.error("Full Update Action Failure:", error); throw new Error(error.message || "Failed to update record."); } }