124_webcalibre2/src/app/dashboard/actions.ts

253 lines
8.2 KiB
TypeScript
Raw Normal View History

2026-01-16 05:22:00 +00:00
// src/app/dashboard/actions.ts
'use server';
import { auth } from "@/auth";
import { revalidatePath } from "next/cache";
2026-01-16 05:22:00 +00:00
import {
getAllFileNodes,
getFileNodeById,
updateFileNode,
deleteFileNode
} from "@/data-access/file-nodes";
import {
getOneDriveItem,
deleteFromOneDrive,
uploadToOneDrive
} from "@/services/onedrive";
2026-01-21 01:34:02 +00:00
import { getEnrichedMetadataFromCloud } from "@/data-access/file-nodes";
2026-01-31 12:58:22 +00:00
import { getFreshAccessToken } from "@/lib/auth-utils";
2026-01-21 01:34:02 +00:00
2026-01-31 12:58:22 +00:00
import { getOneDriveFileBuffer } from "@/services/onedrive"; // Import your working service
import { extractMetadata } from "@/lib/metadata-extractor";
/**
2026-01-16 05:22:00 +00:00
* 1. FETCH: Get all file nodes
* Now simply calls the DAL. Error handling is left to the caller (the UI).
*/
export async function getFileNodes() {
2026-01-16 05:22:00 +00:00
return await getAllFileNodes();
}
/**
2026-01-14 07:29:52 +00:00
* 2. DOWNLOAD: Generates the authenticated OneDrive URL
2026-01-16 05:22:00 +00:00
* Orchestrates the session check, DAL lookup, and Service call.
2026-01-14 07:29:52 +00:00
*/
export async function getDownloadUrlAction(id: string) {
const session = await auth();
if (!session?.user?.id) throw new Error("Unauthorized");
2026-01-16 05:22:00 +00:00
const file = await getFileNodeById(id);
2026-01-14 07:29:52 +00:00
if (!file || !file.oneDriveId) throw new Error("File not found or missing cloud ID");
2026-01-16 05:22:00 +00:00
// Service handles token refresh and graph request internally
const data = await getOneDriveItem(session.user.id, file.oneDriveId);
2026-01-14 07:29:52 +00:00
const downloadUrl = data["@microsoft.graph.downloadUrl"];
2026-01-16 05:22:00 +00:00
if (!downloadUrl) throw new Error("OneDrive did not provide a download URL");
return downloadUrl;
2026-01-14 07:29:52 +00:00
}
/**
2026-01-16 05:22:00 +00:00
* 3. DELETE: Removes from both Cloud and Database
*/
2026-01-16 05:22:00 +00:00
export async function deleteFileNodeAction(id: string) {
const session = await auth();
if (!session?.user?.id) throw new Error("Unauthorized");
try {
2026-01-16 05:22:00 +00:00
const file = await getFileNodeById(id);
if (!file) throw new Error("File record not found");
2026-01-16 05:22:00 +00:00
// Phase 1: Cloud Deletion
if (file.oneDriveId) {
await deleteFromOneDrive(session.user.id, file.oneDriveId);
}
2026-01-16 05:22:00 +00:00
// Phase 2: Database Deletion
await deleteFileNode(id);
revalidatePath("/dashboard");
return { success: true };
} catch (error) {
2026-01-16 05:22:00 +00:00
console.error("Delete Error:", error);
return { success: false, error: "Failed to delete file" };
}
}
/**
2026-01-16 05:22:00 +00:00
* 4. UPDATE: Modify record and optionally sync new content to OneDrive
*/
2026-01-16 05:22:00 +00:00
export async function updateFileNodeAction(id: string, formData: FormData) {
const session = await auth();
if (!session?.user?.id) throw new Error("Unauthorized");
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;
const parentId = parentIdRaw === "root" ? null : parentIdRaw;
let metadata = JSON.parse(metadataStr);
try {
2026-01-16 05:22:00 +00:00
const node = await getFileNodeById(id);
2026-01-16 05:22:00 +00:00
// If a new file is uploaded, push it to OneDrive first
2026-01-14 07:29:52 +00:00
if (newFile && newFile.size > 0 && node?.oneDriveId) {
2026-01-16 05:22:00 +00:00
await uploadToOneDrive(session.user.id, newFile, node.oneDriveId);
metadata.type = newFile.name.split('.').pop()?.toUpperCase() || 'UNKNOWN';
metadata.mimeType = newFile.type;
}
2026-01-16 05:22:00 +00:00
// Update the database via DAL
await updateFileNode(id, {
name,
description,
parentId,
metadata,
size: newFile ? BigInt(newFile.size) : undefined,
});
revalidatePath("/dashboard");
return { success: true };
2026-01-16 05:22:00 +00:00
} catch (error) {
console.error("Update Error:", error);
return { success: false, error: "Failed to update record" };
}
2026-01-21 01:34:02 +00:00
}
2026-01-31 12:58:22 +00:00
// export async function getMetadataPreviewAction(fileId: string) {
// const session = await auth();
// if (!session?.user?.id) throw new Error("Unauthorized");
// try {
// console.log(`🔍 Starting enhancement for file: ${fileId}`);
// // This calls the DAL -> which calls the Service -> which calls OneDrive
// const data = await getEnrichedMetadataFromCloud(fileId);
// // This log will show you exactly what we found in your terminal!
// console.log("✅ Extracted Metadata Result:", data);
// return { success: true, data };
// } catch (error: any) {
// console.error("❌ Enhancement Action Error:", error.message);
// return { success: false, error: error.message };
// }
// }
/**
* 5. ENHANCE (Magic Fill): Extracts deep metadata from the actual file binary
*/
// export async function getMetadataPreviewAction(fileId: string) {
// const session = await auth();
// if (!session?.user?.id) throw new Error("Unauthorized");
// console.log(`\n--- 🔍 Magic Fill Started for File ID: ${fileId} ---`);
// try {
// // 1. Get the record from DB to get the oneDriveId and Name
// const node = await getFileNodeById(fileId);
// if (!node || !node.oneDriveId) {
// throw new Error("File not found or not synced with OneDrive");
// }
// // 2. Get fresh token
// const token = await getFreshAccessToken(session.user.id);
// // 3. Fetch the actual binary content from Microsoft Graph
// console.log(`📡 Fetching binary from Microsoft Graph...`);
// let response;
// try {
// response = await fetch(
// `https://graph.microsoftonline.com/v1.0/me/drive/items/${node.oneDriveId}/content`,
// {
// headers: { Authorization: `Bearer ${token}` },
// cache: 'no-store' // Ensure we aren't hitting a stale server cache
// }
// );
// } catch (err: any) {
// console.error("❌ THE ACTUAL NETWORK ERROR:");
// console.error("Message:", err.message);
// console.error("Cause/Stack:", err.cause || err.stack); // This is the gold mine
// throw new Error(`Server-side fetch failed: ${err.message}`);
// }
// if (!response.ok) {
// throw new Error(`Failed to fetch file content: ${response.statusText}`);
// }
// const arrayBuffer = await response.arrayBuffer();
// const buffer = Buffer.from(arrayBuffer);
// console.log(`📦 Downloaded ${buffer.length} bytes.`);
// // 4. Run the Metadata Utility
// const extractedData = await extractMetadata(buffer, node.name);
// // --- 🏁 THE TERMINAL LOG YOU REQUESTED ---
// console.log("✅ RAW DATA EXTRACTED FROM FILE:");
// console.dir(extractedData, { depth: null, colors: true });
// console.log(`--- 🏁 Magic Fill Finished ---\n`);
// return { success: true, data: extractedData };
// } catch (error: any) {
// console.error("❌ Magic Fill Error:", error.message);
// return { success: false, error: error.message };
// }
// }
2026-01-21 01:34:02 +00:00
export async function getMetadataPreviewAction(fileId: string) {
const session = await auth();
if (!session?.user?.id) throw new Error("Unauthorized");
2026-01-31 12:58:22 +00:00
console.log(`\n--- 🔍 Magic Fill Started for File ID: ${fileId} ---`);
2026-01-21 01:34:02 +00:00
try {
2026-01-31 12:58:22 +00:00
const node = await getFileNodeById(fileId);
if (!node || !node.oneDriveId) throw new Error("File not found");
// 1. Get the token from our utility
const token = await getFreshAccessToken(session.user.id);
// LOG: Just check the length to be sure it's not empty
console.log(`🔑 Token retrieved (Length: ${token.length})`);
console.log(`📡 Fetching binary for: ${node.name}...`);
// 2. Fetch the content from Microsoft Graph
const response = await fetch(
`https://graph.microsoft.com/v1.0/me/drive/items/${node.oneDriveId}/content`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Accept': '*/*'
},
}
);
if (!response.ok) {
// If it fails here, we'll see the real reason from Microsoft
const errorText = await response.text();
console.error("❌ Microsoft Graph Error Response:", errorText);
throw new Error(`OneDrive Download Failed: ${response.status}`);
}
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
console.log(`📦 Success! Downloaded ${buffer.length} bytes.`);
// 3. Extract Metadata
const extractedData = await extractMetadata(buffer, node.name);
2026-01-21 01:34:02 +00:00
2026-01-31 12:58:22 +00:00
console.log("✅ RAW DATA EXTRACTED:");
console.dir(extractedData, { depth: null, colors: true });
return { success: true, data: extractedData };
2026-01-21 01:34:02 +00:00
} catch (error: any) {
2026-01-31 12:58:22 +00:00
console.error("❌ Magic Fill Error:", error.message);
2026-01-21 01:34:02 +00:00
return { success: false, error: error.message };
}
}