2026-01-16 05:22:00 +00:00
|
|
|
// src/app/dashboard/actions.ts
|
|
|
|
|
|
2026-01-08 05:41:31 +00:00
|
|
|
'use server';
|
2026-01-11 13:41:54 +00:00
|
|
|
|
2026-01-08 05:41:31 +00:00
|
|
|
import { auth } from "@/auth";
|
2026-01-11 13:41:54 +00:00
|
|
|
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-08 05:41:31 +00:00
|
|
|
|
2026-02-01 10:37:02 +00:00
|
|
|
//import { getEnrichedMetadataFromCloud } from "@/data-access/file-nodes";
|
2026-01-21 01:34:02 +00:00
|
|
|
|
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-02-01 10:37:02 +00:00
|
|
|
|
|
|
|
|
|
2026-01-11 13:41:54 +00:00
|
|
|
/**
|
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).
|
2026-01-11 13:41:54 +00:00
|
|
|
*/
|
2026-01-08 05:41:31 +00:00
|
|
|
export async function getFileNodes() {
|
2026-01-16 05:22:00 +00:00
|
|
|
return await getAllFileNodes();
|
2026-01-11 13:41:54 +00:00
|
|
|
}
|
2026-01-08 05:41:31 +00:00
|
|
|
|
2026-01-11 13:41:54 +00:00
|
|
|
/**
|
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-11 13:41:54 +00:00
|
|
|
*/
|
2026-01-16 05:22:00 +00:00
|
|
|
export async function deleteFileNodeAction(id: string) {
|
2026-01-11 13:41:54 +00:00
|
|
|
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-11 13:41:54 +00:00
|
|
|
|
2026-01-16 05:22:00 +00:00
|
|
|
// Phase 1: Cloud Deletion
|
|
|
|
|
if (file.oneDriveId) {
|
|
|
|
|
await deleteFromOneDrive(session.user.id, file.oneDriveId);
|
2026-01-11 13:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 05:22:00 +00:00
|
|
|
// Phase 2: Database Deletion
|
|
|
|
|
await deleteFileNode(id);
|
2026-01-11 13:41:54 +00:00
|
|
|
|
|
|
|
|
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-11 13:41:54 +00:00
|
|
|
}
|
2026-01-13 13:17:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-16 05:22:00 +00:00
|
|
|
* 4. UPDATE: Modify record and optionally sync new content to OneDrive
|
2026-01-13 13:17:40 +00:00
|
|
|
*/
|
2026-01-16 05:22:00 +00:00
|
|
|
export async function updateFileNodeAction(id: string, formData: FormData) {
|
2026-01-13 13:17:40 +00:00
|
|
|
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-13 13:17:40 +00:00
|
|
|
|
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);
|
2026-01-13 13:17:40 +00:00
|
|
|
|
|
|
|
|
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,
|
2026-01-13 13:17:40 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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-13 13:17:40 +00:00
|
|
|
}
|
2026-01-21 01:34:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-31 12:58:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
|
|
try {
|
2026-01-31 12:58:22 +00:00
|
|
|
const node = await getFileNodeById(fileId);
|
2026-02-01 10:37:02 +00:00
|
|
|
if (!node || !node.oneDriveId) throw new Error("No OneDrive ID found");
|
2026-01-31 12:58:22 +00:00
|
|
|
|
2026-02-01 10:37:02 +00:00
|
|
|
console.log(`📡 Attempting fetch via Service for: ${node.name}`);
|
2026-01-31 12:58:22 +00:00
|
|
|
|
2026-02-01 10:37:02 +00:00
|
|
|
const token = await getFreshAccessToken(session.user.id);
|
|
|
|
|
|
|
|
|
|
if (!token) throw new Error("Could not retrieve access token");
|
|
|
|
|
// Call your existing service
|
|
|
|
|
const buffer = await getOneDriveFileBuffer(node.oneDriveId, token);
|
|
|
|
|
|
|
|
|
|
console.log(`📦 Buffer received: ${buffer.length} bytes`);
|
2026-01-31 12:58:22 +00:00
|
|
|
|
|
|
|
|
const extractedData = await extractMetadata(buffer, node.name);
|
2026-01-21 01:34:02 +00:00
|
|
|
|
2026-02-01 10:37:02 +00:00
|
|
|
console.log("✅ Extracted:", extractedData);
|
2026-01-31 12:58:22 +00:00
|
|
|
return { success: true, data: extractedData };
|
|
|
|
|
|
2026-01-21 01:34:02 +00:00
|
|
|
} catch (error: any) {
|
2026-02-01 10:37:02 +00:00
|
|
|
console.error("❌ Service Fetch Error:", error.message);
|
|
|
|
|
// If this still says ENOTFOUND, the code is fine, but the terminal is blocked.
|
2026-01-21 01:34:02 +00:00
|
|
|
return { success: false, error: error.message };
|
|
|
|
|
}
|
2026-01-08 05:41:31 +00:00
|
|
|
}
|