2026-01-08 05:41:31 +00:00
|
|
|
'use server';
|
|
|
|
|
|
|
|
|
|
import { auth } from "@/auth";
|
|
|
|
|
import { prisma } from "@/lib/prisma";
|
|
|
|
|
import { revalidatePath } from "next/cache";
|
2026-01-11 13:41:54 +00:00
|
|
|
import { getFreshAccessToken } from "@/lib/auth-utils";
|
2026-01-08 05:41:31 +00:00
|
|
|
|
|
|
|
|
export async function syncOneDrive() {
|
|
|
|
|
const session = await auth();
|
|
|
|
|
|
|
|
|
|
if (!session?.user?.id) throw new Error("Unauthorized");
|
|
|
|
|
|
2026-01-11 13:41:54 +00:00
|
|
|
try {
|
|
|
|
|
const accessToken = await getFreshAccessToken(session.user.id);
|
2026-01-08 05:41:31 +00:00
|
|
|
|
2026-01-11 13:41:54 +00:00
|
|
|
if (!accessToken) {
|
|
|
|
|
throw new Error("Microsoft account not linked properly or session expired.");
|
|
|
|
|
}
|
2026-01-08 05:41:31 +00:00
|
|
|
|
2026-01-11 13:41:54 +00:00
|
|
|
const response = await fetch("https://graph.microsoft.com/v1.0/me/drive/root:/WebCalibre:/children", {
|
|
|
|
|
headers: {
|
|
|
|
|
Authorization: `Bearer ${accessToken}`,
|
|
|
|
|
"Content-Type": "application/json"
|
2026-01-08 05:41:31 +00:00
|
|
|
},
|
|
|
|
|
});
|
2026-01-11 13:41:54 +00:00
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
const errorData = await response.json();
|
|
|
|
|
if (response.status === 404) {
|
|
|
|
|
return { success: true, count: 0 };
|
|
|
|
|
}
|
|
|
|
|
throw new Error(errorData.error?.message || "Failed to fetch data from OneDrive");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
let syncedCount = 0;
|
|
|
|
|
|
|
|
|
|
// Regular expression to identify if a string is a UUID
|
|
|
|
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
|
|
|
|
|
|
|
|
for (const item of data.value) {
|
|
|
|
|
const isFolder = !!item.folder;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* FILTER: If the item is a folder and the name is a UUID, skip it.
|
|
|
|
|
* These are storage containers created by the upload action, not user-facing folders.
|
|
|
|
|
*/
|
|
|
|
|
if (isFolder && uuidRegex.test(item.name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const extension = isFolder
|
|
|
|
|
? 'FOLDER'
|
|
|
|
|
: (item.name.split('.').pop()?.toUpperCase() || 'UNKNOWN');
|
|
|
|
|
|
|
|
|
|
const fileSize = item.size ? BigInt(item.size) : BigInt(0);
|
|
|
|
|
|
|
|
|
|
await prisma.fileNode.upsert({
|
|
|
|
|
where: { oneDriveId: item.id },
|
|
|
|
|
update: {
|
|
|
|
|
name: item.name,
|
|
|
|
|
size: fileSize,
|
|
|
|
|
isFolder: isFolder,
|
|
|
|
|
metadata: {
|
|
|
|
|
type: extension,
|
|
|
|
|
mimeType: item.file?.mimeType || null
|
|
|
|
|
},
|
|
|
|
|
path: item.parentReference?.path + '/' + item.name,
|
|
|
|
|
updatedAt: new Date(),
|
|
|
|
|
},
|
|
|
|
|
create: {
|
|
|
|
|
id: crypto.randomUUID(),
|
|
|
|
|
oneDriveId: item.id,
|
|
|
|
|
name: item.name,
|
|
|
|
|
size: fileSize,
|
|
|
|
|
isFolder: isFolder,
|
|
|
|
|
path: item.parentReference?.path + '/' + item.name,
|
|
|
|
|
ownerId: session.user.id,
|
|
|
|
|
metadata: {
|
|
|
|
|
type: extension,
|
|
|
|
|
mimeType: item.file?.mimeType || null
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
syncedCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
revalidatePath('/dashboard');
|
|
|
|
|
return { success: true, count: syncedCount };
|
|
|
|
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error("Sync Process Failure:", error.message);
|
|
|
|
|
throw new Error(error.message || "An unexpected error occurred during sync.");
|
2026-01-08 05:41:31 +00:00
|
|
|
}
|
|
|
|
|
}
|