124_webcalibre2/src/data-access/file-nodes.ts

191 lines
4.7 KiB
TypeScript
Raw Normal View History

2026-01-16 05:22:00 +00:00
// src/data-access/file-nodes.ts
import "server-only";
2026-01-21 01:34:02 +00:00
import { getOneDriveFileBuffer } from "@/services/onedrive";
import { extractMetadata } from "@/lib/metadata-extractor";
2026-01-16 05:22:00 +00:00
import { prisma } from "@/lib/prisma";
2026-01-21 01:34:02 +00:00
2026-01-16 05:22:00 +00:00
/**
* FETCH: Retrieve all nodes for the dashboard.
* Centralizing this here allows us to change sort order or filters
* in one place for the entire application.
*/
export async function getAllFileNodes() {
return await prisma.fileNode.findMany({
orderBy: {
updatedAt: 'desc',
},
});
}
/**
* FETCH: Get a single node by ID.
* Used by the Download route and Update pages to verify a file exists.
*/
export async function getFileNodeById(id: string) {
return await prisma.fileNode.findUnique({
where: { id },
});
}
/**
* UPDATE: Modify metadata, name, or virtual location.
* This function accepts the data object to keep the DAL flexible.
*/
export async function updateFileNode(id: string, data: any) {
return await prisma.fileNode.update({
where: { id },
data: {
...data,
updatedAt: new Date(),
},
});
}
/**
* DELETE: Remove the record from the database.
* Cloud deletion should be handled by the Service Layer before calling this.
*/
export async function deleteFileNode(id: string) {
return await prisma.fileNode.delete({
where: { id },
});
}
/**
* MASTER CREATE: Handles both standard uploads and virtual folders.
* If no ID is provided, it generates a fresh UUID.
*/
export async function createFileNode(data: {
id?: string; // Optional: used for virtual folders/UUID storage
oneDriveId: string | null;
name: string;
hash?: string | null; // ✅ ADDED: For SHA-256 duplicate prevention
2026-01-16 05:22:00 +00:00
description?: string;
isFolder: boolean;
path: string;
ownerId: string;
parentId?: string | null; // Optional: for nested structures
size?: bigint;
metadata: any;
}) {
return await prisma.fileNode.create({
data: {
...data,
id: data.id ?? crypto.randomUUID(), // Use provided ID or generate new one
}
});
}
// ... other functions (getAllFileNodes, etc)
/**
* UPSERT: Create or Update a file node based on OneDrive ID
* Moved here because it interacts with the Database.
*/
export async function upsertFileNode(oneDriveId: string, data: {
name: string;
size: bigint;
isFolder: boolean;
path: string;
ownerId: string;
metadata: any;
hash?: string | null; // ✅ ADDED: Keep hash in sync during upserts
}) {
2026-01-16 05:22:00 +00:00
return await prisma.fileNode.upsert({
where: { oneDriveId },
update: {
name: data.name,
size: data.size,
isFolder: data.isFolder,
path: data.path,
hash: data.hash, // ✅ ADDED
2026-01-16 05:22:00 +00:00
updatedAt: new Date(),
},
create: {
id: crypto.randomUUID(),
oneDriveId: oneDriveId,
name: data.name,
size: data.size,
isFolder: data.isFolder,
path: data.path,
ownerId: data.ownerId,
metadata: data.metadata,
hash: data.hash, // ✅ ADDED
2026-01-16 05:22:00 +00:00
}
});
2026-01-21 01:34:02 +00:00
}
2026-05-28 11:38:41 +00:00
/**
* FETCH: Get all virtual folders for selection in dropdowns.
* Used by the BulkUpload page to set destinations.
*/
export async function getAllFolders() {
return await prisma.fileNode.findMany({
where: {
isFolder: true
},
select: {
id: true,
name: true
},
orderBy: {
name: 'asc'
}
});
}
2026-01-21 01:34:02 +00:00
2026-05-28 11:38:41 +00:00
/**
* UPSERT BY HASH: The core of the Disaster Recovery process.
* If a hash exists, we update the OneDrive ID (Restoring the link).
* If not, we create a new entry.
*/
export async function upsertFileNodeByHash(data: {
name: string;
hash: string;
oneDriveId: string;
parentId?: string | null;
size: bigint;
ownerId: string;
mimeType?: string;
}) {
// First, check if we have a record with this hash
const existing = await prisma.fileNode.findFirst({
where: { hash: data.hash }
});
if (existing) {
// 🛡️ DISASTER RECOVERY MODE
// The database knows about this file, but the OneDrive link is old.
// We update the existing record with the NEW cloud ID.
return await prisma.fileNode.update({
where: { id: existing.id },
data: {
oneDriveId: data.oneDriveId,
// Optional: Update parent if the user chose a new folder during restore
parentId: data.parentId || existing.parentId,
updatedAt: new Date(),
}
});
}
// ✨ NEW UPLOAD MODE
return await prisma.fileNode.create({
data: {
id: crypto.randomUUID(),
oneDriveId: data.oneDriveId,
name: data.name,
hash: data.hash,
size: data.size,
isFolder: false,
ownerId: data.ownerId,
parentId: data.parentId || null,
path: data.name, // Simplified for now
metadata: {}, // Placeholder for extractMetadata logic
}
});
}
2026-01-21 01:34:02 +00:00