mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
Merge branch 'OpenSignLabs:staging' into staging
This commit is contained in:
Generated
+45
-33
@@ -16,12 +16,13 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"parse": "^4.3.1",
|
||||
"parse": "^5.1.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"print-js": "^1.6.0",
|
||||
"radix-ui": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.2",
|
||||
"react-confetti": "^6.1.0",
|
||||
"react-cookie": "^7.1.4",
|
||||
"react-datepicker": "^6.4.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
@@ -7705,12 +7706,12 @@
|
||||
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
@@ -7718,7 +7719,7 @@
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
@@ -8778,9 +8779,9 @@
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -10961,16 +10962,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"body-parser": "1.20.2",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -17269,19 +17270,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/parse": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/parse/-/parse-4.3.1.tgz",
|
||||
"integrity": "sha512-ypLPhMPFsJY+C2MXg6HdrVu6ielsL+kUjcSqh7J01lPC5oBuLh70F9YMQSw51QBocEeMSVgB7eUorFOH+MkVpA==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/parse/-/parse-5.1.0.tgz",
|
||||
"integrity": "sha512-46gVRe1JHsh21Ht0/Ko6PeMDl6wELLMYxnZPFD6iZm2EWsWnzi2txNGE6PvnIv+G7yOufZIOD0BCZLYOFl3toA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime-corejs3": "7.23.2",
|
||||
"idb-keyval": "6.2.1",
|
||||
"react-native-crypto-js": "1.0.0",
|
||||
"uuid": "9.0.1",
|
||||
"ws": "8.13.0",
|
||||
"ws": "8.16.0",
|
||||
"xmlhttprequest": "1.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.21.0 <17 || >=18 <20"
|
||||
"node": ">=18 <21"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"crypto-js": "4.2.0"
|
||||
@@ -17331,9 +17332,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/parse/node_modules/ws": {
|
||||
"version": "8.13.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
|
||||
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -19308,9 +19309,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
@@ -19458,6 +19459,20 @@
|
||||
"react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-confetti": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz",
|
||||
"integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==",
|
||||
"dependencies": {
|
||||
"tween-functions": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0 || ^17.0.1 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-cookie": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-7.1.4.tgz",
|
||||
@@ -22575,6 +22590,11 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/tween-functions": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz",
|
||||
"integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -22823,14 +22843,6 @@
|
||||
"cookie": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-cookie/node_modules/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"parse": "^4.3.1",
|
||||
"parse": "^5.1.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"print-js": "^1.6.0",
|
||||
"radix-ui": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.2",
|
||||
"react-confetti": "^6.1.0",
|
||||
"react-cookie": "^7.1.4",
|
||||
"react-datepicker": "^6.4.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "../../styles/AddUser.css";
|
||||
import { getFileName } from "../../constant/Utils";
|
||||
import { checkIsSubscribed, getFileName } from "../../constant/Utils";
|
||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||
import Upgrade from "../../primitives/Upgrade";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
// import SelectFolder from "../../premitives/SelectFolder";
|
||||
|
||||
const EditTemplate = ({ template, onSuccess }) => {
|
||||
@@ -9,9 +12,21 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
Name: template?.Name || "",
|
||||
Note: template?.Note || "",
|
||||
Description: template?.Description || "",
|
||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false"
|
||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
|
||||
AutomaticReminders: template?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: template?.RemindOnceInEvery || 5
|
||||
});
|
||||
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
useEffect(() => {
|
||||
fetchSubscription();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
const fetchSubscription = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
}
|
||||
};
|
||||
const handleStrInput = (e) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
};
|
||||
@@ -25,12 +40,26 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const isChecked = formData.SendinOrder === "true" ? true : false;
|
||||
const data = { ...formData, SendinOrder: isChecked };
|
||||
const AutoReminder = formData?.AutomaticReminders || false;
|
||||
|
||||
let reminderDate = {};
|
||||
if (AutoReminder) {
|
||||
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
|
||||
const ReminderDate = new Date(template?.createdAt);
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
reminderDate = { NextReminderDate: ReminderDate };
|
||||
}
|
||||
const data = { ...formData, SendinOrder: isChecked, ...reminderDate };
|
||||
onSuccess(data);
|
||||
};
|
||||
|
||||
const handleAutoReminder = () => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
AutomaticReminders: !formData.AutomaticReminders
|
||||
}));
|
||||
};
|
||||
return (
|
||||
<div className="addusercontainer">
|
||||
<div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]">
|
||||
<div className="form-wrapper">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
@@ -128,6 +157,57 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
<div style={{ fontSize: 12 }}>No</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs mt-2">
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Disable Auto reminder is free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
Auto reminder{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
checked={formData.AutomaticReminders}
|
||||
onChange={handleAutoReminder}
|
||||
type="checkbox"
|
||||
value=""
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600 mt-2"></div>
|
||||
</label>
|
||||
</div>
|
||||
{isSubscribe && formData?.AutomaticReminders === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Remind once in every (Days)
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.RemindOnceInEvery}
|
||||
name="RemindOnceInEvery"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
onChange={handleStrInput}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
|
||||
<div className="buttoncontainer">
|
||||
<button type="submit" className="submitbutton">
|
||||
|
||||
@@ -10,7 +10,6 @@ import loader from "../../assets/images/loader2.gif";
|
||||
function EmailComponent({
|
||||
isEmail,
|
||||
pdfUrl,
|
||||
isCeleb,
|
||||
setIsEmail,
|
||||
setSuccessEmail,
|
||||
pdfName,
|
||||
@@ -22,6 +21,7 @@ function EmailComponent({
|
||||
const [emailList, setEmailList] = useState([]);
|
||||
const [emailValue, setEmailValue] = useState();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isEmailCelebration, setIsEmailCelebration] = useState(false);
|
||||
//function for send email
|
||||
const sendEmail = async () => {
|
||||
setIsLoading(true);
|
||||
@@ -62,6 +62,10 @@ function EmailComponent({
|
||||
" target=_blank>here</a> </p></div></div></body></html>"
|
||||
};
|
||||
sendMail = await axios.post(url, params, { headers: headers });
|
||||
setIsEmailCelebration(true);
|
||||
setTimeout(() => {
|
||||
setIsEmailCelebration(false);
|
||||
}, 3000);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
setIsLoading(false);
|
||||
@@ -245,22 +249,17 @@ function EmailComponent({
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
{isCeleb && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
marginLeft: "50px"
|
||||
}}
|
||||
>
|
||||
{isEmailCelebration && (
|
||||
<div className="absolute w-[100%] flex justify-center items-center">
|
||||
<img
|
||||
alt="print img"
|
||||
width={300}
|
||||
height={250}
|
||||
// style={styles.gifCeleb}
|
||||
src={celebration}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "system-ui",
|
||||
|
||||
@@ -561,7 +561,7 @@ export const signPdfFun = async (
|
||||
isCustomCompletionMail = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// below for loop is used to get first signature of user to send if to signpdf
|
||||
// for adding it in completion certificate
|
||||
let getSignature;
|
||||
@@ -676,7 +676,9 @@ export const createDocument = async (template, placeholders, signerData) => {
|
||||
objectId: Doc.CreatedBy.objectId
|
||||
},
|
||||
Signers: signers,
|
||||
SendinOrder: Doc?.SendinOrder || false
|
||||
SendinOrder: Doc?.SendinOrder || false,
|
||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5)
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -1349,8 +1351,8 @@ export const multiSignEmbed = async (
|
||||
position.type === radioButtonWidget
|
||||
? 10
|
||||
: position.type === "checkbox"
|
||||
? 10
|
||||
: newUpdateHeight;
|
||||
? 10
|
||||
: newUpdateHeight;
|
||||
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
||||
|
||||
if (signyourself) {
|
||||
|
||||
+160
-84
@@ -11,12 +11,14 @@ import SignersInput from "../components/shared/fields/SignersInput";
|
||||
import Title from "../components/Title";
|
||||
import PageNotFound from "./PageNotFound";
|
||||
import { SaveFileSize } from "../constant/saveFileSize";
|
||||
import { getFileName, toDataUrl } from "../constant/Utils";
|
||||
import { checkIsSubscribed, getFileName, toDataUrl } from "../constant/Utils";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import axios from "axios";
|
||||
import { isEnableSubscription, submitBtn } from "../constant/const";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import Upgrade from "../primitives/Upgrade";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
|
||||
// `Form` render all type of Form on this basis of their provided in path
|
||||
function Form() {
|
||||
@@ -48,7 +50,9 @@ const Forms = (props) => {
|
||||
TimeToCompleteDays: 15,
|
||||
SendinOrder: "false",
|
||||
password: "",
|
||||
file: ""
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false
|
||||
});
|
||||
const [fileupload, setFileUpload] = useState("");
|
||||
const [fileload, setfileload] = useState(false);
|
||||
@@ -60,6 +64,7 @@ const Forms = (props) => {
|
||||
const [isPassword, setIsPassword] = useState(false);
|
||||
const [isDecrypting, setIsDecrypting] = useState(false);
|
||||
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const handleStrInput = (e) => {
|
||||
setIsCorrectPass(true);
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
@@ -70,6 +75,17 @@ const Forms = (props) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [props.title]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSubscription();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
const fetchSubscription = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
}
|
||||
};
|
||||
|
||||
function getFileAsArrayBuffer(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
@@ -383,6 +399,8 @@ const Forms = (props) => {
|
||||
if (props.title !== "Sign Yourself") {
|
||||
const isChecked = formData.SendinOrder === "false" ? false : true;
|
||||
object.set("SendinOrder", isChecked);
|
||||
object.set("AutomaticReminders", formData.autoreminder);
|
||||
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
|
||||
}
|
||||
object.set("URL", fileupload);
|
||||
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
||||
@@ -402,7 +420,6 @@ const Forms = (props) => {
|
||||
className: "contracts_Users",
|
||||
objectId: ExtCls[0].objectId
|
||||
});
|
||||
|
||||
const res = await object.save();
|
||||
if (res) {
|
||||
setSigners([]);
|
||||
@@ -457,7 +474,11 @@ const Forms = (props) => {
|
||||
? "Note to myself"
|
||||
: "Please review and sign this document",
|
||||
TimeToCompleteDays: 15,
|
||||
SendinOrder: "true"
|
||||
SendinOrder: "true",
|
||||
password: "",
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false
|
||||
});
|
||||
setFileUpload("");
|
||||
setpercentage(0);
|
||||
@@ -536,6 +557,9 @@ const Forms = (props) => {
|
||||
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||
}
|
||||
};
|
||||
const handleAutoReminder = () => {
|
||||
setFormData((prev) => ({ ...prev, autoreminder: !formData.autoreminder }));
|
||||
};
|
||||
return (
|
||||
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
|
||||
<Title title={props?.title} />
|
||||
@@ -732,89 +756,141 @@ const Forms = (props) => {
|
||||
</div>
|
||||
)}
|
||||
{props.title !== "Sign Yourself" && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Send In Order
|
||||
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
|
||||
<sup>
|
||||
<i
|
||||
className="fa-solid fa-question rounded-full"
|
||||
style={{
|
||||
borderColor: "#33bbff",
|
||||
color: "#33bbff",
|
||||
fontSize: 13,
|
||||
borderWidth: 1.5,
|
||||
padding: "1.5px 4px"
|
||||
}}
|
||||
></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="sendInOrder-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">Send in Order</p>
|
||||
<p>
|
||||
Choose how you want the signing requests to be sent to
|
||||
the document signers:
|
||||
</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">Yes:</span>
|
||||
<span>
|
||||
{" "}
|
||||
Selecting this option will send the signing
|
||||
request to the first signer initially. Once the
|
||||
first signer completes their part, the next signer
|
||||
in the sequence will receive the request. This
|
||||
process continues until all signers have signed
|
||||
the document. This method ensures that the
|
||||
document is signed in a specific order.
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">No: </span>
|
||||
<span>
|
||||
Selecting this option will send the signing links
|
||||
to all signers simultaneously. Every signer can
|
||||
sign the document at their convenience, regardless
|
||||
of whether other signers have completed their
|
||||
signatures. This method is faster but does not
|
||||
enforce any signing order among the participants.
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
<>
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Send In Order
|
||||
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
|
||||
<sup>
|
||||
<i
|
||||
className="fa-solid fa-question rounded-full"
|
||||
style={{
|
||||
borderColor: "#33bbff",
|
||||
color: "#33bbff",
|
||||
fontSize: 13,
|
||||
borderWidth: 1.5,
|
||||
padding: "1.5px 4px"
|
||||
}}
|
||||
></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="sendInOrder-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">Send in Order</p>
|
||||
<p>
|
||||
Choose how you want the signing requests to be sent to
|
||||
the document signers:
|
||||
</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">Yes:</span>
|
||||
<span>
|
||||
{" "}
|
||||
Selecting this option will send the signing
|
||||
request to the first signer initially. Once the
|
||||
first signer completes their part, the next
|
||||
signer in the sequence will receive the request.
|
||||
This process continues until all signers have
|
||||
signed the document. This method ensures that
|
||||
the document is signed in a specific order.
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">No: </span>
|
||||
<span>
|
||||
Selecting this option will send the signing
|
||||
links to all signers simultaneously. Every
|
||||
signer can sign the document at their
|
||||
convenience, regardless of whether other signers
|
||||
have completed their signatures. This method is
|
||||
faster but does not enforce any signing order
|
||||
among the participants.
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Select the option that best suits the needs of your
|
||||
document processing.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
className=""
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">Yes</div>
|
||||
<p>
|
||||
Select the option that best suits the needs of your
|
||||
document processing.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">Yes</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">No</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">No</div>
|
||||
<div className="text-xs mt-2">
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Disable Auto reminder is free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
Auto reminder{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
checked={formData.autoreminder}
|
||||
onChange={handleAutoReminder}
|
||||
type="checkbox"
|
||||
value=""
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600 mt-2"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{formData?.autoreminder === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Remind once in every (Days)
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.remindOnceInEvery}
|
||||
name="remindOnceInEvery"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
onChange={handleStrInput}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import SignPad from "../components/pdf/SignPad";
|
||||
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
||||
import Tour from "reactour";
|
||||
import Confetti from "react-confetti";
|
||||
import moment from "moment";
|
||||
import {
|
||||
contractDocument,
|
||||
@@ -61,6 +62,7 @@ function PdfRequestFiles() {
|
||||
const [handleError, setHandleError] = useState();
|
||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||
const [otpLoader, setOtpLoader] = useState(false);
|
||||
const [isCelebration, setIsCelebration] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
@@ -219,7 +221,7 @@ function PdfRequestFiles() {
|
||||
}
|
||||
}
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async () => {
|
||||
const getDocumentDetails = async (isNextUser) => {
|
||||
let currUserId;
|
||||
//getting document details
|
||||
const documentData = await contractDocument(documentId);
|
||||
@@ -412,6 +414,27 @@ function PdfRequestFiles() {
|
||||
setSignerPos(documentData[0].Placeholders);
|
||||
}
|
||||
setPdfDetails(documentData);
|
||||
// Check if the current signer is not a last signer and handle the complete message.
|
||||
if (isNextUser) {
|
||||
const getSignedAuditTrail = documentData[0].AuditTrail.filter(
|
||||
(data) => data.Activity === "Signed"
|
||||
);
|
||||
const isLastSigner =
|
||||
getSignedAuditTrail?.length === documentData?.[0]?.Signers?.length;
|
||||
if (!isLastSigner) {
|
||||
setIsCompleted({
|
||||
isModal: true,
|
||||
message:
|
||||
"You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers."
|
||||
});
|
||||
} else {
|
||||
setIsCelebration(true);
|
||||
setTimeout(() => {
|
||||
setIsCelebration(false);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
setIsUiLoading(false);
|
||||
} else {
|
||||
alert("No data found!");
|
||||
@@ -701,19 +724,12 @@ function PdfRequestFiles() {
|
||||
setIsSigned(true);
|
||||
setSignedSigners([]);
|
||||
setUnSignedSigners([]);
|
||||
getDocumentDetails();
|
||||
getDocumentDetails(true);
|
||||
const index = pdfDetails?.[0].Signers.findIndex(
|
||||
(x) => x.Email === jsonSender.email
|
||||
);
|
||||
const newIndex = index + 1;
|
||||
const user = pdfDetails?.[0].Signers[newIndex];
|
||||
if (user) {
|
||||
setIsCompleted({
|
||||
isModal: true,
|
||||
message:
|
||||
"You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers."
|
||||
});
|
||||
}
|
||||
if (sendInOrder) {
|
||||
const requestBody = pdfDetails?.[0]?.RequestBody;
|
||||
const requestSubject = pdfDetails?.[0]?.RequestSubject;
|
||||
@@ -1120,7 +1136,6 @@ function PdfRequestFiles() {
|
||||
alertMessage: ""
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Title title={"Request Sign"} />
|
||||
@@ -1169,6 +1184,14 @@ function PdfRequestFiles() {
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{isCelebration && (
|
||||
<div style={{ position: "relative", zIndex: "1000" }}>
|
||||
<Confetti
|
||||
width={window.innerWidth}
|
||||
height={window.innerHeight}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="relative flex flex-col md:flex-row justify-between bg-[#ebebeb]"
|
||||
|
||||
@@ -405,7 +405,7 @@ function PlaceHolderSign() {
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else if (res[0] && res.length) {
|
||||
} else if (res.length && res[0]?.objectId) {
|
||||
setActiveMailAdapter(res[0]?.active_mail_adapter);
|
||||
setSignerUserId(res[0].objectId);
|
||||
const tourstatus = res[0].TourStatus && res[0].TourStatus;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PDFDocument } from "pdf-lib";
|
||||
import "../styles/signature.css";
|
||||
import Parse from "parse";
|
||||
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||
import Confetti from "react-confetti";
|
||||
import axios from "axios";
|
||||
import Loader from "../primitives/LoaderWithMsg";
|
||||
import loader from "../assets/images/loader2.gif";
|
||||
@@ -70,7 +71,6 @@ function SignYourSelf() {
|
||||
const [dragKey, setDragKey] = useState();
|
||||
const [signKey, setSignKey] = useState();
|
||||
const [imgWH, setImgWH] = useState({});
|
||||
const [isCeleb, setIsCeleb] = useState(false);
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
||||
const [successEmail, setSuccessEmail] = useState(false);
|
||||
@@ -109,6 +109,7 @@ function SignYourSelf() {
|
||||
const [isDontShow, setIsDontShow] = useState(false);
|
||||
const [extUserId, setExtUserId] = useState("");
|
||||
const [isCompleted, setIsCompleted] = useState(false);
|
||||
const [isCelebration, setIsCelebration] = useState(false);
|
||||
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||
const [activeMailAdapter, setActiveMailAdapter] = useState("");
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(true);
|
||||
@@ -229,8 +230,12 @@ function SignYourSelf() {
|
||||
setIsUiLoading(false);
|
||||
setIsSignPad(false);
|
||||
setIsEmail(true);
|
||||
setIsCelebration(true);
|
||||
setXyPostion([]);
|
||||
setSignBtnPosition([]);
|
||||
setTimeout(() => {
|
||||
setIsCelebration(false);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
@@ -649,10 +654,6 @@ function SignYourSelf() {
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
setIsCeleb(true);
|
||||
setTimeout(() => {
|
||||
setIsCeleb(false);
|
||||
}, 3000);
|
||||
setIsUiLoading(true);
|
||||
const existingPdfBytes = pdfArrayBuffer;
|
||||
// Load a PDFDocument from the existing PDF bytes
|
||||
@@ -1122,6 +1123,11 @@ function SignYourSelf() {
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{isCelebration && (
|
||||
<div style={{ position: "relative", zIndex: "999" }}>
|
||||
<Confetti width={window.innerWidth} height={window.innerHeight} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="signatureContainer" ref={divRef}>
|
||||
{!isEmailVerified && (
|
||||
@@ -1258,7 +1264,6 @@ function SignYourSelf() {
|
||||
<EmailComponent
|
||||
isEmail={isEmail}
|
||||
pdfUrl={pdfUrl}
|
||||
isCeleb={isCeleb}
|
||||
setIsEmail={setIsEmail}
|
||||
pdfName={pdfDetails[0] && pdfDetails[0].Name}
|
||||
setSuccessEmail={setSuccessEmail}
|
||||
|
||||
@@ -36,6 +36,7 @@ import AddRoleModal from "../components/pdf/AddRoleModal";
|
||||
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||
import Parse from "parse";
|
||||
const TemplatePlaceholder = () => {
|
||||
const navigate = useNavigate();
|
||||
const { templateId } = useParams();
|
||||
@@ -704,35 +705,29 @@ const TemplatePlaceholder = () => {
|
||||
Name: pdfDetails[0]?.Name || "",
|
||||
Note: pdfDetails[0]?.Note || "",
|
||||
Description: pdfDetails[0]?.Description || "",
|
||||
SendinOrder: pdfDetails[0]?.SendinOrder || false
|
||||
SendinOrder: pdfDetails[0]?.SendinOrder || false,
|
||||
AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
|
||||
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
|
||||
NextReminderDate: pdfDetails[0]?.NextReminderDate
|
||||
};
|
||||
const updateTemplate = new Parse.Object("contracts_Template");
|
||||
updateTemplate.id = templateId;
|
||||
for (const key in data) {
|
||||
updateTemplate.set(key, data[key]);
|
||||
}
|
||||
await updateTemplate.save(null, {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
});
|
||||
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Template/${templateId}`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
setIsCreateDocModal(true);
|
||||
setIsMailSend(true);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
setIsCreateDocModal(true);
|
||||
setIsMailSend(true);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} catch (e) {
|
||||
setIsLoading(false);
|
||||
alert("Something went wrong, please try again later.");
|
||||
console.log("error", e);
|
||||
}
|
||||
} else {
|
||||
@@ -1207,7 +1202,6 @@ const TemplatePlaceholder = () => {
|
||||
setIsCheckbox(false);
|
||||
};
|
||||
|
||||
console.log("signerpos", signerPos);
|
||||
return (
|
||||
<div>
|
||||
<Title title={"Template"} />
|
||||
|
||||
@@ -139,7 +139,10 @@ const ReportTable = (props) => {
|
||||
className: "_User",
|
||||
objectId: Doc.CreatedBy.objectId
|
||||
},
|
||||
Signers: signers
|
||||
Signers: signers,
|
||||
SendinOrder: Doc?.SendinOrder || false,
|
||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// `replaceMailVaribles` is used to replace variables from mail with there actual values
|
||||
function replaceMailVaribles(subject, body, variables) {
|
||||
let replacedSubject = subject;
|
||||
let replacedBody = body;
|
||||
|
||||
for (const variable in variables) {
|
||||
const regex = new RegExp(`{{${variable}}}`, 'g');
|
||||
if (subject) {
|
||||
replacedSubject = replacedSubject.replace(regex, variables[variable]);
|
||||
}
|
||||
if (body) {
|
||||
replacedBody = replacedBody.replace(regex, variables[variable]);
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
subject: replacedSubject,
|
||||
body: replacedBody,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// `sendmail` is used to signing reminder mail to signer
|
||||
async function sendMail(doc, signer, mailcount) {
|
||||
const subject = `{{sender_name}} has requested you to sign "{{document_title}}"`;
|
||||
const body = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign <b>"{{document_title}}"</b>.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p>{{signing_url}}</p><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team OpenSign™</p><br></body> </html>`;
|
||||
const url = `${process.env.SERVER_URL}/functions/sendmailv3`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
};
|
||||
|
||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||
const encodeBase64 = btoa(`${doc.objectId}/${signer.Email}/${signer.objectId}`);
|
||||
const expireDate = doc?.ExpiryDate?.iso;
|
||||
const newDate = new Date(expireDate);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
const signPdf = `${baseUrl.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr.Phone,
|
||||
receiver_name: signer.Name,
|
||||
receiver_email: signer.Email,
|
||||
receiver_phone: signer.Phone,
|
||||
expiry_date: localExpireDate,
|
||||
company_name: doc?.ExtUserPtr?.Company || '',
|
||||
signing_url: `<a href=${signPdf}>Sign here</a>`,
|
||||
};
|
||||
const mail = replaceMailVaribles(subject, body, variables);
|
||||
|
||||
let params = {
|
||||
mailProvider: doc?.ExtUserPtr?.active_mail_adapter,
|
||||
extUserId: doc?.ExtUserPtr?.objectId,
|
||||
recipient: signer.Email,
|
||||
subject: mail.subject,
|
||||
from: doc?.ExtUserPtr?.Email,
|
||||
html: mail.body,
|
||||
};
|
||||
try {
|
||||
// The axios request is used to send a signing reminder email.
|
||||
const res = await axios.post(url, params, { headers: headers });
|
||||
// console.log('res ', res.data.result);
|
||||
if (res.data.result.status === 'success') {
|
||||
mailcount += 1;
|
||||
return { status: 'success', count: mailcount };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in mail of sendreminder api', err);
|
||||
return { status: 'error' };
|
||||
}
|
||||
}
|
||||
export default async function autoReminder(request, response) {
|
||||
// The query below is used to find documents where the reminder date is less than or equal to the current date, and which have existing signers and a signed URL.
|
||||
try {
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.limit(2000);
|
||||
docQuery.lessThanOrEqualTo('NextReminderDate', new Date());
|
||||
docQuery.equalTo('AutomaticReminders', true);
|
||||
docQuery.exists('NextReminderDate');
|
||||
docQuery.exists('Signers');
|
||||
docQuery.exists('SignedUrl');
|
||||
docQuery.descending('createdAt');
|
||||
docQuery.include('Signers,AuditTrail.UserPtr,ExtUserPtr');
|
||||
docQuery.notEqualTo('IsCompleted', true);
|
||||
docQuery.notEqualTo('IsDeclined', true);
|
||||
docQuery.notEqualTo('IsArchive', true);
|
||||
docQuery.greaterThanOrEqualTo('ExpiryDate', new Date());
|
||||
|
||||
const docsArr = await docQuery.find({ useMasterKey: true });
|
||||
|
||||
if (docsArr && docsArr.length > 0) {
|
||||
const _docsArr = JSON.parse(JSON.stringify(docsArr));
|
||||
let mailCount = 0;
|
||||
for (const doc of _docsArr) {
|
||||
// The reminderDate variable is used to calculate the next reminder date.
|
||||
const RemindOnceInEvery = doc?.RemindOnceInEvery || 5;
|
||||
const ReminderDate = new Date(doc?.NextReminderDate?.iso);
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
// The sendInOrder variable is used to determine whether to send emails in order or not.
|
||||
const SendInOrder = doc?.SendinOrder || false;
|
||||
if (SendInOrder) {
|
||||
// The auditTrail variable is used to get the count of how many users have already signed the document.
|
||||
const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed');
|
||||
const count = auditTrail?.length || 0;
|
||||
const signer = doc?.Signers?.[count];
|
||||
if (signer) {
|
||||
const mailRes = await sendMail(doc, signer, mailCount);
|
||||
if (mailRes && mailRes.status === 'success') {
|
||||
mailCount += mailRes.count;
|
||||
}
|
||||
try {
|
||||
// The code below is used to update the next reminder date of the document based on the "remind once every X days" setting.
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = doc.objectId;
|
||||
updateDoc.set('NextReminderDate', ReminderDate);
|
||||
const updateRes = await updateDoc.save(null, { useMasterKey: true });
|
||||
// console.log('updateRes ', updateRes);
|
||||
} catch (err) {
|
||||
console.log('err in update document', err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The AuditTrail variable is used to check if there is any user who has already signed the document.
|
||||
const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed');
|
||||
if (auditTrail?.length > 0) {
|
||||
// The signers variable is used to get the signers who haven't signed the document.
|
||||
const signers = doc?.Signers.filter(signer => {
|
||||
const signedUser = auditTrail?.find(y => y.UserPtr.objectId === signer.objectId);
|
||||
if (!signedUser) {
|
||||
return signer;
|
||||
}
|
||||
});
|
||||
if (signers?.length > 0) {
|
||||
// The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet.
|
||||
for (const signer of signers) {
|
||||
const mailRes = await sendMail(doc, signer, mailCount);
|
||||
if (mailRes && mailRes.status === 'success') {
|
||||
mailCount += mailRes.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet.
|
||||
const signers = doc?.Signers;
|
||||
if (signers?.length > 0) {
|
||||
for (const signer of signers) {
|
||||
const mailRes = await sendMail(doc, signer, mailCount);
|
||||
if (mailRes && mailRes.status === 'success') {
|
||||
mailCount += mailRes.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The code below is used to update the next reminder date of the document based on the "remind once every X days" setting.
|
||||
try {
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = doc.objectId;
|
||||
updateDoc.set('NextReminderDate', ReminderDate);
|
||||
const updateRes = await updateDoc.save(null, { useMasterKey: true });
|
||||
// console.log('updateRes ', updateRes);
|
||||
} catch (err) {
|
||||
console.log('err in sendmail', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
response.json({ status: 'success', document_count: docsArr.length, mail_count: mailCount });
|
||||
} else {
|
||||
response.json({ status: 'no record found' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
const code = err?.code || 400;
|
||||
const message = err?.message || 'Somehting went wrong!';
|
||||
response.status(code).json({ error: message });
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import saveSubscription from './saveSubscription.js';
|
||||
import saveInvoice from './saveInvoice.js';
|
||||
import savePayments from './savePayments.js';
|
||||
import gooogleauth from './googleauth.js';
|
||||
import autoReminder from './autoReminder.js';
|
||||
export const app = express();
|
||||
|
||||
dotenv.config();
|
||||
@@ -16,10 +17,8 @@ app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||
|
||||
app.post('/file_upload', uploadFile);
|
||||
|
||||
app.post('/savesubscription', saveSubscription)
|
||||
app.post('/saveinvoice', saveInvoice)
|
||||
app.post('/savepayment', savePayments)
|
||||
app.post('/googleauth', gooogleauth)
|
||||
|
||||
|
||||
|
||||
app.post('/savesubscription', saveSubscription);
|
||||
app.post('/saveinvoice', saveInvoice);
|
||||
app.post('/savepayment', savePayments);
|
||||
app.post('/googleauth', gooogleauth);
|
||||
app.post('/sendreminder', autoReminder);
|
||||
|
||||
@@ -14,19 +14,29 @@ async function DocumentAftersave(request) {
|
||||
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
||||
updateQuery.set('ExpiryDate', ExpiryDate);
|
||||
updateQuery.set('OriginIp', ip);
|
||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
||||
if (AutoReminder) {
|
||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
||||
const ReminderDate = new Date(createdAt);
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
updateQuery.set('NextReminderDate', ReminderDate);
|
||||
}
|
||||
await updateQuery.save(null, { useMasterKey: true });
|
||||
} else if (createdAt && Folder === 'AIDoc') {
|
||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
||||
const ExpiryDate = new Date(createdAt);
|
||||
// console.log("ExpiryDate")
|
||||
// console.log(ExpiryDate)
|
||||
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
|
||||
// console.log("ExpiryDate date after update")
|
||||
// console.log(ExpiryDate)
|
||||
const documentQuery = new Parse.Query('contracts_Document');
|
||||
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
||||
updateQuery.set('ExpiryDate', ExpiryDate);
|
||||
updateQuery.set('OriginIp', ip);
|
||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
||||
if (AutoReminder) {
|
||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
||||
const ReminderDate = new Date(createdAt);
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
updateQuery.set('NextReminderDate', ReminderDate);
|
||||
}
|
||||
await updateQuery.save(null, { useMasterKey: true });
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export default async function GetTemplate(request) {
|
||||
if (res) {
|
||||
// console.log("res ",res)
|
||||
const acl = res.getACL();
|
||||
console.log("acl", acl.getReadAccess(userId))
|
||||
// console.log("acl", acl.getReadAccess(userId))
|
||||
if (acl && acl.getReadAccess(userId)) {
|
||||
return res;
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,14 @@ export default async function TemplateAfterSave(request) {
|
||||
console.log('new entry is insert in contracts_Template');
|
||||
// update acl of New Document If There are signers present in array
|
||||
const signers = request.object.get('Signers');
|
||||
|
||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
||||
if (AutoReminder) {
|
||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
||||
const ReminderDate = new Date(request?.object?.get('createdAt'));
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
request.object.set('NextReminderDate', ReminderDate);
|
||||
await request.object.save(null, { useMasterKey: true });
|
||||
}
|
||||
if (signers && signers.length > 0) {
|
||||
await updateAclDoc(request.object.id);
|
||||
} else {
|
||||
|
||||
+103
-92
@@ -1,13 +1,16 @@
|
||||
import SignPDF from './SignPDF.min.cjs';
|
||||
import fs from 'node:fs';
|
||||
import axios from 'axios';
|
||||
import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js';
|
||||
import { SignPdf } from '@signpdf/signpdf';
|
||||
import { P12Signer } from '@signpdf/signer-p12';
|
||||
import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib';
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
import { replaceMailVaribles, saveFileUsage } from '../../../Utils.js';
|
||||
import GenerateCertificate from './GenerateCertificate.js';
|
||||
const serverUrl = process.env.SERVER_URL,
|
||||
APPID = process.env.APP_ID,
|
||||
masterKEY = process.env.MASTER_KEY;
|
||||
masterKEY = process.env.MASTER_KEY,
|
||||
eSignName = 'opensign',
|
||||
eSigncontact = 'hello@opensignlabs.com';
|
||||
async function uploadFile(e, t) {
|
||||
try {
|
||||
var a = fs.readFileSync(t),
|
||||
@@ -18,23 +21,23 @@ async function uploadFile(e, t) {
|
||||
console.log('Err ', e), fs.unlinkSync(t);
|
||||
}
|
||||
}
|
||||
async function updateDoc(a, r, i, s, o, n, l) {
|
||||
async function updateDoc(a, r, i, n, s, o, l) {
|
||||
try {
|
||||
var c,
|
||||
d,
|
||||
p = {
|
||||
UserPtr: { __type: 'Pointer', className: n, objectId: i },
|
||||
UserPtr: { __type: 'Pointer', className: o, objectId: i },
|
||||
SignedUrl: r,
|
||||
Activity: 'Signed',
|
||||
ipAddress: s,
|
||||
ipAddress: n,
|
||||
SignedOn: new Date(),
|
||||
Signature: l,
|
||||
};
|
||||
let e;
|
||||
var m = (e =
|
||||
o.AuditTrail && 0 < o.AuditTrail.length
|
||||
s.AuditTrail && 0 < s.AuditTrail.length
|
||||
? (-1 !==
|
||||
(d = (c = JSON.parse(JSON.stringify(o.AuditTrail))).findIndex(
|
||||
(d = (c = JSON.parse(JSON.stringify(s.AuditTrail))).findIndex(
|
||||
e => e.UserPtr.objectId === i && 'Created' !== e.Activity
|
||||
))
|
||||
? (c[d] = { ...c[d], ...p })
|
||||
@@ -42,7 +45,7 @@ async function updateDoc(a, r, i, s, o, n, l) {
|
||||
c)
|
||||
: [p]).filter(e => 'Signed' === e.Activity);
|
||||
let t = !1;
|
||||
!((o.Signers && 0 < o.Signers.length && m.length !== o.Signers.length) || !(t = !0));
|
||||
!((s.Signers && 0 < s.Signers.length && m.length !== s.Signers.length) || !(t = !0));
|
||||
var g = { SignedUrl: r, AuditTrail: e, IsCompleted: t };
|
||||
await axios.put(serverUrl + '/classes/contracts_Document/' + a, g, {
|
||||
headers: {
|
||||
@@ -61,9 +64,9 @@ async function sendCompletedMail(e) {
|
||||
a = e.doc,
|
||||
r = e.doc.ExtUserPtr,
|
||||
i = a.Name,
|
||||
s = r.Email;
|
||||
let o = `Document "${i}" has been signed by all parties`,
|
||||
n =
|
||||
n = r.Email;
|
||||
let s = `Document "${i}" has been signed by all parties`,
|
||||
o =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document signed successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document " +
|
||||
`<b>"${i}"</b>` +
|
||||
'. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ' +
|
||||
@@ -80,8 +83,8 @@ async function sendCompletedMail(e) {
|
||||
g.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: r.UserId.objectId });
|
||||
const f = await g.first();
|
||||
f &&
|
||||
((l = JSON.parse(JSON.stringify(f)))?.CompletionSubject && (o = l?.CompletionSubject),
|
||||
l?.CompletionBody && (n = l?.CompletionBody),
|
||||
((l = JSON.parse(JSON.stringify(f)))?.CompletionSubject && (s = l?.CompletionSubject),
|
||||
l?.CompletionBody && (o = l?.CompletionBody),
|
||||
(c = a.ExpiryDate.iso),
|
||||
(d = new Date(c).toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
@@ -99,9 +102,9 @@ async function sendCompletedMail(e) {
|
||||
expiry_date: d,
|
||||
company_name: r.Company,
|
||||
}),
|
||||
(m = replaceMailVaribles(o, n, p)),
|
||||
(o = m.subject),
|
||||
(n = m.body));
|
||||
(m = replaceMailVaribles(s, o, p)),
|
||||
(s = m.subject),
|
||||
(o = m.body));
|
||||
} catch (e) {
|
||||
console.log('error in fetch tenant in signpdf', e.message);
|
||||
}
|
||||
@@ -109,10 +112,10 @@ async function sendCompletedMail(e) {
|
||||
extUserId: r.objectId,
|
||||
url: t,
|
||||
from: 'OpenSign™',
|
||||
recipient: s,
|
||||
subject: o,
|
||||
recipient: n,
|
||||
subject: s,
|
||||
pdfName: i,
|
||||
html: n,
|
||||
html: o,
|
||||
mailProvider: e.mailProvider,
|
||||
};
|
||||
await axios.post(serverUrl + '/functions/sendmailv3', g, {
|
||||
@@ -124,8 +127,8 @@ async function sendCompletedMail(e) {
|
||||
});
|
||||
}
|
||||
async function sendDoctoWebhook(a, e, t, r, i) {
|
||||
let s = [];
|
||||
(s = r
|
||||
let n = [];
|
||||
(n = r
|
||||
? { name: r?.Name, email: r?.Email, phone: r?.Phone }
|
||||
: a?.Signers?.map(e => ({ name: e.Name, email: e.Email, phone: e.Phone })) || [
|
||||
{ name: a?.ExtUserPtr?.Name, email: a?.ExtUserPtr?.Email, phone: a?.ExtUserPtr?.Phone },
|
||||
@@ -133,8 +136,8 @@ async function sendDoctoWebhook(a, e, t, r, i) {
|
||||
a.ExtUserPtr?.Webhook &&
|
||||
((r =
|
||||
'signed' === t
|
||||
? { signer: s, signedAt: new Date() }
|
||||
: { signers: s, completedAt: new Date() }),
|
||||
? { signer: n, signedAt: new Date() }
|
||||
: { signers: n, completedAt: new Date() }),
|
||||
(t = {
|
||||
event: t,
|
||||
objectId: a?.objectId,
|
||||
@@ -178,24 +181,27 @@ async function sendDoctoWebhook(a, e, t, r, i) {
|
||||
}
|
||||
}));
|
||||
}
|
||||
const sendMailsaveCertifcate = async (e, t, a, r, i, s) => {
|
||||
var o = await GenerateCertificate(e),
|
||||
o = await PDFDocument.load(o),
|
||||
o =
|
||||
const sendMailsaveCertifcate = async (e, t, a, r, i, n) => {
|
||||
var s = await GenerateCertificate(e),
|
||||
s = await PDFDocument.load(s),
|
||||
t = new P12Signer(t, { passphrase: process.env.PASS_PHRASE || null }),
|
||||
s =
|
||||
(pdflibAddPlaceholder({
|
||||
pdfDoc: o,
|
||||
pdfDoc: s,
|
||||
reason: 'Digitally signed by OpenSign.',
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15e3,
|
||||
}),
|
||||
await o.save()),
|
||||
o = Buffer.from(o),
|
||||
t = await new SignPDF(o, t).signPDF(),
|
||||
await s.save()),
|
||||
s = Buffer.from(s),
|
||||
t = await new SignPdf().sign(s, t),
|
||||
t =
|
||||
(fs.writeFileSync('./exports/certificate.pdf', t),
|
||||
await uploadFile('certificate.pdf', './exports/certificate.pdf')),
|
||||
n = { CertificateUrl: t.imageUrl };
|
||||
await axios.put(serverUrl + '/classes/contracts_Document/' + e.objectId, n, {
|
||||
o = { CertificateUrl: t.imageUrl };
|
||||
await axios.put(serverUrl + '/classes/contracts_Document/' + e.objectId, o, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': APPID,
|
||||
@@ -205,20 +211,20 @@ const sendMailsaveCertifcate = async (e, t, a, r, i, s) => {
|
||||
e.IsSendMail && !1 === e.IsSendMail
|
||||
? console.log("don't send mail")
|
||||
: sendCompletedMail({ url: a, isCustomMail: r, doc: e, mailProvider: i }),
|
||||
saveFileUsage(o.length, t.imageUrl, s),
|
||||
saveFileUsage(s.length, t.imageUrl, n),
|
||||
sendDoctoWebhook(e, a, 'completed', '', t.imageUrl);
|
||||
};
|
||||
async function PDF(o) {
|
||||
async function PDF(s) {
|
||||
try {
|
||||
if (!o?.user)
|
||||
if (!s?.user)
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
{
|
||||
var n = o?.user?.toJSON(),
|
||||
e = o.params.docId;
|
||||
const F = o.params.userId;
|
||||
var l = o.params.isCustomCompletionMail || !1,
|
||||
c = o.params.mailProvider || '',
|
||||
d = o.params.signature || '',
|
||||
var o = s?.user?.toJSON(),
|
||||
e = s.params.docId;
|
||||
const C = s.params.userId;
|
||||
var l = s.params.isCustomCompletionMail || !1,
|
||||
c = s.params.mailProvider || '',
|
||||
d = s.params.signature || '',
|
||||
t = new Parse.Query('contracts_Document'),
|
||||
a =
|
||||
(t.include('ExtUserPtr,Signers'),
|
||||
@@ -227,95 +233,100 @@ async function PDF(o) {
|
||||
if (!a) throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
|
||||
var r,
|
||||
p = a?.toJSON();
|
||||
let i, s;
|
||||
F
|
||||
? ((r = p.Signers.find(e => e.objectId === F)),
|
||||
let i, n;
|
||||
C
|
||||
? ((r = p.Signers.find(e => e.objectId === C)),
|
||||
console.log('_contractUser ', r),
|
||||
r && ((i = r), (s = 'contracts_Contactbook')))
|
||||
: ((s = 'contracts_Users'), (i = p.ExtUserPtr));
|
||||
r && ((i = r), (n = 'contracts_Contactbook')))
|
||||
: ((n = 'contracts_Users'), (i = p.ExtUserPtr));
|
||||
var m,
|
||||
g = i.Name,
|
||||
f = i.Email;
|
||||
if (!o.params.pdfFile) throw (((m = new Error('Pdf file not present!')).code = 400), m);
|
||||
if (!s.params.pdfFile) throw (((m = new Error('Pdf file not present!')).code = 400), m);
|
||||
{
|
||||
let e = Buffer.from(o.params.pdfFile, 'base64');
|
||||
let e = Buffer.from(s.params.pdfFile, 'base64');
|
||||
var u = process.env.PFX_BASE64,
|
||||
h = Buffer.from(u, 'base64'),
|
||||
y = {
|
||||
UserPtr: { __type: 'Pointer', className: s, objectId: i.objectId },
|
||||
y = new P12Signer(h, { passphrase: process.env.PASS_PHRASE || null }),
|
||||
P = {
|
||||
UserPtr: { __type: 'Pointer', className: n, objectId: i.objectId },
|
||||
SignedUrl: '',
|
||||
Activity: 'Signed',
|
||||
ipAddress: o.headers['x-real-ip'],
|
||||
ipAddress: s.headers['x-real-ip'],
|
||||
};
|
||||
let t;
|
||||
var P = (t = p.AuditTrail && 0 < p.AuditTrail.length ? [...p.AuditTrail, y] : [y]).filter(
|
||||
var v = (t = p.AuditTrail && 0 < p.AuditTrail.length ? [...p.AuditTrail, P] : [P]).filter(
|
||||
e => 'Signed' === e.Activity
|
||||
);
|
||||
let a = !1;
|
||||
!((p.Signers && 0 < p.Signers.length && P.length !== p.Signers.length) || !(a = !0));
|
||||
var v,
|
||||
!((p.Signers && 0 < p.Signers.length && v.length !== p.Signers.length) || !(a = !0));
|
||||
var S,
|
||||
b,
|
||||
S,
|
||||
w,
|
||||
U,
|
||||
D,
|
||||
I = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
|
||||
_ = './exports/' + I;
|
||||
I,
|
||||
_,
|
||||
E = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
|
||||
D = './exports/' + E;
|
||||
let r = e.length;
|
||||
r = (
|
||||
a
|
||||
? ((v = p.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
|
||||
? ((S = p.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
|
||||
(e =
|
||||
v && 0 < v.length
|
||||
S && 0 < S.length
|
||||
? ((b = await PDFDocument.load(e)),
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: b,
|
||||
reason: 'Digitally signed by OpenSign for ' + v?.join(', '),
|
||||
reason: 'Digitally signed by OpenSign for ' + S?.join(', '),
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15e3,
|
||||
}),
|
||||
(S = await b.save()),
|
||||
Buffer.from(S))
|
||||
: ((w = await PDFDocument.load(e)),
|
||||
(w = await b.save()),
|
||||
Buffer.from(w))
|
||||
: ((U = await PDFDocument.load(e)),
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: w,
|
||||
pdfDoc: U,
|
||||
reason: 'Digitally signed by OpenSign for ' + g + ' <' + f + '>',
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15e3,
|
||||
}),
|
||||
(U = await w.save()),
|
||||
Buffer.from(U))),
|
||||
(D = await new SignPDF(e, h).signPDF()),
|
||||
fs.writeFileSync(_, D),
|
||||
D)
|
||||
: (fs.writeFileSync(_, e), e)
|
||||
(I = await U.save()),
|
||||
Buffer.from(I))),
|
||||
(_ = await new SignPdf().sign(e, y)),
|
||||
fs.writeFileSync(D, _),
|
||||
_)
|
||||
: (fs.writeFileSync(D, e), e)
|
||||
).length;
|
||||
var E = await uploadFile(I, _);
|
||||
if (E && E.imageUrl) {
|
||||
var A = await uploadFile(E, D);
|
||||
if (A && A.imageUrl) {
|
||||
var x,
|
||||
A,
|
||||
j = await updateDoc(
|
||||
o.params.docId,
|
||||
E.imageUrl,
|
||||
j,
|
||||
N = await updateDoc(
|
||||
s.params.docId,
|
||||
A.imageUrl,
|
||||
i.objectId,
|
||||
o.headers['x-real-ip'],
|
||||
s.headers['x-real-ip'],
|
||||
p,
|
||||
s,
|
||||
n,
|
||||
d
|
||||
);
|
||||
if (
|
||||
(sendDoctoWebhook(p, E.imageUrl, 'signed', i),
|
||||
saveFileUsage(r, E.imageUrl, n.objectId),
|
||||
j &&
|
||||
j.isCompleted &&
|
||||
((x = { ...p, AuditTrail: j.AuditTrail }),
|
||||
sendMailsaveCertifcate(x, h, E.imageUrl, l, c, n.objectId)),
|
||||
fs.unlinkSync(_),
|
||||
console.log('New Signed PDF created called: ' + _),
|
||||
'success' === j.message)
|
||||
(sendDoctoWebhook(p, A.imageUrl, 'signed', i),
|
||||
saveFileUsage(r, A.imageUrl, o.objectId),
|
||||
N &&
|
||||
N.isCompleted &&
|
||||
((x = { ...p, AuditTrail: N.AuditTrail }),
|
||||
sendMailsaveCertifcate(x, h, A.imageUrl, l, c, o.objectId)),
|
||||
fs.unlinkSync(D),
|
||||
console.log('New Signed PDF created called: ' + D),
|
||||
'success' === N.message)
|
||||
)
|
||||
return { status: 'success', data: E.imageUrl };
|
||||
throw (((A = new Error('Please provide required parameters!')).code = 400), A);
|
||||
return { status: 'success', data: A.imageUrl };
|
||||
throw (((j = new Error('Please provide required parameters!')).code = 400), j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
const signer=require("node-signpdf").default;class SignPDF{constructor(e,t){this.pdfDoc=e,this.certificate=t}async signPDF(){return signer.sign(this.pdfDoc,this.certificate, process.env.PASS_PHRASE ? {passphrase : process.env.PASS_PHRASE}: null)}static unit8ToBuffer(e){var t=Buffer.alloc(e.byteLength),r=new Uint8Array(e);for(let e=0;e<t.length;++e)t[e]=r[e];return t}}module.exports=SignPDF;
|
||||
-1
@@ -1 +0,0 @@
|
||||
class PDFAbstractReference{toString(){throw new Error("Must be implemented by subclasses")}}export default PDFAbstractReference;
|
||||
-1
@@ -1 +0,0 @@
|
||||
import PDFAbstractReference from"./PDFAbstractReference.min.js";class PDFKitReferenceMock extends PDFAbstractReference{constructor(e,t=void 0){super(),this.index=e,void 0!==t&&Object.assign(this,t)}toString(){return this.index+" 0 R"}}export default PDFKitReferenceMock;
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
const ERROR_TYPE_UNKNOWN = 1,
|
||||
ERROR_TYPE_INPUT = 2,
|
||||
ERROR_TYPE_PARSE = 3,
|
||||
ERROR_VERIFY_SIGNATURE = 4;
|
||||
class SignPdfError extends Error {
|
||||
constructor(R, E = ERROR_TYPE_UNKNOWN) {
|
||||
super(R), (this.type = E);
|
||||
}
|
||||
}
|
||||
(SignPdfError.TYPE_UNKNOWN = ERROR_TYPE_UNKNOWN),
|
||||
(SignPdfError.TYPE_INPUT = ERROR_TYPE_INPUT),
|
||||
(SignPdfError.TYPE_PARSE = ERROR_TYPE_PARSE),
|
||||
(SignPdfError.VERIFY_SIGNATURE = ERROR_VERIFY_SIGNATURE);
|
||||
export {
|
||||
ERROR_TYPE_UNKNOWN,
|
||||
ERROR_TYPE_INPUT,
|
||||
ERROR_TYPE_PARSE,
|
||||
ERROR_VERIFY_SIGNATURE,
|
||||
SignPdfError,
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
const DEFAULT_SIGNATURE_LENGTH=8192,DEFAULT_BYTE_RANGE_PLACEHOLDER="**********",SUBFILTER_ADOBE_PKCS7_DETACHED="adbe.pkcs7.detached",SUBFILTER_ADOBE_PKCS7_SHA1="adbe.pkcs7.sha1",SUBFILTER_ADOBE_X509_SHA1="adbe.x509.rsa.sha1",SUBFILTER_ETSI_CADES_DETACHED="ETSI.CAdES.detached";export{DEFAULT_SIGNATURE_LENGTH,DEFAULT_BYTE_RANGE_PLACEHOLDER,SUBFILTER_ADOBE_PKCS7_DETACHED,SUBFILTER_ADOBE_PKCS7_SHA1,SUBFILTER_ADOBE_X509_SHA1,SUBFILTER_ETSI_CADES_DETACHED};
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
import findObject from"./findObject.min.js";import getIndexFromRef from"./getIndexFromRef.min.js";const createBufferPageWithAnnotation=(e,t,n,f)=>{e=findObject(e,t.xref,n).toString();let r,o,i;r=e.indexOf("/Annots"),i=-1<r?(o=e.indexOf("]",r),(i=e.substr(r,o+1-r)).substr(0,i.length-1)):(r=e.length,o=e.length,"/Annots [");t=getIndexFromRef(t.xref,n),n=f.toString(),i+=` ${n}]`,f=e.substr(0,r);let m="";return e.length>o&&(m=e.substr(o+1)),Buffer.concat([Buffer.from(t+` 0 obj
|
||||
`),Buffer.from("<<\n"),Buffer.from(f+i+m+`
|
||||
`),Buffer.from("\n>>\nendobj\n")])};export default createBufferPageWithAnnotation;
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
import getIndexFromRef from"./getIndexFromRef.min.js";const createBufferRootWithAcroform=(r,f,o)=>{var e=getIndexFromRef(f.xref,f.rootRef);return Buffer.concat([Buffer.from(e+` 0 obj
|
||||
`),Buffer.from("<<\n"),Buffer.from(f.root+`
|
||||
`),Buffer.from("/AcroForm "+o),Buffer.from("\n>>\nendobj\n")])};export default createBufferRootWithAcroform;
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
const createBufferTrailer=(f,r,e)=>{let o=[];return o[0]="0000000000 65535 f ",e.forEach((f,r)=>{f=("0000000000"+f).slice(-10);o[r+1]=r+` 1
|
||||
${f} 00000 n `}),o=o.filter(f=>void 0!==f),Buffer.concat([Buffer.from("xref\n"),Buffer.from(r.xref.startingIndex+` 1
|
||||
`),Buffer.from(o.join("\n")),Buffer.from("\ntrailer\n"),Buffer.from("<<\n"),Buffer.from(`/Size ${r.xref.maxIndex+1}
|
||||
`),Buffer.from(`/Root ${r.rootRef}
|
||||
`),Buffer.from(r.infoRef?`/Info ${r.infoRef}
|
||||
`:""),Buffer.from(`/Prev ${r.xRefPosition}
|
||||
`),Buffer.from(">>\n"),Buffer.from("startxref\n"),Buffer.from(f.length+`
|
||||
`),Buffer.from("%%EOF")])};export default createBufferTrailer;
|
||||
@@ -1 +0,0 @@
|
||||
import getIndexFromRef from"./getIndexFromRef.min.js";const findObject=(e,t,f)=>{f=getIndexFromRef(t,f),t=t.offsets.get(f);let n=e.slice(t);return n=(n=(n=n.slice(0,n.indexOf("endobj","utf8"))).slice(n.indexOf("<<","utf8")+2)).slice(0,n.lastIndexOf(">>","utf8"))};export default findObject;
|
||||
-1
@@ -1 +0,0 @@
|
||||
import SignPdfError from"./SignPdfError.min.js";const getIndexFromRef=(r,e)=>{var[o]=e.split(" "),o=parseInt(o);if(r.offsets.has(o))return o;throw new SignPdfError(`Failed to locate object "${e}".`,SignPdfError.TYPE_PARSE)};export default getIndexFromRef;
|
||||
@@ -1 +0,0 @@
|
||||
import getPagesDictionaryRef from"./getPagesDictionaryRef.min.js";import findObject from"./findObject.min.js";export default function getPageRef(e,t,i){var n=getPagesDictionaryRef(t),e=findObject(e,t.xref,n),t=e.indexOf("/Kids"),n=e.indexOf("[",t)+1,t=e.indexOf("]",t);const f=e.slice(n,t).toString();for(var r=[],o=0;o<f.length;o++)"R"===f[o]&&r.push(o);let a={},g=0;return r.forEach((e,t)=>{a={...a,[t+1]:f.substring(g+1,e+1)},g=e+1}),i?a[i]:a[1]}
|
||||
-1
@@ -1 +0,0 @@
|
||||
import SignPdfError from"./SignPdfError.min.js";export default function getPagesDictionaryRef(r){r=/\/Pages\s+(\d+\s+\d+\s+R)/g.exec(r.root);if(null===r)throw new SignPdfError("Failed to find the pages descriptor. This is probably a problem in node-signpdf.",SignPdfError.TYPE_PARSE);return r[1]}
|
||||
@@ -1 +0,0 @@
|
||||
import PDFAbstractReference from"./PDFAbstractReference.min.js";const pad=(e,t)=>(Array(t+1).join("0")+e).slice(-t),escapableRe=/[\n\r\t\b\f()\\]/g,escapable={"\n":"\\n","\r":"\\r","\t":"\\t","\b":"\\b","\f":"\\f","\\":"\\\\","(":"\\(",")":"\\)"},swapBytes=e=>e.swap16();export default class PDFObject{static convert(t,a=null){if("string"==typeof t)return"/"+t;if(t instanceof String){let r=t,n=!1;for(let e=0,t=r.length;e<t;e+=1)if(127<r.charCodeAt(e)){n=!0;break}let e;return e=n?swapBytes(Buffer.from(``+r,"utf16le")):Buffer.from(r,"ascii"),`(${r=(r=(a?a(e):e).toString("binary")).replace(escapableRe,e=>escapable[e])})`}if(Buffer.isBuffer(t))return`<${t.toString("hex")}>`;if(t instanceof PDFAbstractReference)return t.toString();if(t instanceof Date){let e=`D:${pad(t.getUTCFullYear(),4)}${pad(t.getUTCMonth()+1,2)}${pad(t.getUTCDate(),2)}${pad(t.getUTCHours(),2)}${pad(t.getUTCMinutes(),2)}${pad(t.getUTCSeconds(),2)}Z`;return`(${e=a?(e=a(Buffer.from(e,"ascii")).toString("binary")).replace(escapableRe,e=>escapable[e]):e})`}if(Array.isArray(t))return`[${t.map(e=>PDFObject.convert(e,a)).join(" ")}]`;if("[object Object]"!=={}.toString.call(t))return"number"==typeof t?PDFObject.number(t):""+t;{const n=["<<"];return Object.entries(t).forEach(([e,t])=>{let r="";r=t&&-1!==t.toString().indexOf("<<")?t:PDFObject.convert(t,a),n.push(`/${e} `+r)}),n.push(">>"),n.join("\n")}}static number(e){if(-1e21<e&&e<1e21)return Math.round(1e6*e)/1e6;throw new Error("unsupported number: "+e)}}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
import{DEFAULT_BYTE_RANGE_PLACEHOLDER,DEFAULT_SIGNATURE_LENGTH,SUBFILTER_ADOBE_PKCS7_DETACHED}from"./const.min.js";import PDFKitReferenceMock from"./PDFKitReferenceMock.min.js";import PNG from"png-js";import zlib from"zlib";const specialCharacters=["á","Á","é","É","í","Í","ó","Ó","ö","Ö","ő","Ő","ú","Ú","ű","Ű"],MARKERS=[65472,65473,65474,65475,65477,65478,65479,65480,65481,65482,65483,65484,65485,65486,65487],COLOR_SPACE_MAP={1:"DeviceGray",3:"DeviceRGB",4:"DeviceCMYK"};function getImage(e,t){let n;if(255===e[0]&&216===e[1])n=getJpgImage(t,e);else{if(137!==e[0]||"PNG"!==e.toString("ascii",1,4))throw new Error("Unknown image format.");n=getPngImage(t,e)}return n}function getAnnotationApparance(e,t,n){return e.ref({CropBox:[0,10,200,60],Type:"XObject",FormType:1,BBox:[0,10,200,60],Resources:`<</XObject <<
|
||||
/Img${t.index} ${t.index} 0 R
|
||||
>>
|
||||
/Font <<
|
||||
/f1 ${n.index} 0 R
|
||||
>>
|
||||
>>`,MediaBox:[0,10,200,60],Subtype:"Form"},null,getStream(t.index))}const getStream=e=>getConvertedText(`
|
||||
1.0 1.0 1.0 rg
|
||||
0.0 0.0 0.0 RG
|
||||
q
|
||||
q
|
||||
200 0 0 50 0 10 cm
|
||||
/Img${e} Do
|
||||
Q
|
||||
0 0 0 rg
|
||||
BT
|
||||
0 Tr
|
||||
/f1 10.0 Tf
|
||||
1.4 0 0 1 20 45.97412 Tm
|
||||
ET
|
||||
BT
|
||||
0 Tr
|
||||
/f1 10.0 Tf
|
||||
1.4 0 0 1 20 33.56006 Tm
|
||||
ET
|
||||
Q`),getFont=(e,t)=>e.ref({Type:"Font",BaseFont:t,Encoding:"WinAnsiEncoding",Subtype:"Type1"}),getJpgImage=(e,t)=>{if(65496!==t.readUInt16BE(0))throw"SOI not found in JPEG";let n=2,a;for(;n<t.length&&(a=t.readUInt16BE(n),n+=2,!MARKERS.includes(a));)n+=t.readUInt16BE(n);if(!MARKERS.includes(a))throw"Invalid JPEG.";n+=2;var r=t[n++],o=t.readUInt16BE(n),i=(n+=2,t.readUInt16BE(n)),l=(n+=2,t[n++]),l=COLOR_SPACE_MAP[l],r={Type:"XObject",Subtype:"Image",BitsPerComponent:r,Width:i,Height:o,ColorSpace:l,Filter:"DCTDecode"},i=("DeviceCMYK"===l&&(r.Decode=[1,0,1,0,1,0,1,0]),e.ref(r,null,t));return i},getPngImage=(e,t)=>{var t=new PNG(t),n=t.hasAlphaChannel,a={Type:"XObject",Subtype:"Image",BitsPerComponent:n?8:t.bits,Width:t.width,Height:t.height,Filter:"FlateDecode"};if(n||(r=e.ref({Predictor:15,Colors:t.colors,BitsPerComponent:t.bits,Columns:t.width}),a.DecodeParms=r),0===t.palette.length?a.ColorSpace=t.colorSpace:(r=e.ref({stream:new Buffer(t.palette)}),a.ColorSpace=["Indexed","DeviceRGB",t.palette.length/3-1,r]),null!=t.transparency.grayscale){var r=t.transparency.grayscale;a.Mask=[r,r]}else if(t.transparency.rgb){var o,r=t.transparency["rgb"],i=[];for(o of r)i.push(o,o);a.Mask=i}else t.transparency.indexed?loadIndexedAlphaChannel(t):n&&(splitAlphaChannel(t),r=getSmask(e,t),a.Mask=r);return e.ref(a,null,t.imgData)},loadIndexedAlphaChannel=e=>{const o=e.transparency.indexed;return e.decodePixels(n=>{var a=new Buffer(e.width*e.height);let r=0;for(let e=0,t=n.length;e<t;e++)a[r++]=o[n[e]];e.alphaChannel=zlib.deflateSync(a)})},splitAlphaChannel=d=>{d.decodePixels(t=>{let e,n;var a=d.colors,r=d.width*d.height,o=new Buffer(r*a),i=new Buffer(r);let l=n=e=0;for(var c=t.length,g=16===d.bits?1:0;l<c;){for(let e=0;e<a;e++)o[n++]=t[l++],l+=g;i[e++]=t[l++],l+=g}d.imgData=zlib.deflateSync(o),d.alphaChannel=zlib.deflateSync(i)})},getSmask=(e,t)=>{let n;return console.log("image.hasAlphaChannel ",t.hasAlphaChannel),t.hasAlphaChannel&&(console.log("image.alphaChannel ",t.alphaChannel),n=e.ref({Type:"XObject",Subtype:"Image",Height:t.height,Width:t.width,BitsPerComponent:8,Filter:"FlateDecode",ColorSpace:"DeviceGray",Decode:[0,1],stream:t.alphaChannel})),n},getConvertedText=e=>e.split("").map(e=>specialCharacters.includes(e)?getOctalCodeFromCharacter(e):e).join(""),getOctalCodeFromCharacter=e=>"\\"+e.charCodeAt(0).toString(8),pdfkitAddPlaceholder=({pdf:e,pdfBuffer:a,reason:r,contactInfo:t="emailfromp1289@gmail.com",name:n="Name from p12",location:o="Location from p12",signatureLength:i=DEFAULT_SIGNATURE_LENGTH,byteRangePlaceholder:l=DEFAULT_BYTE_RANGE_PLACEHOLDER,subFilter:c=SUBFILTER_ADOBE_PKCS7_DETACHED,sign:g})=>{var d=getFont(e,"Helvetica"),s=getFont(e,"ZapfDingbats"),p=getFont(e,"Helvetica"),f=g.Base64,f=getAnnotationApparance(e,getImage(Buffer.from(f,"base64"),e),p,g),p=e.ref({Type:"Sig",Filter:"Adobe.PPKLite",SubFilter:c,ByteRange:[0,l,l,l],Contents:Buffer.from(String.fromCharCode(0).repeat(i)),Reason:new String(r),M:new Date,ContactInfo:new String(t),Name:new String(n),Location:new String(o)}),h=a.lastIndexOf("/Type /AcroForm"),c=-1!==h;let m=[],C;if(c){let e=h;var S=h-10;let t="",n=11;for(n;n<22;n+=1){var A=a.slice(h-n,S).toString();if("\n"===A[0])break;t=A,e=h-n}l=a.slice(e),i=l.slice(0,l.indexOf("endobj")).toString(),r=(C=parseInt(t),i.slice(i.indexOf("/Fields [")+9,i.indexOf("]")));m=r.split(" ").filter((e,t)=>t%3==0).map(e=>new PDFKitReferenceMock(e))}t=g.Left,n=g.Bottom,o=t+g.Width,l=n+g.Height,i=e.ref({Type:"Annot",Subtype:"Widget",FT:"Sig",Rect:[t,n,o,l],V:p,T:new String("Signature"+(m.length+1)),F:4,P:e.page.dictionary,AP:`<</N ${f.index} 0 R>>`,DA:new String("/Helvetica 0 Tf 0 g")});e.page.dictionary.data.Annots=[i];let T;return T=c?e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i],DR:`<</Font
|
||||
<</Helvetica ${d.index} 0 R/ZapfDingbats ${s.index} 0 R>>
|
||||
>>`},C):e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i]}),{signature:p,form:e._root.data.AcroForm=T,widget:i}};export default pdfkitAddPlaceholder;
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
import {
|
||||
DEFAULT_BYTE_RANGE_PLACEHOLDER,
|
||||
DEFAULT_SIGNATURE_LENGTH,
|
||||
SUBFILTER_ADOBE_PKCS7_DETACHED,
|
||||
} from './const.min.js';
|
||||
import { SignPdfError } from './SignPdfError.min.js';
|
||||
import {
|
||||
PDFArray,
|
||||
PDFDict,
|
||||
PDFHexString,
|
||||
PDFName,
|
||||
PDFNumber,
|
||||
PDFInvalidObject,
|
||||
PDFString,
|
||||
} from 'pdf-lib';
|
||||
const pdflibAddPlaceholder = ({
|
||||
pdfDoc: e = void 0,
|
||||
pdfPage: o = void 0,
|
||||
reason: t,
|
||||
contactInfo: r = 'emailfromp1289@gmail.com',
|
||||
name: i = 'Name from p12',
|
||||
location: n,
|
||||
signingTime: a = void 0,
|
||||
signatureLength: P = DEFAULT_SIGNATURE_LENGTH,
|
||||
byteRangePlaceholder: F = DEFAULT_BYTE_RANGE_PLACEHOLDER,
|
||||
subFilter: D = SUBFILTER_ADOBE_PKCS7_DETACHED,
|
||||
widgetRect: f = [0, 0, 0, 0],
|
||||
appName: g = void 0,
|
||||
}) => {
|
||||
if (void 0 === e && void 0 === o)
|
||||
throw new SignPdfError('PDFDoc or PDFPage must be set.', SignPdfError.TYPE_INPUT);
|
||||
var e = e ?? o.doc,
|
||||
o = o ?? e.getPages()[0],
|
||||
m = PDFArray.withContext(e.context),
|
||||
F =
|
||||
(m.push(PDFNumber.of(0)),
|
||||
m.push(PDFName.of(F)),
|
||||
m.push(PDFName.of(F)),
|
||||
m.push(PDFName.of(F)),
|
||||
PDFHexString.of(String.fromCharCode(0).repeat(P))),
|
||||
P = g ? { App: { Name: g } } : {},
|
||||
g = e.context.obj({
|
||||
Type: 'Sig',
|
||||
Filter: 'Adobe.PPKLite',
|
||||
SubFilter: D,
|
||||
ByteRange: m,
|
||||
Contents: F,
|
||||
Reason: PDFString.of(t),
|
||||
M: PDFString.fromDate(a ?? new Date()),
|
||||
ContactInfo: PDFString.of(r),
|
||||
Name: PDFString.of(i),
|
||||
Location: PDFString.of(n),
|
||||
Prop_Build: { Filter: { Name: 'Adobe.PPKLite' }, ...P },
|
||||
}),
|
||||
D = new Uint8Array(g.sizeInBytes()),
|
||||
m = (g.copyBytesInto(D, 0), PDFInvalidObject.of(D)),
|
||||
F = e.context.register(m);
|
||||
const s = PDFArray.withContext(e.context);
|
||||
f.forEach(e => s.push(PDFNumber.of(e)));
|
||||
(t = e.context.formXObject([], { BBox: f, Resources: {} })),
|
||||
(a = e.context.obj({
|
||||
Type: 'Annot',
|
||||
Subtype: 'Widget',
|
||||
FT: 'Sig',
|
||||
Rect: s,
|
||||
V: F,
|
||||
T: PDFString.of('Signature1'),
|
||||
F: 4,
|
||||
P: o.ref,
|
||||
AP: { N: e.context.register(t) },
|
||||
})),
|
||||
(r = e.context.register(a));
|
||||
let c = o.node.lookupMaybe(PDFName.of('Annots'), PDFArray),
|
||||
d =
|
||||
((c = void 0 === c ? e.context.obj([]) : c).push(r),
|
||||
o.node.set(PDFName.of('Annots'), c),
|
||||
e.catalog.lookupMaybe(PDFName.of('AcroForm'), PDFDict));
|
||||
void 0 === d &&
|
||||
((d = e.context.obj({ Fields: [] })),
|
||||
(i = e.context.register(d)),
|
||||
e.catalog.set(PDFName.of('AcroForm'), i));
|
||||
let N;
|
||||
N = d.has(PDFName.of('SigFlags')) ? d.get(PDFName.of('SigFlags')) : PDFNumber.of(0);
|
||||
n = PDFNumber.of(3 | N.asNumber());
|
||||
d.set(PDFName.of('SigFlags'), n), d.get(PDFName.of('Fields')).push(r);
|
||||
};
|
||||
export { pdflibAddPlaceholder };
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
import PDFObject from"./pdfObject.min.js";import PDFKitReferenceMock from"./PDFKitReferenceMock.min.js";import removeTrailingNewLine from"./removeTrailingNewLine.min.js";import{DEFAULT_SIGNATURE_LENGTH,SUBFILTER_ADOBE_PKCS7_DETACHED}from"./const.min.js";import pdfkitAddPlaceholder from"./pdfkitAddPlaceholder.min.js";import getIndexFromRef from"./getIndexFromRef.min.js";import readPdf from"./readPdf.min.js";import getPageRef from"./getPageRef.min.js";import createBufferRootWithAcroform from"./createBufferRootWithAcroform.min.js";import createBufferPageWithAnnotation from"./createBufferPageWithAnnotation.min.js";import createBufferTrailer from"./createBufferTrailer.min.js";const isContainBufferRootWithAcroform=e=>{e=/\/AcroForm\s+(\d+\s\d+\sR)/g.exec(e.toString());return null!=e&&null!=e[1]&&""!==e[1]},getAssembledPdf=(e,r,f,o)=>{let t=e;return t=Buffer.concat([t,Buffer.from("\n"),Buffer.from(r+` 0 obj
|
||||
`),Buffer.from(PDFObject.convert(f))]),o&&(t=Buffer.concat([t,Buffer.from("\nstream\n"),Buffer.from(o),Buffer.from("\nendstream")])),t=Buffer.concat([t,Buffer.from("\nendobj\n")])},plainAddPlaceholder=({pdfBuffer:e,reason:r,contactInfo:f="emailfromp1289@gmail.com",name:o="Name from p12",location:t="Location from p12",signatureLength:n=DEFAULT_SIGNATURE_LENGTH,subFilter:i=SUBFILTER_ADOBE_PKCS7_DETACHED,sign:m})=>{let a=removeTrailingNewLine(e);const c=readPdf(a);var d=getPageRef(a,c,m.Page),u=getIndexFromRef(c.xref,d);const l=new Map;var s={ref:(e,r,f)=>{c.xref.maxIndex+=1;r=null!=r?r:c.xref.maxIndex;return l.set(r,a.length+1),a=getAssembledPdf(a,r,e,f),new PDFKitReferenceMock(c.xref.maxIndex)},page:{dictionary:new PDFKitReferenceMock(u,{data:{Annots:[]}})},_root:{data:{}}},{form:s,widget:e}=pdfkitAddPlaceholder({pdf:s,pdfBuffer:e,reason:r,contactInfo:f,name:o,location:t,signatureLength:n,subFilter:i,sign:m});return isContainBufferRootWithAcroform(a)||(r=getIndexFromRef(c.xref,c.rootRef),l.set(r,a.length+1),a=Buffer.concat([a,Buffer.from("\n"),createBufferRootWithAcroform(a,c,s)])),l.set(u,a.length+1),a=Buffer.concat([a,Buffer.from("\n"),createBufferPageWithAnnotation(a,c,d,e)]),a=Buffer.concat([a,Buffer.from("\n"),createBufferTrailer(a,c,l)])};export default plainAddPlaceholder;
|
||||
@@ -1 +0,0 @@
|
||||
import readRefTable from"./readRefTable.min.js";import findObject from"./findObject.min.js";const getValue=(e,t)=>{let r=e.indexOf(t);if(-1!==r)return e=e.slice(r),-1===(r=e.indexOf("/",1))&&(r=e.indexOf(">",1)),e.slice(t.length+1,r).toString().trim()},readPdf=e=>{var t=e.lastIndexOf("trailer"),r=e.slice(t,e.length-6),f=r.slice(r.lastIndexOf("startxref")+10).toString(),f=parseInt(f),i=readRefTable(e),n=getValue(r,"/Root");return{xref:i,rootRef:n,root:findObject(e,i,n).toString(),infoRef:getValue(r,"/Info"),trailerStart:t,previousXrefs:[],xRefPosition:f}};export default readPdf;
|
||||
@@ -1 +0,0 @@
|
||||
import SignPdfError from"./SignPdfError.min.js";import xrefToRefMap from"./xrefToRefMap.min.js";const getLastTrailerPosition=e=>{var r=e.lastIndexOf(Buffer.from("trailer","utf8")),r=e.slice(r,e.length-6),e=r.slice(r.lastIndexOf(Buffer.from("startxref","utf8"))+10).toString();return parseInt(e)},getXref=(e,r)=>{let t=e.slice(r);e=t.indexOf(Buffer.from("xref","utf8"));if(-1===e)throw new SignPdfError(`Could not find xref anywhere at or after ${r}.`,SignPdfError.TYPE_PARSE);if(0<e&&""!==t.slice(0,e).toString().replace(/\s*/g,""))throw new SignPdfError(`Expected xref at ${r} but found other content.`,SignPdfError.TYPE_PARSE);r=t.indexOf(Buffer.from("%%EOF","utf8"));if(-1===r)throw new SignPdfError("Expected EOF after xref and trailer but could not find one.",SignPdfError.TYPE_PARSE);if(!(r=(t=(t=(t=t.slice(0,r)).slice(e+4)).slice(t.indexOf("\n")+1)).toString().split("/Size")[1]))throw new SignPdfError("Size not found in xref table.",SignPdfError.TYPE_PARSE);if(null===(r=/^\s*(\d+)/.exec(r)))throw new SignPdfError("Failed to parse size of xref table.",SignPdfError.TYPE_PARSE);var r=parseInt(r[1]),[e,f]=t.toString().split("trailer");let n;null!=f.split("/Prev")[1]&&([,f]=/Prev (\d+)/g.exec(f),n=f);f=xrefToRefMap(e);return{size:r,prev:n,xRefContent:f}},getFullXrefTable=e=>{var r=getLastTrailerPosition(e),t=getXref(e,r);return void 0===t.prev?t.xRefContent:(e=e.slice(0,r),r=getFullXrefTable(e),new Map([...r,...t.xRefContent]))},readRefTable=e=>{e=getFullXrefTable(e);return{startingIndex:0,maxIndex:Math.max(...e.keys()),offsets:e}};export default readRefTable;export{getLastTrailerPosition,getXref,getFullXrefTable};
|
||||
-1
@@ -1 +0,0 @@
|
||||
import SignPdfError from"./SignPdfError.min.js";const sliceLastChar=(r,e)=>{return r.slice(r.length-1).toString()===e?r.slice(0,r.length-1):r},removeTrailingNewLine=r=>{if(!(r instanceof Buffer))throw new SignPdfError("PDF expected as Buffer.",SignPdfError.TYPE_INPUT);r=sliceLastChar(r,"\n");if("\n%%EOF"!==(r=sliceLastChar(r,"\r")).slice(r.length-6).toString())throw new SignPdfError("A PDF file must end with an EOF line.",SignPdfError.TYPE_PARSE);return r};export default removeTrailingNewLine;
|
||||
@@ -1 +0,0 @@
|
||||
import SignPdfError from"./SignPdfError.min.js";const xrefToRefMap=r=>{r=r.split("\n").filter(r=>""!==r);let n=0,t=0;const f=new Map;return r.forEach(r=>{r=r.split(" ");if(2===r.length)n=parseInt(r[0]),t=parseInt(r[1]);else{if(t<=0)throw new SignPdfError("Too many lines in xref table.",SignPdfError.TYPE_PARSE);--t;var[r,,e]=r;if("f"!==e.trim()){if("n"!==e.trim())throw new SignPdfError(`Unknown in-use flag "${e}". Expected "n" or "f".`,SignPdfError.TYPE_PARSE);if(!/^\d+$/.test(r.trim()))throw new SignPdfError(`Expected integer offset. Got "${r}".`,SignPdfError.TYPE_PARSE);e=parseInt(r.trim());f.set(n,e)}n+=1}}),f};export default xrefToRefMap;
|
||||
@@ -10,7 +10,7 @@ import formData from 'form-data';
|
||||
import Mailgun from 'mailgun.js';
|
||||
import { ApiPayloadConverter } from 'parse-server-api-mail-adapter';
|
||||
import S3Adapter from '@parse/s3-files-adapter';
|
||||
import FSFilesAdapter from 'parse-server-fs-adapter';
|
||||
import FSFilesAdapter from '@parse/fs-files-adapter';
|
||||
import AWS from 'aws-sdk';
|
||||
import { app as customRoute } from './cloud/customRoute/customApp.js';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
Generated
+802
-505
File diff suppressed because it is too large
Load Diff
@@ -18,9 +18,13 @@
|
||||
"watch": "nodemon index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@parse/fs-files-adapter": "^3.0.0",
|
||||
"@parse/s3-files-adapter": "^2.2.0",
|
||||
"@signpdf/placeholder-pdf-lib": "^3.2.4",
|
||||
"@signpdf/signer-p12": "^3.2.4",
|
||||
"@signpdf/signpdf": "^3.2.4",
|
||||
"aws-sdk": "^2.1581.0",
|
||||
"axios": "^1.6.8",
|
||||
"axios": "^1.7.1",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
@@ -30,18 +34,16 @@
|
||||
"googleapis": "^134.0.0",
|
||||
"jsonschema": "^1.4.1",
|
||||
"mailgun.js": "^10.2.1",
|
||||
"mongoose": "^8.3.3",
|
||||
"mongoose": "^8.4.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"multer-s3": "^3.0.1",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-signpdf": "^1.5.1",
|
||||
"nodemailer": "^6.9.13",
|
||||
"parse": "^5.0.0",
|
||||
"parse": "^5.1.0",
|
||||
"parse-dbtool": "^1.2.0",
|
||||
"parse-server": "^6.5.5",
|
||||
"parse-server": "^7.0.0",
|
||||
"parse-server-api-mail-adapter": "^3.1.1",
|
||||
"parse-server-fs-adapter": "^1.0.1",
|
||||
"parse-server-s3-adapter": "^1.2.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"pdfkit": "^0.14.0",
|
||||
"posthog-node": "^3.6.3"
|
||||
@@ -51,7 +53,7 @@
|
||||
"@babel/eslint-parser": "^7.24.5",
|
||||
"eslint": "^8.57.0",
|
||||
"jasmine": "^5.1.0",
|
||||
"mongodb-runner": "^5.5.4",
|
||||
"mongodb-runner": "^5.6.2",
|
||||
"nodemon": "^3.1.0",
|
||||
"nyc": "15.1.0",
|
||||
"prettier": "^3.2.5",
|
||||
|
||||
Reference in New Issue
Block a user