New Features:
1. Added support to recreate a new document from declined document without having to redo everything from scratch.
2. Added replace pdf file feature for Templates. PDF underlying a Template can now be replaced while keeping all the fields the same.
3. Introduced the ability to replace pdf file for in UpdateTemplate and CreateDocumentfromtemplate API.
4. Revamped the preferences menu UI.

Bug Fixes:
1. Fixed issue with capital letters in contact emails via API.
2. Better validations & error handling in APIs
This commit is contained in:
prafull-opensignlabs
2025-04-17 06:34:06 +00:00
parent ec68770ff0
commit 3b1d8a48b7
20 changed files with 932 additions and 535 deletions
+2
View File
@@ -51,6 +51,7 @@ import editContact from './parsefunction/editContact.js';
import forwardDoc from './parsefunction/ForwardDoc.js';
import saveAsTemplate from './parsefunction/saveAsTemplate.js';
import updateTenant from './parsefunction/updateTenant.js';
import recreateDocument from './parsefunction/recreateDocument.js';
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
@@ -112,3 +113,4 @@ Parse.Cloud.define('editcontact', editContact);
Parse.Cloud.define('forwarddoc', forwardDoc);
Parse.Cloud.define('saveastemplate', saveAsTemplate);
Parse.Cloud.define('updatetenant', updateTenant);
Parse.Cloud.define('recreatedoc', recreateDocument);
@@ -1,35 +0,0 @@
import { exec } from 'child_process';
export default function DigitalSign(pdf, pfx, details) {
const signcmd = `java -jar PDFDigitalSigner.jar "${pdf}" "${pfx.name}" "${pfx.passphrase}" "${details.name}" "${details.location}" "${details.reason}"`;
// const signcmd = `java -jar PDFDigitalSigner.jar "${pdf}" keystore.pfx opensign "${details.name}" "${details.location}" "${details.reason}"`;
return new Promise((resolve, reject) => {
exec(signcmd, (error, stdout, stderr) => {
if (error) {
reject(`Error: ${error.message}`);
}
if (stderr) {
reject(`stderr: ${stderr}`);
}
// Resolve the promise with the output
resolve(stdout.trim());
});
});
}
export async function retryAsync(fn, args = [], retries = 3, delay = 2000) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fn(...args); // Try executing the async function
if (response) return { response, attempt }; // Stop retrying if response is received
} catch (error) {
if (attempt < retries) {
console.log(`Attempt ${attempt} failed. Retrying in ${delay / 1000} seconds...\n`);
await new Promise(resolve => setTimeout(resolve, delay)); // Wait before retrying
} else {
return { error, attempt };
// throw new Error(error);
}
}
}
}
@@ -20,6 +20,16 @@ const masterKEY = process.env.MASTER_KEY;
const eSignName = 'OpenSign';
const eSigncontact = 'hello@opensignlabs.com';
async function unlinkFile(path) {
if (fs.existsSync(path)) {
try {
fs.unlinkSync(path);
} catch (err) {
console.log('Err in unlink file: ', path);
}
}
}
// `updateDoc` is used to create url in from pdfFile
async function uploadFile(pdfName, filepath) {
try {
@@ -33,8 +43,8 @@ async function uploadFile(pdfName, filepath) {
return { imageUrl: fileUrl };
} catch (err) {
console.log('Err ', err);
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
fs.unlinkSync(filepath);
// below line of code is used to remove exported signed pdf file from exports folder
unlinkFile(filepath);
}
}
@@ -240,10 +250,10 @@ async function sendCompletedMail(obj) {
});
// console.log('res', res.data.result);
if (res.data?.result?.status !== 'success') {
fs.unlinkSync(`./exports/signed_certificate_${doc.objectId}.pdf`);
unlinkFile(`./exports/signed_certificate_${doc.objectId}.pdf`);
}
} catch (err) {
fs.unlinkSync(`./exports/signed_certificate_${doc.objectId}.pdf`);
unlinkFile(`./exports/signed_certificate_${doc.objectId}.pdf`);
}
}
@@ -288,7 +298,7 @@ async function sendMailsaveCertifcate(doc, pfx, isCustomMail, mailProvider, file
sendCompletedMail({ isCustomMail, doc, mailProvider, filename });
}
saveFileUsage(CertificateBuffer.length, file.imageUrl, doc?.CreatedBy?.objectId);
fs.unlinkSync(pfx.name);
unlinkFile(pfx.name);
}
/**
*
@@ -438,10 +448,10 @@ async function PDF(req) {
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl };
sendMailsaveCertifcate(doc, pfx, isCustomMail, mailProvider, `signed_${name}`);
} else {
fs.unlinkSync(pfxname);
unlinkFile(pfxname);
}
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
fs.unlinkSync(signedFilePath);
// below code is used to remove exported signed pdf file from exports folder
unlinkFile(signedFilePath);
// console.log(`New Signed PDF created called: ${filePath}`);
if (updatedDoc.message === 'success') {
return { status: 'success', data: data.imageUrl };
@@ -466,7 +476,7 @@ async function PDF(req) {
} catch (err) {
console.log('err in saving debugginglog', err);
}
fs.unlinkSync(pfxname);
unlinkFile(pfxname);
throw err;
}
}
@@ -0,0 +1,36 @@
export default async function recreateDocument(request) {
const { docId } = request.params;
if (!docId) {
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Missing docId parameter');
}
if (!request.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User not aunthenticated');
}
try {
const docQuery = new Parse.Query('contracts_Document');
docQuery.equalTo('objectId', docId);
const doc = await docQuery.first({ useMasterKey: true });
if (!doc) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found');
}
const _docRes = doc?.toJSON();
const { objectId, SignedUrl, AuditTrail, ACL, DeclineBy, DeclineReason, ...docRes } = _docRes;
const createDoc = new Parse.Object('contracts_Document');
Object.entries(docRes).forEach(([key, value]) => {
if (key === 'IsDeclined') {
createDoc.set(key, false);
} else {
createDoc.set(key, value);
}
// console.log(`${key}: ${value}`);
});
const createDocRes = await createDoc.save(null, { useMasterKey: true });
// console.log('createDocRes', createDocRes);
const newDoc = JSON.parse(JSON.stringify(createDocRes));
return { objectId: newDoc.objectId, createdAt: newDoc.createdAt, updatedAt: newDoc.updatedAt };
} catch (err) {
console.log('err in recreate document', err);
throw err;
}
}