diff --git a/package-lock.json b/package-lock.json index 4d58a40ec..e5de6b60a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "mustache": "^4.2.0", "node-persist": "^4.0.4", "nodemailer": "^6.10.0", + "normalize-url": "^9.0.0", "pdf-lib": "^1.17.1", "phone": "^3.1.71", "query-string": "7.1.3", @@ -2353,6 +2354,12 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/@jsreport/nodejs-client/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/@kurkle/color": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", @@ -9597,6 +9604,18 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-9.0.0.tgz", + "integrity": "sha512-z9nC87iaZXXySbWWtTHfCFJyFvKaUAW6lODhikG7ILSbVgmwuFjUqkgnheHvAUcGedO29e2QGBRXMUD64aurqQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/notepack.io": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-3.0.1.tgz", diff --git a/package.json b/package.json index 9ff798efb..c1f10ad4c 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "mustache": "^4.2.0", "node-persist": "^4.0.4", "nodemailer": "^6.10.0", + "normalize-url": "^9.0.0", "pdf-lib": "^1.17.1", "phone": "^3.1.71", "query-string": "7.1.3", diff --git a/server/esign/webhook.js b/server/esign/webhook.js index d0bd6efde..3499597bf 100644 --- a/server/esign/webhook.js +++ b/server/esign/webhook.js @@ -3,7 +3,9 @@ const { Documenso } = require("@documenso/sdk-typescript"); const logger = require("../utils/logger"); const { QUERY_META_FOR_ESIG_COMPLETION, INSERT_ESIGNATURE_COMPLETED_DOCOUMENT, UPDATE_ESIGNATURE_DOCUMENT, DISTRIBUTE_ESIGNATURE_DOCUMENT, QUERY_DOCUMENSO_KEY, GET_DOCUMENSO_KEY_BY_JOBID } = require("../graphql-client/queries"); const { uploadFileBuffer } = require("../media/imgproxy-media"); - +const axios = require("axios"); +const normalizeUrl = require("normalize-url"); +const { log } = require("node-persist"); const client = require('../graphql-client/graphql-client').client; const webhookTypeEnums = { @@ -48,15 +50,12 @@ async function esignWebhook(req, res) { break; case webhookTypeEnums.DOCUMENT_CREATED: //This is largely a throwaway event we know it was created. - // Here you can add any additional processing you want to do when a document is created break; case webhookTypeEnums.DOCUMENT_COMPLETED: //TODO: DR: Add notification for document completed. await handleDocumentCompleted(message.payload); - // Here you can add any additional processing you want to do when a document is completed break; case webhookTypeEnums.DOCUMENT_SIGNED: - // Here you can add any additional processing you want to do when a document is signed await client.request(UPDATE_ESIGNATURE_DOCUMENT, { external_document_id: documentId, esig_update: { @@ -114,7 +113,35 @@ async function handleDocumentCompleted(payload) { let key = `${jobs_by_pk.bodyshop.id}/${jobs_by_pk.id}/${replaceAccents(document.filename).replace(/[^A-Z0-9]+/gi, "_")}-${new Date().getTime()}.pdf`; if (jobs_by_pk?.bodyshop?.uselocalmediaserver) { - //TODO:LMS not yet implemented. + + const { bodyshop: { localmediaserverhttp, localmediatoken } } = jobs_by_pk; + + const options = { + headers: { + "X-Requested-With": "XMLHttpRequest", + ims_token: localmediatoken + }, + }; + const formData = new FormData(); + formData.append("jobid", jobid); + formData.append("file", buffer); //TODO: Validate this is the correct type. + + const imexMediaServerResponse = await axios.post( + normalizeUrl(`${localmediaserverhttp}/jobs/upload`), + formData, + options + ); + + if (imexMediaServerResponse.status !== 200) { + log.error(`esig-webhook-lms-upload-error`, "ERROR", "redis", "api", { + message: imexMediaServerResponse.statusText, + jobid, + documentId: payload.id + }); + //TODO: DR: Add notification for document upload failure. + } else { + //Succesful upload - we don't really need to do anything here. + } } else { //S3 Upload @@ -134,22 +161,6 @@ async function handleDocumentCompleted(payload) { bucket: uploadResult.bucket }); - await client.request(DISTRIBUTE_ESIGNATURE_DOCUMENT, { - external_document_id: payload.id.toString(), - esig_update: { - status: "COMPLETED", - completed: true, - completed_at: new Date().toISOString() - }, - audit: { - jobid: jobs_by_pk.id, - bodyshopid: jobs_by_pk.bodyshop.id, - operation: `Esignature document with title ${payload.title} (ID: ${payload.documentMeta.id}) has been completed.`, - useremail: uploaded_by, - type: 'esig-complete' - } - }) - //insert the document record with the s3 key and bucket info. await client.request(INSERT_ESIGNATURE_COMPLETED_DOCOUMENT, { docInput: { @@ -166,6 +177,24 @@ async function handleDocumentCompleted(payload) { } } + //Update the audit trail and records to mark the document as completed. + await client.request(DISTRIBUTE_ESIGNATURE_DOCUMENT, { + external_document_id: payload.id.toString(), + esig_update: { + status: "COMPLETED", + completed: true, + completed_at: new Date().toISOString() + }, + audit: { + jobid: jobs_by_pk.id, + bodyshopid: jobs_by_pk.bodyshop.id, + operation: `Esignature document with title ${payload.title} (ID: ${payload.documentMeta.id}) has been completed.`, + useremail: uploaded_by, + type: 'esig-complete' + } + }) + + } catch (error) { logger.log(`esig-webhook-event-completed-error`, "ERROR", "redis", "api", { message: error.message, stack: error.stack,