const UnitOfWork = require('../../database/UnitOfWork'); const ContractUploadService = require('../../services/contracts/ContractUploadService'); const UserDocumentRepository = require('../../repositories/documents/UserDocumentRepository'); const { logger } = require('../../middleware/logger'); function normalizeSignature(signatureImage) { if (!signatureImage) return null; const str = String(signatureImage); const m = str.match(/^data:(.+);base64,(.+)$/); if (m && m[2]) { const mime = m[1] || 'image/png'; const base64 = m[2]; const size = Buffer.from(base64, 'base64').length; return { base64, mime, size }; } try { const size = Buffer.from(str, 'base64').length; return { base64: str, mime: 'image/png', size }; } catch (e) { logger.warn('[ContractUploadController] normalizeSignature failed to parse provided signature'); return null; } } class ContractUploadController { static async uploadPersonalContract(req, res) { const userId = req.user.userId; logger.info(`[ContractUploadController] uploadPersonalContract called for userId: ${userId}`); const file = req.file; // optional, we now generate from templates when absent const contractData = req.body.contractData ? JSON.parse(req.body.contractData) : undefined; const signatureImage = req.body.signatureImage; const unitOfWork = new UnitOfWork(); await unitOfWork.start(); try { const signatureMeta = normalizeSignature(signatureImage); const repo = new UserDocumentRepository(unitOfWork); if (signatureMeta) { await repo.insertDocument({ userId, documentType: 'signature', contractType: 'contract', objectStorageId: null, signatureBase64: signatureMeta.base64, originalFilename: 'signature.png', fileSize: signatureMeta.size, mimeType: signatureMeta.mime }); logger.info('[ContractUploadController] signature stored for user', { userId, bytes: signatureMeta.size }); } const uploads = []; // Primary contract uploads.push(await ContractUploadService.uploadContract({ userId, file, documentType: 'contract', contractCategory: 'personal', unitOfWork, contractData, signatureImage: signatureMeta ? signatureMeta.base64 : null, contract_type: 'contract', user_type: 'personal' })); // GDPR contract (auto-generated from latest GDPR template) uploads.push(await ContractUploadService.uploadContract({ userId, documentType: 'contract', contractCategory: 'personal', unitOfWork, contractData, signatureImage: signatureMeta ? signatureMeta.base64 : null, contract_type: 'gdpr', user_type: 'personal' })); // Cleanup standalone signature record after contracts are saved if (signatureMeta) { await repo.deleteSignatureDocumentsForUser(userId); logger.info('[ContractUploadController] signature cleanup completed for user', { userId }); } await unitOfWork.commit(); logger.info(`[ContractUploadController] uploadPersonalContract success for userId: ${userId}`); res.json({ success: true, uploads, downloadUrls: uploads.map(u => u.url || null) }); } catch (error) { logger.error(`[ContractUploadController] uploadPersonalContract error for userId: ${userId}`, { error }); await unitOfWork.rollback(error); res.status(400).json({ success: false, message: error.message }); } } static async uploadCompanyContract(req, res) { const userId = req.user.userId; logger.info(`[ContractUploadController] uploadCompanyContract called for userId: ${userId}`); const file = req.file; const contractData = req.body.contractData ? JSON.parse(req.body.contractData) : undefined; const signatureImage = req.body.signatureImage; const unitOfWork = new UnitOfWork(); await unitOfWork.start(); try { const signatureMeta = normalizeSignature(signatureImage); const repo = new UserDocumentRepository(unitOfWork); if (signatureMeta) { await repo.insertDocument({ userId, documentType: 'signature', contractType: 'contract', objectStorageId: null, signatureBase64: signatureMeta.base64, originalFilename: 'signature.png', fileSize: signatureMeta.size, mimeType: signatureMeta.mime }); logger.info('[ContractUploadController] signature stored for company user', { userId, bytes: signatureMeta.size }); } const result = await ContractUploadService.uploadContract({ userId, file, documentType: 'contract', contractCategory: 'company', unitOfWork, contractData, signatureImage: signatureMeta ? signatureMeta.base64 : null, contract_type: 'contract', user_type: 'company' }); await unitOfWork.commit(); if (signatureMeta) { await repo.deleteSignatureDocumentsForUser(userId); logger.info('[ContractUploadController] signature cleanup completed for company user', { userId }); } logger.info(`[ContractUploadController] uploadCompanyContract success for userId: ${userId}`); res.json({ success: true, upload: result, downloadUrl: result.url || null }); } catch (error) { logger.error(`[ContractUploadController] uploadCompanyContract error for userId: ${userId}`, { error }); await unitOfWork.rollback(error); res.status(400).json({ success: false, message: error.message }); } } } module.exports = ContractUploadController;