From a191db8449769fc73dc30a75a8f9de4ce917af57 Mon Sep 17 00:00:00 2001 From: aewing Date: Sun, 28 Dec 2025 01:41:47 +0000 Subject: [PATCH] fixed viewer and folder issues --- backend/server.ts | 62 +++++++++++-- frontend/index.html | 209 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 240 insertions(+), 31 deletions(-) diff --git a/backend/server.ts b/backend/server.ts index d9630d1..90a7978 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -185,9 +185,56 @@ const fetchJson = async (url: string, token: string) => { }; const resolveShareLink = async (link: string, token: string) => { - const encoded = `u!${b64Url(link)}`; - const data = await fetchJson(`https://graph.microsoft.com/v1.0/shares/${encoded}/driveItem`, token); - return { driveId: data.parentReference?.driveId as string, itemId: data.id as string }; + // Decode the link in case it comes pre-encoded from the database + const decodedLink = decodeURIComponent(link); + console.log('[resolveShareLink] Decoded link:', decodedLink); + + // Check if this is a short sharing link (/:f:/ or /:b:/) or a direct document library URL + if (decodedLink.includes('/:f:/') || decodedLink.includes('/:b:/')) { + // Short sharing link - use shares API + const encoded = `u!${b64Url(decodedLink)}`; + console.log('[resolveShareLink] Using shares API, encoded:', encoded); + const data = await fetchJson(`https://graph.microsoft.com/v1.0/shares/${encoded}/driveItem`, token); + return { driveId: data.parentReference?.driveId as string, itemId: data.id as string }; + } else { + // Direct document library URL - parse it and use drive API + // Example: https://czflex.sharepoint.com/sites/Team/Shared Documents/Forms/AllItems.aspx?RootFolder=/sites/Team/Shared Documents/General/... + const url = new URL(decodedLink); + const pathMatch = url.hostname.match(/^([^.]+)\.sharepoint\.com$/); + if (!pathMatch) throw new Error('Invalid SharePoint URL'); + + const hostname = pathMatch[1]; // e.g., 'czflex' + const sitePath = url.pathname.split('/Shared')[0]; // e.g., /sites/Team + const rootFolderParam = url.searchParams.get('RootFolder'); + if (!rootFolderParam) throw new Error('RootFolder parameter missing'); + + // Extract the folder path relative to the document library + // RootFolder format: /sites/Team/Shared Documents/General/Operations [Server]/... + // We need: General/Operations [Server]/... + const folderPath = rootFolderParam.split('/Shared Documents/')[1]; + if (!folderPath) throw new Error('Could not parse folder path'); + + console.log('[resolveShareLink] Hostname:', hostname); + console.log('[resolveShareLink] Site path:', sitePath); + console.log('[resolveShareLink] Folder path:', folderPath); + + // Get the site ID first using hostname:sitePath format + const siteData = await fetchJson(`https://graph.microsoft.com/v1.0/sites/${hostname}.sharepoint.com:${sitePath}`, token); + const siteId = siteData.id; + + // Get the default document library drive + const driveData = await fetchJson(`https://graph.microsoft.com/v1.0/sites/${siteId}/drive`, token); + const driveId = driveData.id; + + // Get the folder item by path + const itemData = await fetchJson( + `https://graph.microsoft.com/v1.0/drives/${driveId}/root:/${folderPath}`, + token + ); + + console.log('[resolveShareLink] Resolved to driveId:', driveId, 'itemId:', itemData.id); + return { driveId, itemId: itemData.id }; + } }; const listChildrenRecursive = async ( @@ -225,9 +272,12 @@ const filterByCategory = (items: DriveItem[], category?: string, pdfOnly: boolea if (i.folder) return false; const name = i.name.toLowerCase(); const mimeType = i.file?.mimeType?.toLowerCase() || ''; - // Include PDFs and Word documents + // Include PDFs, Word documents, and images return name.endsWith('.pdf') || mimeType.includes('pdf') || - name.endsWith('.doc') || name.endsWith('.docx') || mimeType.includes('word'); + name.endsWith('.doc') || name.endsWith('.docx') || mimeType.includes('word') || + name.endsWith('.jpg') || name.endsWith('.jpeg') || name.endsWith('.png') || + name.endsWith('.gif') || name.endsWith('.bmp') || name.endsWith('.tiff') || + name.endsWith('.webp') || mimeType.includes('image'); }); } @@ -274,6 +324,7 @@ app.get('/api/job-files', async (c) => { // Filter to show only PDFs by default (can be disabled with pdfOnly=false query param) const pdfOnly = c.req.query('pdfOnly') !== 'false'; const filtered = filterByCategory(items, category, pdfOnly); + console.log(`[job-files] Found ${items.length} total items, ${filtered.length} after filtering`); const mapped = filtered.map((i) => ({ id: i.id, @@ -291,6 +342,7 @@ app.get('/api/job-files', async (c) => { } catch (err) { const message = (err as Error)?.message || String(err); const status = (err as any)?.status || 500; + console.error('[job-files] ERROR:', message); logLine('logs/error.log', `/api/job-files error: ${message}`); return c.json({ error: message }, status); } diff --git a/frontend/index.html b/frontend/index.html index b23c83a..22de787 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -67,7 +67,7 @@