Improve web signing flow and locale handling
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "linkedsign-backend",
|
||||
"version": "1.2.8",
|
||||
"version": "1.2.9",
|
||||
"private": true,
|
||||
"description": "Initial backend for LinkedSign",
|
||||
"main": "src/server.js",
|
||||
|
||||
@@ -8,18 +8,21 @@ const getCtx = (req) => ({
|
||||
userName: req.user?.name || req.user?.email,
|
||||
userEmail: req.user?.email || null,
|
||||
frontendUrl: req.headers.origin || null,
|
||||
clientLocale: req.body?.clientLocale || null,
|
||||
clientTimeZone: req.body?.clientTimeZone || null,
|
||||
clientCountry: req.body?.clientCountry || null,
|
||||
});
|
||||
|
||||
const sign = async (req, res, next) => {
|
||||
try {
|
||||
const { documentId, certificateId, certPassword, reason, location, page, rect, signatureStyle, qrPosition, qrBackground, qrBorder, signatureImageBase64 } = req.body;
|
||||
const { documentId, certificateId, certPassword, reason, location, page, rect, signatureStyle, qrPosition, qrBackground, qrBorder, signatureImageBase64, clientLocale, clientTimeZone, clientCountry } = req.body;
|
||||
const docId = Number(documentId);
|
||||
const certId = Number(certificateId);
|
||||
if (!docId || !certId || isNaN(docId) || isNaN(certId)) {
|
||||
const e = new Error('documentId and certificateId are required.'); e.statusCode = 400; throw e;
|
||||
}
|
||||
const result = await signaturesService.sign(
|
||||
{ documentId: docId, certificateId: certId, certPassword, reason, location, page, rect, signatureStyle, qrPosition, qrBackground, qrBorder, signatureImageBase64 },
|
||||
{ documentId: docId, certificateId: certId, certPassword, reason, location, page, rect, signatureStyle, qrPosition, qrBackground, qrBorder, signatureImageBase64, clientLocale, clientTimeZone, clientCountry },
|
||||
req.user.id,
|
||||
getCtx(req)
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ const { signPdf } = require('../signing/signing.service');
|
||||
const auditService = require('../audit/audit.service');
|
||||
const env = require('../../config/env');
|
||||
|
||||
const sign = async ({ documentId, certificateId, certPassword, reason, location, page, rect, signatureStyle, qrPosition, qrBackground, qrBorder, signatureImageBase64 }, userId, context = {}) => {
|
||||
const sign = async ({ documentId, certificateId, certPassword, reason, location, page, rect, signatureStyle, qrPosition, qrBackground, qrBorder, signatureImageBase64, clientLocale, clientTimeZone, clientCountry }, userId, context = {}) => {
|
||||
const doc = await documentsRepository.findById(documentId);
|
||||
if (!doc) { const e = new Error('Document not found.'); e.statusCode = 404; throw e; }
|
||||
if (doc.user_id !== userId) { const e = new Error('Access denied.'); e.statusCode = 403; throw e; }
|
||||
@@ -50,6 +50,9 @@ const sign = async ({ documentId, certificateId, certPassword, reason, location,
|
||||
qrBorder: qrBorder || 'none',
|
||||
signatureImageBase64: signatureImageBase64 || null,
|
||||
verificationUrl,
|
||||
clientLocale: clientLocale || context.clientLocale || null,
|
||||
clientTimeZone: clientTimeZone || context.clientTimeZone || null,
|
||||
clientCountry: clientCountry || context.clientCountry || null,
|
||||
}));
|
||||
} catch (signErr) {
|
||||
const msg = signErr.message || '';
|
||||
|
||||
@@ -39,6 +39,34 @@ function getSignatureWidth(style, signerName = '') {
|
||||
return Math.max(170, Math.min(270, Math.round(calculatedWidth)));
|
||||
}
|
||||
|
||||
function buildLocalizedSignatureTimestamp({ locale, timeZone } = {}) {
|
||||
const now = new Date();
|
||||
const normalizedLocale = locale || 'es-EC';
|
||||
const options = timeZone ? { timeZone } : {};
|
||||
|
||||
try {
|
||||
return {
|
||||
dateStr: now.toLocaleDateString(normalizedLocale, {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
...options,
|
||||
}),
|
||||
timeStr: now.toLocaleTimeString(normalizedLocale, {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: true,
|
||||
...options,
|
||||
}),
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
dateStr: now.toLocaleDateString('es-EC', { day: '2-digit', month: '2-digit', year: 'numeric' }),
|
||||
timeStr: now.toLocaleTimeString('es-EC', { hour: '2-digit', minute: '2-digit', hour12: true }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ── Style: CLASSIC (blue bar + DS badge) ──────────────────────────────────────
|
||||
async function drawStyleClassic(pdfDoc, page, sx, sy, sw, sh, { signerName, reason, dateStr, timeStr, location }) {
|
||||
const f1 = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
|
||||
@@ -222,6 +250,8 @@ const signPdf = async ({
|
||||
qrBackground = 'transparent',
|
||||
qrBorder = 'none',
|
||||
verificationUrl = null,
|
||||
clientLocale = null,
|
||||
clientTimeZone = null,
|
||||
outputDir = null,
|
||||
outputBaseName = null,
|
||||
}) => {
|
||||
@@ -258,9 +288,10 @@ const signPdf = async ({
|
||||
};
|
||||
const { x: sx, y: sy, width: sw, height: sh } = sigRect;
|
||||
|
||||
const now = new Date();
|
||||
const dateStr = now.toLocaleDateString('es-EC', { day: '2-digit', month: '2-digit', year: 'numeric' });
|
||||
const timeStr = now.toLocaleTimeString('es-EC', { hour: '2-digit', minute: '2-digit', hour12: true });
|
||||
const { dateStr, timeStr } = buildLocalizedSignatureTimestamp({
|
||||
locale: clientLocale,
|
||||
timeZone: clientTimeZone,
|
||||
});
|
||||
|
||||
const info = { signerName, reason, dateStr, timeStr, location, signatureImageBase64, verificationUrl, qrPosition, qrBackground, qrBorder };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user