// Job Folder Integration Module // This module handles folder creation and share link capture after PocketBase record creation // Uses the same Graph API token from the server to avoid re-authentication const { DRIVE_ID, PARENT_ITEM_ID } = require('./config'); /** * Creates a job folder structure in OneDrive/SharePoint and returns the share link * @param {string} accessToken - Graph API access token (from server's token flow) * @param {string} jobNumber - Job number (e.g., "12345") * @param {string} jobFullName - Full job name calculated from form data * @returns {Promise} Result with folder IDs and share link */ async function createJobFolderAndGetLink(accessToken, jobNumber, jobFullName) { try { // 1) Create main folder under configured parent const mainFolderName = `${jobNumber} - ${jobFullName}`; const createFolderEndpoint = `https://graph.microsoft.com/v1.0/drives/${DRIVE_ID}/items/${PARENT_ITEM_ID}/children`; console.log(`[Job Folder Integration] Creating main folder: ${mainFolderName}`); const folderResp = await fetch(createFolderEndpoint, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: mainFolderName, folder: {}, "@microsoft.graph.conflictBehavior": "rename" }) }); const folderData = await folderResp.json(); console.log(`[Job Folder Integration] Create folder response:`, { status: folderResp.status, folderId: folderData.id, folderName: folderData.name }); if (!folderResp.ok) { throw new Error(`Create main folder failed: ${JSON.stringify(folderData)}`); } const mainFolderId = folderData.id; // 2) Create subfolder "Managers Info" console.log('[Job Folder Integration] Creating subfolder: Managers Info'); const subFolderResp = await fetch( `https://graph.microsoft.com/v1.0/drives/${DRIVE_ID}/items/${mainFolderId}/children`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Managers Info', folder: {}, "@microsoft.graph.conflictBehavior": "rename" }) } ); const subFolderData = await subFolderResp.json(); console.log('[Job Folder Integration] Create subfolder response:', { status: subFolderResp.status, subfolderId: subFolderData.id }); if (!subFolderResp.ok) { throw new Error(`Create subfolder failed: ${JSON.stringify(subFolderData)}`); } const subFolderId = subFolderData.id; // 3) Create share link for the main folder console.log('[Job Folder Integration] Creating share link for main folder'); const shareResp = await fetch( `https://graph.microsoft.com/v1.0/drives/${DRIVE_ID}/items/${mainFolderId}/createLink`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'view', scope: 'organization' }) } ); const shareData = await shareResp.json(); console.log('[Job Folder Integration] Share link response:', { status: shareResp.status, hasLink: !!shareData.link?.webUrl }); if (!shareResp.ok) { throw new Error(`Create share link failed: ${JSON.stringify(shareData)}`); } const shareLink = shareData.link && shareData.link.webUrl ? shareData.link.webUrl : null; console.log(`[Job Folder Integration] ✓ Successfully created folder structure and share link`); console.log(`[Job Folder Integration] Share link: ${shareLink}`); return { success: true, mainFolderId, mainFolderName, subFolderId, shareLink, folderPath: mainFolderName }; } catch (error) { console.error('[Job Folder Integration] Error in createJobFolderAndGetLink:', error); throw error; } } module.exports = { createJobFolderAndGetLink };