diff --git a/controller/documentTemplate/DocumentTemplateController.js b/controller/documentTemplate/DocumentTemplateController.js index 227c7ec..6c4550c 100644 --- a/controller/documentTemplate/DocumentTemplateController.js +++ b/controller/documentTemplate/DocumentTemplateController.js @@ -25,6 +25,7 @@ function saveDebugFile(filename, data, encoding = 'utf8') { const debugDir = ensureDebugDir(); const p = path.join(debugDir, filename); try { + let folderStructureWarning = null; if (Buffer.isBuffer(data)) fs.writeFileSync(p, data); else fs.writeFileSync(p, data, { encoding }); logger.debug(`[DEBUG] Wrote debug file: ${p}`); @@ -1458,6 +1459,7 @@ exports.previewLatestForUser = async (req, res) => { const hasContractFolder = keys.some(k => k.startsWith(`${basePrefix}contract/`)); const hasGdprFolder = keys.some(k => k.startsWith(`${basePrefix}gdpr/`)); if (!hasContractFolder && !hasGdprFolder) { + folderStructureWarning = 'Admin user has to clean up and move the files in exoscale folder'; logger.error('[previewLatestForUser] contract folder structure invalid: Admin user has to clean up and move the files in exoscale folder', { userId: targetUserId, contractCategory, @@ -1470,6 +1472,11 @@ exports.previewLatestForUser = async (req, res) => { logger.warn('[previewLatestForUser] contract folder structure check failed', e && (e.stack || e.message)); } + const jsonWithWarning = (payload) => { + if (!folderStructureWarning) return payload; + return { ...payload, warning: folderStructureWarning }; + }; + // Choose document_type set based on contractType (aligned with ContractUploadService paths) // uploadContract stores under contracts/// with document_type 'contract' // so use contract_type column to disambiguate between contract vs gdpr @@ -1502,7 +1509,8 @@ exports.previewLatestForUser = async (req, res) => { } if (!doc || !doc.object_storage_id) { - return res.status(404).json({ message: `No uploaded ${contractType.toUpperCase()} file found for this user` }); + if (folderStructureWarning) res.setHeader('X-Contract-Preview-Warning', folderStructureWarning); + return res.status(404).json(jsonWithWarning({ message: `No uploaded ${contractType.toUpperCase()} file found for this user` })); } try { @@ -1526,7 +1534,8 @@ exports.previewLatestForUser = async (req, res) => { const pdfBuffer = await s3BodyToBuffer(fileObj.Body); if (!pdfBuffer || !pdfBuffer.length) { logger.warn('[previewLatestForUser] S3 returned empty Body', { key: doc.object_storage_id, userId: targetUserId, contractType }); - return res.status(404).json({ message: `${contractType.toUpperCase()} file not available` }); + if (folderStructureWarning) res.setHeader('X-Contract-Preview-Warning', folderStructureWarning); + return res.status(404).json(jsonWithWarning({ message: `${contractType.toUpperCase()} file not available` })); } const b64 = pdfBuffer.toString('base64'); @@ -1537,14 +1546,17 @@ exports.previewLatestForUser = async (req, res) => { `); res.setHeader('Content-Type', 'text/html; charset=utf-8'); + if (folderStructureWarning) res.setHeader('X-Contract-Preview-Warning', folderStructureWarning); return res.send(html); } catch (e) { if (e && (e.name === 'NoSuchKey' || (e.$metadata && e.$metadata.httpStatusCode === 404))) { logger.warn('[previewLatestForUser] object missing in storage', { key: doc.object_storage_id, userId: targetUserId, contractType }); - return res.status(404).json({ message: `${contractType.toUpperCase()} file not available` }); + if (folderStructureWarning) res.setHeader('X-Contract-Preview-Warning', folderStructureWarning); + return res.status(404).json(jsonWithWarning({ message: `${contractType.toUpperCase()} file not available` })); } logger.error('[previewLatestForUser] S3 fetch failed', e && (e.stack || e.message)); - return res.status(500).json({ message: 'Failed to load user document' }); + if (folderStructureWarning) res.setHeader('X-Contract-Preview-Warning', folderStructureWarning); + return res.status(500).json(jsonWithWarning({ message: 'Failed to load user document' })); } } catch (err) { logger.error('[previewLatestForUser] error', err && err.stack ? err.stack : err);