diff --git a/controller/documentTemplate/DocumentTemplateController.js b/controller/documentTemplate/DocumentTemplateController.js index 63135ae..80c120e 100644 --- a/controller/documentTemplate/DocumentTemplateController.js +++ b/controller/documentTemplate/DocumentTemplateController.js @@ -125,7 +125,8 @@ async function enrichTemplate(template, s3, serverBaseUrl = null) { } if (serverBaseUrl) { - previewUrl = `${serverBaseUrl}/api/document-templates/${template.id}/preview`; + // CHANGED: route path must match getRoutes.js + previewUrl = `${serverBaseUrl}/document-templates/${template.id}/preview`; } else { previewUrl = fileUrl; } @@ -1253,7 +1254,7 @@ exports.previewPdf = async (req, res) => { html = html.replace(/{{\s*currentDate\s*}}/g, formatDateTime()); } - // Apply stamps/signature placeholders where appropriate (harmless for sanitized content) + // Apply stamps/signature where appropriate (harmless for sanitized content) try { html = await applyCompanyStampPlaceholders(html, req); } catch (e) { logger.warn('[previewPdf] applyCompanyStampPlaceholders failed', e && e.message); } try { html = await applyProfitPlanetSignature(html); } catch (e) { logger.warn('[previewPdf] applyProfitPlanetSignature failed', e && e.message); } diff --git a/models/DocumentTemplate.js b/models/DocumentTemplate.js index 1bc73a6..af81dc5 100644 --- a/models/DocumentTemplate.js +++ b/models/DocumentTemplate.js @@ -1,4 +1,4 @@ // This file is now just a field reference for document_templates table module.exports = { - fields: ['id', 'name', 'type', 'storageKey', 'description', 'lang', 'version', 'state', 'createdAt', 'updatedAt'] + fields: ['id', 'name', 'type', 'storageKey', 'description', 'lang', 'user_type', 'version', 'state', 'createdAt', 'updatedAt'] }; \ No newline at end of file diff --git a/repositories/referral/ReferralTokenRepository.js b/repositories/referral/ReferralTokenRepository.js index d490a76..21ebf51 100644 --- a/repositories/referral/ReferralTokenRepository.js +++ b/repositories/referral/ReferralTokenRepository.js @@ -73,10 +73,8 @@ class ReferralTokenRepository { rt.max_uses AS max_uses, rt.uses_remaining AS uses_remaining, rt.status, - rt.created_at, - rt.updated_at, - rt.max_uses_label AS max_uses_label, - rt.uses_remaining_label AS uses_remaining_label, + rt.created_at, + rt.updated_at, (SELECT COUNT(*) FROM referral_token_usage rtu WHERE rtu.referral_token_id = rt.id) AS usage_count, CASE WHEN rt.max_uses = -1 THEN 0 @@ -94,8 +92,6 @@ class ReferralTokenRepository { id: r.id, max_uses: r.max_uses, uses_remaining: r.uses_remaining, - max_uses_label: r.max_uses_label, - uses_remaining_label: r.uses_remaining_label, used_count: r.used_count }); }); @@ -191,8 +187,6 @@ class ReferralTokenRepository { rt.expires_at, rt.max_uses AS max_uses, rt.uses_remaining AS uses_remaining, - rt.max_uses_label AS max_uses_label, - rt.uses_remaining_label AS uses_remaining_label, CASE WHEN rt.max_uses = -1 THEN 0 WHEN rt.max_uses IS NULL OR rt.uses_remaining IS NULL THEN 0 @@ -215,8 +209,6 @@ class ReferralTokenRepository { token: r.token, max_uses: r.max_uses, uses_remaining: r.uses_remaining, - max_uses_label: r.max_uses_label, - uses_remaining_label: r.uses_remaining_label, used_count: r.used_count }); logger.info('ReferralTokenRepository.getReferrerInfoByToken:success', { token }); diff --git a/repositories/template/DocumentTemplateRepository.js b/repositories/template/DocumentTemplateRepository.js index bf0f5d2..8481cc2 100644 --- a/repositories/template/DocumentTemplateRepository.js +++ b/repositories/template/DocumentTemplateRepository.js @@ -4,8 +4,25 @@ const { logger } = require('../../middleware/logger'); class DocumentTemplateRepository { async create(data, conn) { logger.info('DocumentTemplateRepository.create:start', { name: data.name, type: data.type }); - const { name, type, storageKey, description, lang } = data; - const user_type = (data.user_type || data.userType || 'both'); + // ADDED: validate required fields + normalize optional fields + const required = ['name', 'type', 'storageKey', 'lang']; + for (const k of required) { + const v = data[k]; + if (v === undefined || v === null || String(v).trim() === '') { + const err = new Error(`Invalid document template: missing field "${k}"`); + err.code = 'INVALID_TEMPLATE_DATA'; + logger.error('DocumentTemplateRepository.create:invalid', { field: k }); + throw err; + } + } + const name = String(data.name); + const type = String(data.type); + const storageKey = String(data.storageKey); + const description = data.description === undefined ? null : data.description; // avoid undefined bind + const lang = String(data.lang); + const allowedUserTypes = new Set(['personal', 'company', 'both']); + const user_type = allowedUserTypes.has(data.user_type || data.userType) ? (data.user_type || data.userType) : 'both'; + const query = ` INSERT INTO document_templates (name, type, storageKey, description, lang, user_type, version, state, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, 1, 'inactive', NOW(), NOW()) diff --git a/routes/getRoutes.js b/routes/getRoutes.js index 19e6243..4628e10 100644 --- a/routes/getRoutes.js +++ b/routes/getRoutes.js @@ -103,6 +103,8 @@ router.get('/document-templates/:id', authMiddleware, DocumentTemplateController router.get('/document-templates-public', authMiddleware, adminOnly, DocumentTemplateController.listTemplatesPublic); router.get('/document-templates/:id/generate-pdf', authMiddleware, DocumentTemplateController.generatePdf); router.get('/document-templates/:id/preview', authMiddleware, DocumentTemplateController.previewTemplate); +router.get('/document-templates/:id/preview-pdf', authMiddleware, DocumentTemplateController.previewPdf); +router.get('/document-templates/active/mine', authMiddleware, DocumentTemplateController.listMyActiveTemplates); router.get('/document-templates/:id/download-pdf', authMiddleware, DocumentTemplateController.downloadPdf); router.get('/api/document-templates', authMiddleware, adminOnly, DocumentTemplateController.listTemplatesFiltered);