feat: implement dotenv secrets loading from /home/admin/secrets/.env
- Added dotenv package to load environment variables from absolute path - Secrets now loaded automatically on app startup, no manual sourcing needed - Secrets file secured with chmod 600, outside project directory - Enables persistent secrets across service restarts - Tested: Job submission flow working end-to-end with all steps completing
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
// 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<Object>} 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
|
||||
};
|
||||
Reference in New Issue
Block a user