mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
feat: add disable OTP feature to directly sign document without verification
This commit is contained in:
@@ -638,6 +638,14 @@
|
||||
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminEmail}}.",
|
||||
"sent-this-month":"Sent this month",
|
||||
"available-seats":"Available seats",
|
||||
"buy-users":"Buy more users"
|
||||
|
||||
"buy-users":"Buy more users",
|
||||
"isdisable-otp": "Enable OTP verification",
|
||||
"isdisable-otp-help": {
|
||||
"p1": "Would you like to enable the verification process using a one-time password (OTP)?",
|
||||
"p2": "Selecting this option will enable OTP verification. Users will receive a verification code via email, which they must enter to sign the document.",
|
||||
"p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.",
|
||||
"p4": "Please choose the option that best suits your document signing requirements."
|
||||
},
|
||||
"advanced-options":"Advanced options",
|
||||
"hide-advanced-options":"Hide Advanced options"
|
||||
}
|
||||
|
||||
@@ -637,5 +637,15 @@
|
||||
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
|
||||
"sent-this-month":"envoyé ce mois-ci",
|
||||
"available-seats":"Disponible sièges",
|
||||
"buy-users":"Acheter plus d'utilisateurs"
|
||||
"buy-users":"Acheter plus d'utilisateurs",
|
||||
"isdisable-otp": "Activer la vérification OTP",
|
||||
"isdisable-otp-help": {
|
||||
"p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?",
|
||||
"p2": "La sélection de cette option activera la vérification OTP. Les utilisateurs recevront un code de vérification par e-mail, qu'ils devront saisir pour signer le document.",
|
||||
"p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.",
|
||||
"p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents."
|
||||
},
|
||||
"advanced-options":"Options avancées",
|
||||
"hide-advanced-options": "Masquer les options avancées"
|
||||
|
||||
}
|
||||
|
||||
@@ -154,7 +154,9 @@ function EmailComponent({
|
||||
<div className="flex flex-row">
|
||||
{!isAndroid && (
|
||||
<button
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||
}
|
||||
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
|
||||
>
|
||||
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||
|
||||
@@ -142,7 +142,7 @@ function Header({
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, pdfUrl, setIsDownloading)
|
||||
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
@@ -342,7 +342,9 @@ function Header({
|
||||
alreadySign ? (
|
||||
<div className="flex flex-row">
|
||||
<button
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||
}
|
||||
type="button"
|
||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||
>
|
||||
@@ -459,7 +461,9 @@ function Header({
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||
}
|
||||
type="button"
|
||||
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||
>
|
||||
|
||||
@@ -1741,9 +1741,7 @@ export const contactBook = async (objectId) => {
|
||||
|
||||
//function for getting document details from contract_Documents class
|
||||
export const contractDocument = async (documentId) => {
|
||||
const data = {
|
||||
docId: documentId
|
||||
};
|
||||
const data = { docId: documentId };
|
||||
const documentDeatils = await axios
|
||||
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
||||
headers: {
|
||||
@@ -2047,11 +2045,12 @@ export const handleDownloadPdf = async (
|
||||
) => {
|
||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
||||
setIsDownloading("pdf");
|
||||
const docId = pdfDetails?.[0]?.IsDisableOTP ? pdfDetails?.[0]?.objectId : "";
|
||||
try {
|
||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||
const axiosRes = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||
{ url: pdfUrl },
|
||||
{ url: pdfUrl, docId: docId },
|
||||
{
|
||||
headers: {
|
||||
"content-type": "Application/json",
|
||||
@@ -2075,16 +2074,24 @@ export const sanitizeFileName = (pdfName) => {
|
||||
return pdfName.replace(/ /g, "_");
|
||||
};
|
||||
//function for print digital sign pdf
|
||||
export const handleToPrint = async (event, pdfUrl, setIsDownloading) => {
|
||||
export const handleToPrint = async (
|
||||
event,
|
||||
pdfUrl,
|
||||
setIsDownloading,
|
||||
pdfDetails
|
||||
) => {
|
||||
event.preventDefault();
|
||||
setIsDownloading("pdf");
|
||||
try {
|
||||
const docId = pdfDetails?.[0]?.IsDisableOTP
|
||||
? pdfDetails?.[0]?.objectId
|
||||
: "";
|
||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
|
||||
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
|
||||
const axiosRes = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||
{ url: pdfUrl },
|
||||
{ url: pdfUrl, docId: docId },
|
||||
{
|
||||
headers: {
|
||||
"content-type": "Application/json",
|
||||
|
||||
+207
-107
@@ -61,7 +61,8 @@ const Forms = (props) => {
|
||||
password: "",
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false
|
||||
autoreminder: false,
|
||||
IsDisableOTP: "false"
|
||||
});
|
||||
const [fileupload, setFileUpload] = useState("");
|
||||
const [fileload, setfileload] = useState(false);
|
||||
@@ -74,6 +75,7 @@ const Forms = (props) => {
|
||||
const [isDecrypting, setIsDecrypting] = useState(false);
|
||||
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isAdvanceOpt, setIsAdvanceOpt] = useState(false);
|
||||
const handleStrInput = (e) => {
|
||||
setIsCorrectPass(true);
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
@@ -137,7 +139,6 @@ const Forms = (props) => {
|
||||
} catch (err) {
|
||||
console.log("err in sending posthog encryptedpdf", err);
|
||||
}
|
||||
// console.log("err ", err);
|
||||
try {
|
||||
setIsDecrypting(true);
|
||||
const size = files?.[0].size;
|
||||
@@ -402,6 +403,13 @@ const Forms = (props) => {
|
||||
object.set("SendinOrder", isChecked);
|
||||
object.set("AutomaticReminders", formData.autoreminder);
|
||||
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
|
||||
if (isEnableSubscription) {
|
||||
const IsDisableOTP =
|
||||
formData.IsDisableOTP === "false" ? true : false;
|
||||
object.set("IsDisableOTP", IsDisableOTP);
|
||||
} else {
|
||||
object.set("IsDisableOTP", true);
|
||||
}
|
||||
}
|
||||
object.set("URL", fileupload);
|
||||
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
||||
@@ -428,7 +436,17 @@ const Forms = (props) => {
|
||||
setFormData({
|
||||
Name: "",
|
||||
Description: "",
|
||||
Note: ""
|
||||
Note:
|
||||
props.title === "Sign Yourself"
|
||||
? "Note to myself"
|
||||
: "Please review and sign this document",
|
||||
TimeToCompleteDays: 15,
|
||||
SendinOrder: "true",
|
||||
password: "",
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false,
|
||||
IsDisableOTP: "false"
|
||||
});
|
||||
setFileUpload("");
|
||||
setpercentage(0);
|
||||
@@ -477,7 +495,8 @@ const Forms = (props) => {
|
||||
password: "",
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false
|
||||
autoreminder: false,
|
||||
IsDisableOTP: "false"
|
||||
});
|
||||
setFileUpload("");
|
||||
setpercentage(0);
|
||||
@@ -754,120 +773,73 @@ const Forms = (props) => {
|
||||
isReset={isReset}
|
||||
/>
|
||||
)}
|
||||
{props.title === "Request Signatures" && (
|
||||
{props.title !== "Sign Yourself" && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
{t("time-to-complete")}
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
{t("send-in-order")}
|
||||
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
|
||||
<sup>
|
||||
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="sendInOrder-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("send-in-order")}</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">{t("yes")}: </span>
|
||||
<span>{t("send-in-order-help.p2")}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">{t("no")}: </span>
|
||||
<span>{t("send-in-order-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
name="TimeToCompleteDays"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formData.TimeToCompleteDays}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
className="op-radio op-radio-xs"
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">{t("yes")}</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
className="op-radio op-radio-xs"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">{t("no")}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{props.title !== "Sign Yourself" && (
|
||||
<>
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
{t("send-in-order")}
|
||||
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
|
||||
<sup>
|
||||
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="sendInOrder-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("send-in-order")}</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">{t("yes")}:</span>
|
||||
<span>{t("send-in-order-help.p2")}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">{t("no")}: </span>
|
||||
<span>{t("send-in-order-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
className="op-radio op-radio-xs"
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">{t("yes")}</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
className="op-radio op-radio-xs"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">{t("no")}</div>
|
||||
</div>
|
||||
</div>
|
||||
{isEnableSubscription && (
|
||||
<div className="text-xs mt-2">
|
||||
<span
|
||||
className={
|
||||
isSubscribe
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
{t("auto-reminder")}
|
||||
{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={formData.autoreminder}
|
||||
onChange={handleAutoReminder}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{formData?.autoreminder === true && (
|
||||
{isAdvanceOpt && (
|
||||
<div className={` overflow-y-auto z-[500] transition-all`}>
|
||||
{props.title === "Request Signatures" && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
{t("remind-once")}
|
||||
{t("time-to-complete")}
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.remindOnceInEvery}
|
||||
name="remindOnceInEvery"
|
||||
name="TimeToCompleteDays"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
onChange={handleStrInput}
|
||||
value={formData.TimeToCompleteDays}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
@@ -876,8 +848,136 @@ const Forms = (props) => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
{props.title !== "Sign Yourself" && (
|
||||
<>
|
||||
{isEnableSubscription && (
|
||||
<div className="text-xs mt-2">
|
||||
<span className={isSubscribe ? "" : " text-gray-300"}>
|
||||
{t("auto-reminder")}{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0 mt-1.5`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={formData.autoreminder}
|
||||
onChange={handleAutoReminder}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{formData?.autoreminder === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
{t("remind-once")}
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.remindOnceInEvery}
|
||||
name="remindOnceInEvery"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
onChange={handleStrInput}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{isEnableSubscription && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
<span className={isSubscribe ? "" : " text-gray-300"}>
|
||||
{t("isdisable-otp")}{" "}
|
||||
<a
|
||||
data-tooltip-id="isdisableotp-tooltip"
|
||||
className="ml-1"
|
||||
>
|
||||
<sup>
|
||||
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||
</sup>
|
||||
</a>{" "}
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<Upgrade />
|
||||
)}
|
||||
</span>
|
||||
<Tooltip id="isdisableotp-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("isdisable-otp")}</p>
|
||||
<p>{t("isdisable-otp-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
{t("yes")}:{" "}
|
||||
</span>
|
||||
<span>{t("isdisable-otp-help.p2")}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
{t("no")}:{" "}
|
||||
</span>
|
||||
<span>{t("isdisable-otp-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>{t("isdisable-otp-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
<div
|
||||
className={`${
|
||||
isSubscribe ? "" : "pointer-events-none opacity-50"
|
||||
} flex items-center gap-2 ml-2 mb-1 `}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
className="op-radio op-radio-xs"
|
||||
name="IsDisableOTP"
|
||||
checked={formData.IsDisableOTP === "true"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">{t("yes")}</div>
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
isSubscribe ? "" : "pointer-events-none opacity-50"
|
||||
} flex items-center gap-2 ml-2 mb-1 `}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="IsDisableOTP"
|
||||
className="op-radio op-radio-xs"
|
||||
checked={formData.IsDisableOTP === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">{t("no")}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
onClick={() => setIsAdvanceOpt(!isAdvanceOpt)}
|
||||
className={`mt-2.5 op-link op-link-primary text-sm`}
|
||||
>
|
||||
{isAdvanceOpt
|
||||
? t("hide-advanced-options")
|
||||
: t("advanced-options")}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center mt-3 gap-2">
|
||||
<button
|
||||
className={`${
|
||||
|
||||
@@ -28,6 +28,28 @@ function GuestLogin() {
|
||||
const [contactId, setContactId] = useState(contactBookId);
|
||||
const [sendmail, setSendmail] = useState();
|
||||
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||
const navigateToDoc = async (docId, contactId) => {
|
||||
try {
|
||||
const docDetails = await Parse.Cloud.run("getDocument", {
|
||||
docId: docId
|
||||
});
|
||||
if (!docDetails.error) {
|
||||
if (sendmail === "false") {
|
||||
navigate(
|
||||
`/load/recipientSignPdf/${docId}/${contactId}?sendmail=${sendmail}`
|
||||
);
|
||||
} else {
|
||||
navigate(`/load/recipientSignPdf/${docId}/${contactId}`);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err while getting doc", err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
handleServerUrl();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -70,13 +92,14 @@ function GuestLogin() {
|
||||
"linkcontacttodoc",
|
||||
params
|
||||
);
|
||||
// console.log("linkContactRes ", linkContactRes);
|
||||
setContactId(linkContactRes?.contactId);
|
||||
await navigateToDoc(checkSplit[0], linkContactRes?.contactId);
|
||||
} catch (err) {
|
||||
console.log("Err in link ext contact", err);
|
||||
}
|
||||
} else {
|
||||
setContactId(checkSplit[2]);
|
||||
await navigateToDoc(checkSplit[0], checkSplit[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,15 +137,12 @@ function GuestLogin() {
|
||||
if (OTP) {
|
||||
setLoading(true);
|
||||
try {
|
||||
let url = `${serverUrl}functions/AuthLoginAsMail/`;
|
||||
let url = `${serverUrl}functions/AuthLoginAsMail`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email,
|
||||
otp: OTP
|
||||
};
|
||||
let body = { email: email, otp: OTP };
|
||||
let user = await axios.post(url, body, { headers: headers });
|
||||
if (user.data.result === "Invalid Otp") {
|
||||
alert(t("invalid-otp"));
|
||||
@@ -140,7 +160,6 @@ function GuestLogin() {
|
||||
`Parse/${parseId}/currentUser`,
|
||||
JSON.stringify(_user)
|
||||
);
|
||||
// console.log("contractUserDetails ", contractUserDetails);
|
||||
if (contractUserDetails && contractUserDetails.length > 0) {
|
||||
localStorage.setItem(
|
||||
"Extand_Class",
|
||||
@@ -174,10 +193,15 @@ function GuestLogin() {
|
||||
try {
|
||||
setLoading(true);
|
||||
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
|
||||
// console.log("linkContactRes ", linkContactRes);
|
||||
setContactId(linkContactRes.contactId);
|
||||
setEnterOtp(true);
|
||||
await SendOtp();
|
||||
const isDisableOTP = await navigateToDoc(
|
||||
documentId,
|
||||
linkContactRes.contactId
|
||||
);
|
||||
if (!isDisableOTP) {
|
||||
setEnterOtp(true);
|
||||
await SendOtp();
|
||||
}
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
alert(t("something-went-wrong-mssg"));
|
||||
@@ -208,7 +232,7 @@ function GuestLogin() {
|
||||
<div className="w-full md:w-[50%] text-base-content">
|
||||
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
|
||||
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
|
||||
{t("guest-email-alert")}
|
||||
{t("get-otp-alert")}
|
||||
</legend>
|
||||
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
|
||||
<input
|
||||
@@ -236,7 +260,7 @@ function GuestLogin() {
|
||||
>
|
||||
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
|
||||
<legend className="text-[12px] text-[#878787] mt-2">
|
||||
{t("get-verification-code-2")}
|
||||
{t("guest-email-alert")}
|
||||
</legend>
|
||||
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
|
||||
<p className="text-sm">{t("enter-verification-code")}</p>
|
||||
|
||||
@@ -142,23 +142,23 @@ function PdfRequestFiles(props) {
|
||||
let isGuestSignFlow = false;
|
||||
let sendmail;
|
||||
let getDocId = "";
|
||||
const route = !props.templateId && window.location.pathname; //'/load/recipientSignPdf/TOAVuhXbfw/fPAKdK1qgX'
|
||||
//window.location.search = ?sendmail=false
|
||||
const getQuery =
|
||||
!props.templateId &&
|
||||
window.location?.search &&
|
||||
window.location?.search?.split("?"); //['','sendmail=false']
|
||||
|
||||
//'sendmail=false'
|
||||
let contactBookId = "";
|
||||
const route = !props.templateId && window.location.pathname;
|
||||
const getQuery = !props.templateId && window.location?.search?.split("?"); //['','sendmail=false']
|
||||
if (getQuery) {
|
||||
sendmail = getQuery[1].split("=")[1]; //false
|
||||
sendmail = getQuery?.[1]?.split("=")[1]; //false
|
||||
}
|
||||
const checkSplit = route && route?.split("/"); // ['', 'load', 'recipientSignPdf', 'TOAVuhXbfw', 'fPAKdK1qgX']
|
||||
if (checkSplit && checkSplit.length > 4) {
|
||||
|
||||
const routeId = route && route?.split("/"); // ['', 'load', 'recipientSignPdf', ':docId', ':contactBookId']
|
||||
if (routeId && routeId.length > 4) {
|
||||
// this condition will be occur only in guest flow in which load routeId will be include
|
||||
isGuestSignFlow = true;
|
||||
getDocId = checkSplit[3];
|
||||
getDocId = routeId[3];
|
||||
contactBookId = routeId[4];
|
||||
} else {
|
||||
getDocId = checkSplit[2];
|
||||
// this condition will be occur only in if user is logged in and load routeId will be exclude
|
||||
getDocId = routeId[2];
|
||||
contactBookId = routeId?.[3] || "";
|
||||
}
|
||||
let getDocumentId = getDocId || documentId;
|
||||
useEffect(() => {
|
||||
@@ -372,6 +372,7 @@ function PdfRequestFiles(props) {
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
);
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
// `currUserId` will be contactId or extUserId
|
||||
let currUserId;
|
||||
//getting document details
|
||||
const documentData = await contractDocument(documentId || docId);
|
||||
@@ -399,13 +400,13 @@ function PdfRequestFiles(props) {
|
||||
const expireUpdateDate = new Date(expireDate).getTime();
|
||||
const currDate = new Date().getTime();
|
||||
const getSigners = documentData[0].Signers;
|
||||
const getCurrentSigner =
|
||||
getSigners &&
|
||||
getSigners.filter(
|
||||
(data) => data.UserId.objectId === jsonSender?.objectId
|
||||
);
|
||||
const getCurrentSigner = getSigners?.find(
|
||||
(data) => data.UserId.objectId === jsonSender?.objectId
|
||||
);
|
||||
|
||||
currUserId = getCurrentSigner[0] ? getCurrentSigner[0].objectId : "";
|
||||
currUserId = getCurrentSigner?.objectId
|
||||
? getCurrentSigner.objectId
|
||||
: contactBookId || "";
|
||||
if (isEnableSubscription) {
|
||||
await checkIsSubscribed(
|
||||
documentData[0]?.ExtUserPtr?.objectId,
|
||||
@@ -428,10 +429,7 @@ function PdfRequestFiles(props) {
|
||||
setIsCelebration(true);
|
||||
setTimeout(() => setIsCelebration(false), 5000);
|
||||
} else if (declined) {
|
||||
const currentDecline = {
|
||||
currnt: "another",
|
||||
isDeclined: true
|
||||
};
|
||||
const currentDecline = { currnt: "another", isDeclined: true };
|
||||
setIsDecline(currentDecline);
|
||||
} else if (currDate > expireUpdateDate) {
|
||||
const expireDateFormat = moment(new Date(expireDate)).format(
|
||||
@@ -457,36 +455,24 @@ function PdfRequestFiles(props) {
|
||||
}
|
||||
}
|
||||
}
|
||||
const audittrailData =
|
||||
documentData[0].AuditTrail &&
|
||||
documentData[0].AuditTrail.length > 0 &&
|
||||
documentData[0].AuditTrail.filter(
|
||||
(data) => data.Activity === "Signed"
|
||||
);
|
||||
|
||||
const audittrailData = documentData?.[0]?.AuditTrail?.filter(
|
||||
(data) => data.Activity === "Signed"
|
||||
);
|
||||
const checkAlreadySign =
|
||||
documentData[0].AuditTrail &&
|
||||
documentData[0].AuditTrail.length > 0 &&
|
||||
documentData[0].AuditTrail.filter(
|
||||
documentData?.[0]?.AuditTrail?.some(
|
||||
(data) =>
|
||||
data.UserPtr?.objectId === currUserId &&
|
||||
data?.UserPtr?.objectId === currUserId &&
|
||||
data.Activity === "Signed"
|
||||
);
|
||||
if (
|
||||
checkAlreadySign &&
|
||||
checkAlreadySign[0] &&
|
||||
checkAlreadySign.length > 0
|
||||
) {
|
||||
) || false;
|
||||
if (checkAlreadySign) {
|
||||
setAlreadySign(true);
|
||||
} else {
|
||||
const obj = documentData?.[0];
|
||||
setSendInOrder(obj?.SendinOrder || false);
|
||||
if (
|
||||
obj &&
|
||||
obj.Signers &&
|
||||
obj.Signers.length > 0 &&
|
||||
obj.Placeholders &&
|
||||
obj.Placeholders.length > 0
|
||||
obj?.Signers?.length > 0 &&
|
||||
obj?.Placeholders?.length > 0
|
||||
) {
|
||||
const params = {
|
||||
event: "viewed",
|
||||
@@ -502,7 +488,10 @@ function PdfRequestFiles(props) {
|
||||
email: x?.Email,
|
||||
phone: x?.Phone
|
||||
})),
|
||||
viewedBy: jsonSender.email,
|
||||
viewedBy:
|
||||
documentData?.[0].Signers?.find(
|
||||
(x) => x.objectId === currUserId
|
||||
)?.Email || jsonSender?.email,
|
||||
viewedAt: new Date(),
|
||||
createdAt: documentData?.[0].createdAt
|
||||
}
|
||||
@@ -583,40 +572,51 @@ function PdfRequestFiles(props) {
|
||||
//checking if condition current user already sign or owner does not exist as a signer or document has been declined by someone or document has been expired
|
||||
//then stop to display tour message
|
||||
if (
|
||||
(checkAlreadySign &&
|
||||
checkAlreadySign[0] &&
|
||||
checkAlreadySign.length > 0) ||
|
||||
checkAlreadySign ||
|
||||
!currUserId ||
|
||||
declined ||
|
||||
currDate > expireUpdateDate
|
||||
) {
|
||||
setRequestSignTour(true);
|
||||
} else {
|
||||
//else condition to check current user exist in contracts_Users class and check tour message status
|
||||
//if not then check user exist in contracts_Contactbook class and check tour message statu
|
||||
const res = await contractUsers();
|
||||
if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else if (res[0] && res?.length) {
|
||||
setContractName("_Users");
|
||||
currUserId = res[0].objectId;
|
||||
setSignerUserId(currUserId);
|
||||
const tourData = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourData && tourData.length > 0) {
|
||||
const checkTourRequest = tourData.filter(
|
||||
(data) => data?.requestSign
|
||||
const isDisableOTP = documentData?.[0]?.IsDisableOTP || false;
|
||||
if (isDisableOTP) {
|
||||
try {
|
||||
const resContact = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getcontact`,
|
||||
{
|
||||
contactId: currUserId
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||
}
|
||||
}
|
||||
);
|
||||
setTourStatus(tourData);
|
||||
setRequestSignTour(checkTourRequest[0]?.requestSign || false);
|
||||
const contact = resContact?.data?.result;
|
||||
setContractName("_Contactbook");
|
||||
setSignerUserId(contact?.objectId);
|
||||
const tourData = contact?.TourStatus && contact?.TourStatus;
|
||||
if (tourData && tourData.length > 0) {
|
||||
const checkTourRequest =
|
||||
tourData?.some((data) => data?.requestSign) || false;
|
||||
setTourStatus(tourData);
|
||||
setRequestSignTour(checkTourRequest);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err while getting tourstatus", err);
|
||||
}
|
||||
} else if (res?.length === 0) {
|
||||
const res = await contactBook(currUserId);
|
||||
} else {
|
||||
//else condition to check current user exist in contracts_Users class and check tour message status
|
||||
//if not then check user exist in contracts_Contactbook class and check tour message status
|
||||
const res = await contractUsers();
|
||||
if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else if (res[0] && res.length) {
|
||||
setContractName("_Contactbook");
|
||||
const objectId = res[0].objectId;
|
||||
setSignerUserId(objectId);
|
||||
} else if (res[0] && res?.length) {
|
||||
setContractName("_Users");
|
||||
currUserId = res[0].objectId;
|
||||
setSignerUserId(currUserId);
|
||||
const tourData = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourData && tourData.length > 0) {
|
||||
const checkTourRequest = tourData.filter(
|
||||
@@ -625,8 +625,25 @@ function PdfRequestFiles(props) {
|
||||
setTourStatus(tourData);
|
||||
setRequestSignTour(checkTourRequest[0]?.requestSign || false);
|
||||
}
|
||||
} else if (res.length === 0) {
|
||||
setHandleError(t("user-not-exist"));
|
||||
} else if (res?.length === 0) {
|
||||
const res = await contactBook(currUserId);
|
||||
if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else if (res[0] && res.length) {
|
||||
setContractName("_Contactbook");
|
||||
const objectId = res[0].objectId;
|
||||
setSignerUserId(objectId);
|
||||
const tourData = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourData && tourData.length > 0) {
|
||||
const checkTourRequest = tourData.filter(
|
||||
(data) => data?.requestSign
|
||||
);
|
||||
setTourStatus(tourData);
|
||||
setRequestSignTour(checkTourRequest[0]?.requestSign || false);
|
||||
}
|
||||
} else if (res.length === 0) {
|
||||
setHandleError(t("user-not-exist"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -643,12 +660,12 @@ function PdfRequestFiles(props) {
|
||||
setIsUiLoading({ isLoad: false });
|
||||
}
|
||||
//function to get default signatur eof current user from `contracts_Signature` class
|
||||
const defaultSignRes = await getDefaultSignature(jsonSender.objectId);
|
||||
const defaultSignRes = await getDefaultSignature(jsonSender?.objectId);
|
||||
if (defaultSignRes?.status === "success") {
|
||||
setDefaultSignImg(defaultSignRes?.res?.defaultSignature);
|
||||
setMyInitial(defaultSignRes?.res?.defaultInitial);
|
||||
} else if (defaultSignRes?.status === "error") {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
const sign = defaultSignRes?.res?.defaultSignature || "";
|
||||
const initials = defaultSignRes?.res?.defaultInitial || "";
|
||||
setDefaultSignImg(sign);
|
||||
setMyInitial(initials);
|
||||
}
|
||||
setIsLoading({ isLoad: false });
|
||||
} catch (err) {
|
||||
@@ -664,20 +681,30 @@ function PdfRequestFiles(props) {
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
);
|
||||
let currentUser = JSON.parse(localuser);
|
||||
let isEmailVerified = currentUser?.emailVerified;
|
||||
const isDisableOTP = pdfDetails?.[0]?.IsDisableOTP || false;
|
||||
//if emailVerified data is not present in local user details then fetch again in _User class
|
||||
if (!currentUser?.emailVerified) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const getUser = await userQuery.get(currentUser?.objectId, {
|
||||
sessionToken: currentUser?.sessionToken
|
||||
});
|
||||
if (getUser) {
|
||||
currentUser = JSON.parse(JSON.stringify(getUser));
|
||||
if (!isDisableOTP) {
|
||||
try {
|
||||
if (!currentUser?.emailVerified) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const getUser = await userQuery.get(currentUser?.objectId, {
|
||||
sessionToken:
|
||||
currentUser?.sessionToken || localStorage.getItem("accesstoken")
|
||||
});
|
||||
if (getUser) {
|
||||
currentUser = JSON.parse(JSON.stringify(getUser));
|
||||
}
|
||||
}
|
||||
isEmailVerified = currentUser?.emailVerified;
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
} catch (err) {
|
||||
console.log("err in get email verification ", err);
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
}
|
||||
}
|
||||
let isEmailVerified = currentUser?.emailVerified;
|
||||
//check if isEmailVerified then go on next step
|
||||
if (isEmailVerified) {
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
if (isDisableOTP || isEmailVerified) {
|
||||
try {
|
||||
const checkUser = signerPos.filter(
|
||||
(data) => data.signerObjId === signerObjectId
|
||||
@@ -858,17 +885,9 @@ function PdfRequestFiles(props) {
|
||||
// console.log("pdfte", pdfBytes);
|
||||
//get ExistUserPtr object id of user class to get tenantDetails
|
||||
const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId;
|
||||
//get ExistUserPtr email to get userDetails
|
||||
const res = await contractUsers();
|
||||
let activeMailAdapter = "";
|
||||
if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (!res || res?.length === 0) {
|
||||
activeMailAdapter = "";
|
||||
} else if (res[0] && res.length) {
|
||||
activeMailAdapter = res[0]?.active_mail_adapter;
|
||||
}
|
||||
let activeMailAdapter =
|
||||
pdfDetails?.[0]?.ExtUserPtr?.active_mail_adapter;
|
||||
|
||||
//function for call to embed signature in pdf and get digital signature pdf
|
||||
const resSign = await signPdfFun(
|
||||
pdfBytes,
|
||||
@@ -880,13 +899,13 @@ function PdfRequestFiles(props) {
|
||||
widgets
|
||||
);
|
||||
if (resSign && resSign.status === "success") {
|
||||
setPdfUrl(res.data);
|
||||
setPdfUrl(resSign.data);
|
||||
setIsSigned(true);
|
||||
setSignedSigners([]);
|
||||
setUnSignedSigners([]);
|
||||
getDocumentDetails(true);
|
||||
const index = pdfDetails?.[0].Signers.findIndex(
|
||||
(x) => x.Email === currentUser?.email
|
||||
const index = pdfDetails?.[0]?.Signers.findIndex(
|
||||
(x) => x.objectId === signerObjectId
|
||||
);
|
||||
const newIndex = index + 1;
|
||||
const usermail = {
|
||||
@@ -1054,21 +1073,6 @@ function PdfRequestFiles(props) {
|
||||
alertMessage: t("something-went-wrong-mssg")
|
||||
});
|
||||
}
|
||||
} else {
|
||||
//else verify users email
|
||||
try {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(currentUser?.objectId, {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
});
|
||||
if (user) {
|
||||
isEmailVerified = user?.get("emailVerified");
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error in save user's emailVerified in user class");
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1314,38 +1318,58 @@ function PdfRequestFiles(props) {
|
||||
const closeRequestSignTour = async () => {
|
||||
setRequestSignTour(true);
|
||||
if (isDontShow) {
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
const requestSignIndex = tourStatus.findIndex(
|
||||
(obj) => obj["requestSign"] === false || obj["requestSign"] === true
|
||||
);
|
||||
if (requestSignIndex !== -1) {
|
||||
updatedTourStatus[requestSignIndex] = { requestSign: true };
|
||||
} else {
|
||||
updatedTourStatus.push({ requestSign: true });
|
||||
const isDisableOTP = pdfDetails?.[0]?.IsDisableOTP || false;
|
||||
if (isDisableOTP) {
|
||||
try {
|
||||
await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/updatecontacttour`,
|
||||
{
|
||||
contactId: signerObjectId
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("update tour messages error", e);
|
||||
}
|
||||
} else {
|
||||
updatedTourStatus = [{ requestSign: true }];
|
||||
}
|
||||
try {
|
||||
await axios.put(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts${contractName}/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
const requestSignIndex = tourStatus.findIndex(
|
||||
(obj) => obj["requestSign"] === false || obj["requestSign"] === true
|
||||
);
|
||||
if (requestSignIndex !== -1) {
|
||||
updatedTourStatus[requestSignIndex] = { requestSign: true };
|
||||
} else {
|
||||
updatedTourStatus.push({ requestSign: true });
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("update tour messages error", e);
|
||||
} else {
|
||||
updatedTourStatus = [{ requestSign: true }];
|
||||
}
|
||||
try {
|
||||
await axios.put(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts${contractName}/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("update tour messages error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1938,7 +1962,12 @@ function PdfRequestFiles(props) {
|
||||
<div className="flex mt-4 gap-1 px-[15px]">
|
||||
<button
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, pdfUrl, setIsDownloading)
|
||||
handleToPrint(
|
||||
e,
|
||||
pdfUrl,
|
||||
setIsDownloading,
|
||||
pdfDetails
|
||||
)
|
||||
}
|
||||
type="button"
|
||||
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral"
|
||||
|
||||
@@ -266,7 +266,8 @@ const ReportTable = (props) => {
|
||||
Signers: signers,
|
||||
SendinOrder: Doc?.SendinOrder || false,
|
||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5
|
||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
|
||||
IsDisableOTP: Doc?.IsDisableOTP || false
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"upgrade-now": "Upgrade now",
|
||||
"upgrade-to": "Upgrade to",
|
||||
"plan": "Plan",
|
||||
"subscribe-card-teamplan":"Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!",
|
||||
"subscribe-card-teamplan": "Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!",
|
||||
"subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.",
|
||||
"user-name-limit-char": "To have a username less than 8 character please subscribe",
|
||||
"tour-content": "Don't show this again",
|
||||
@@ -614,27 +614,35 @@
|
||||
"select-date-format": "Select a date format",
|
||||
"quantity-of-credits": "Quantity of premium credits",
|
||||
"remaining-credits": "Premium credits available:",
|
||||
"remaining-credits-help":"Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.",
|
||||
"remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.",
|
||||
"additional-credits": "Please purchase premium credits",
|
||||
"quota-err-quicksend": "Quota Reached, You don't have enough credits.",
|
||||
"buy-credits": "Buy Premium Credits",
|
||||
"rotate-right":"Rotate right",
|
||||
"rotate-left":"Rotate left",
|
||||
"rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?",
|
||||
"templateid":"Template-Id",
|
||||
"bulk-send-subcription-alert":"Please upgrade to Professional or Team plan to use bulk send.",
|
||||
"generate-test-token":"Generate Test Token",
|
||||
"regenerate-test-token":"Regenerate Test Token",
|
||||
"help-test-token":"This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.",
|
||||
"help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.",
|
||||
"quota-mail-info-head":"Monthly request signatures email limit",
|
||||
"rotate-right": "Rotate right",
|
||||
"rotate-left": "Rotate left",
|
||||
"rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?",
|
||||
"templateid": "Template-Id",
|
||||
"bulk-send-subcription-alert": "Please upgrade to Professional or Team plan to use bulk send.",
|
||||
"generate-test-token": "Generate Test Token",
|
||||
"regenerate-test-token": "Regenerate Test Token",
|
||||
"help-test-token": "This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.",
|
||||
"help-api-token": "This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.",
|
||||
"quota-mail-info-head": "Monthly request signatures email limit",
|
||||
"quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.",
|
||||
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
|
||||
"quota-mail-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
|
||||
"quota-mail-head":"Quota Reached",
|
||||
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminEmail}}.",
|
||||
"sent-this-month":"Sent this month",
|
||||
"available-seats":"Available seats",
|
||||
"buy-users":"Buy more users"
|
||||
|
||||
"quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
|
||||
"quota-mail-head": "Quota Reached",
|
||||
"unauthorized-modal": "You don't have permission to perform this action, please contact {{adminEmail}}.",
|
||||
"sent-this-month": "Sent this month",
|
||||
"available-seats": "Available seats",
|
||||
"buy-users": "Buy more users",
|
||||
"isdisable-otp": "Enable OTP verification",
|
||||
"isdisable-otp-help": {
|
||||
"p1": "Would you like to enable the verification process using a one-time password (OTP)?",
|
||||
"p2": "Selecting this option will enable OTP verification. Users will receive a verification code via email, which they must enter to sign the document.",
|
||||
"p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.",
|
||||
"p4": "Please choose the option that best suits your document signing requirements."
|
||||
},
|
||||
"advanced-options": "Advanced options",
|
||||
"hide-advanced-options": "Hide Advanced options"
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"upgrade-to": "Mettre à niveau vers",
|
||||
"pro": "PRO",
|
||||
"plan": "Offre",
|
||||
"subscribe-card-teamplan":"Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !",
|
||||
"subscribe-card-teamplan": "Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !",
|
||||
"subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.",
|
||||
"user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner",
|
||||
"tour-content": "Ne plus afficher",
|
||||
@@ -611,29 +611,37 @@
|
||||
"Add-seats": "Ajouter des sièges",
|
||||
"format": "format",
|
||||
"select-date-format": "Sélectionnez un format de date",
|
||||
"quantity-of-credits":"Quantité de crédits de prime",
|
||||
"remaining-credits":"Crédits premium disponibles :",
|
||||
"additional-credits":"Veuillez acheter des crédits premium",
|
||||
"remaining-credits-help":"Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.",
|
||||
"quantity-of-credits": "Quantité de crédits de prime",
|
||||
"remaining-credits": "Crédits premium disponibles :",
|
||||
"additional-credits": "Veuillez acheter des crédits premium",
|
||||
"remaining-credits-help": "Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.",
|
||||
"quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.",
|
||||
"buy-credits": "Acheter des crédits premium",
|
||||
"rotate-right" :"Faire pivoter à droite",
|
||||
"rotate-left" :"Faire pivoter à gauche",
|
||||
"rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?",
|
||||
"templateid":"ID de modèle",
|
||||
"bulk-send-subcription-alert":"Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.",
|
||||
"rotate-right": "Faire pivoter à droite",
|
||||
"rotate-left": "Faire pivoter à gauche",
|
||||
"rotate-alert-mssg": "Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?",
|
||||
"templateid": "ID de modèle",
|
||||
"bulk-send-subcription-alert": "Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.",
|
||||
"generate-test-token": "Générer jeton de test",
|
||||
"regenerate-test-token":"Régénérer le jeton de test",
|
||||
"help-test-token":"Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.",
|
||||
"help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.",
|
||||
"quota-mail-info-head":"Limite mensuelle d'e-mails de signatures de demandes",
|
||||
"regenerate-test-token": "Régénérer le jeton de test",
|
||||
"help-test-token": "Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.",
|
||||
"help-api-token": "Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.",
|
||||
"quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes",
|
||||
"quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.",
|
||||
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
|
||||
"quota-mail-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
|
||||
"quota-mail-head":"Quota atteint",
|
||||
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
|
||||
"sent-this-month":"envoyé ce mois-ci",
|
||||
"available-seats":"Disponible sièges",
|
||||
"buy-users":"Acheter plus d'utilisateurs"
|
||||
|
||||
"quota-mail-tip": "Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
|
||||
"quota-mail-head": "Quota atteint",
|
||||
"unauthorized-modal": "Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
|
||||
"sent-this-month": "envoyé ce mois-ci",
|
||||
"available-seats": "Disponible sièges",
|
||||
"buy-users": "Acheter plus d'utilisateurs",
|
||||
"isdisable-otp": "Activer la vérification OTP",
|
||||
"isdisable-otp-help": {
|
||||
"p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?",
|
||||
"p2": "La sélection de cette option activera la vérification OTP. Les utilisateurs recevront un code de vérification par e-mail, qu'ils devront saisir pour signer le document.",
|
||||
"p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.",
|
||||
"p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents."
|
||||
},
|
||||
"advanced-options": "Options avancées",
|
||||
"hide-advanced-options": "Masquer les options avancées"
|
||||
}
|
||||
|
||||
@@ -196,6 +196,8 @@ export default async function createDocumentWithTemplate(request, response) {
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
const isDisableOTP = template?.IsDisableOTP || request.body?.isDisableOTP || false;
|
||||
object.set('IsDisableOTP', isDisableOTP);
|
||||
object.set('CreatedBy', template.CreatedBy);
|
||||
object.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
|
||||
@@ -63,6 +63,7 @@ export default async function createDocumentwithCoordinate(request, response) {
|
||||
const email_body = request.body.email_body;
|
||||
const sendInOrder = request.body.sendInOrder || false;
|
||||
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
|
||||
const isDisableOTP = request.body.isDisableOTP || false;
|
||||
// console.log('fileData ', fileData);
|
||||
const protocol = customAPIurl();
|
||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||
@@ -162,6 +163,7 @@ export default async function createDocumentwithCoordinate(request, response) {
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
object.set('IsDisableOTP', isDisableOTP);
|
||||
object.set('IsSendMail', send_email);
|
||||
let contact = [];
|
||||
if (signers && signers.length > 0) {
|
||||
|
||||
@@ -17,6 +17,8 @@ export default async function createTemplatewithCoordinate(request, response) {
|
||||
const base64File = request.body.file;
|
||||
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
||||
const SendinOrder = request.body.sendInOrder || false;
|
||||
const isDisableOTP = request.body.isDisableOTP || false;
|
||||
|
||||
// console.log('fileData ', fileData);
|
||||
const protocol = customAPIurl();
|
||||
|
||||
@@ -80,6 +82,7 @@ export default async function createTemplatewithCoordinate(request, response) {
|
||||
object.set('URL', fileUrl);
|
||||
object.set('CreatedBy', userPtr);
|
||||
object.set('ExtUserPtr', extUserPtr);
|
||||
object.set('IsDisableOTP', isDisableOTP);
|
||||
let contact = [];
|
||||
if (signers && signers.length > 0) {
|
||||
let parseSigners;
|
||||
|
||||
@@ -65,6 +65,8 @@ import ExtUserAftersave from './parsefunction/ExtUserAftersave.js';
|
||||
import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js';
|
||||
import AllowedCredits from './parsefunction/AllowedCredits.js';
|
||||
import BuyCredits from './parsefunction/BuyCredits.js';
|
||||
import getContact from './parsefunction/getContact.js';
|
||||
import updateContactTour from './parsefunction/updateContactTour.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);
|
||||
@@ -142,3 +144,5 @@ Parse.Cloud.define('allowedusers', AllowedUsers);
|
||||
Parse.Cloud.define('buyaddonusers', BuyAddonUsers);
|
||||
Parse.Cloud.define('allowedcredits', AllowedCredits);
|
||||
Parse.Cloud.define('buycredits', BuyCredits);
|
||||
Parse.Cloud.define('getcontact', getContact);
|
||||
Parse.Cloud.define('updatecontacttour', updateContactTour);
|
||||
|
||||
@@ -7,99 +7,101 @@ export default async function callWebhook(request) {
|
||||
const contactId = request.params.contactId;
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
if (event === 'viewed' && contactId) {
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
const res = await docQuery.get(docId, { useMasterKey: true });
|
||||
if (res) {
|
||||
const _res = res.toJSON();
|
||||
const userPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: contactId,
|
||||
};
|
||||
const date = new Date().toISOString();
|
||||
const obj = {
|
||||
UserPtr: userPtr,
|
||||
SignedUrl: _res.SignedUrl,
|
||||
Activity: 'Viewed',
|
||||
ipAddress: request.headers['x-real-ip'],
|
||||
ViewedOn: date,
|
||||
};
|
||||
const isUserExist = _res?.AuditTrail?.some(
|
||||
x => x.UserPtr.objectId === contactId && x?.ViewedOn
|
||||
);
|
||||
if (!isUserExist) {
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = res.id;
|
||||
if (_res?.AuditTrail && _res?.AuditTrail?.length > 0) {
|
||||
updateDoc.set('AuditTrail', [..._res?.AuditTrail, obj]);
|
||||
} else {
|
||||
updateDoc.set('AuditTrail', [obj]);
|
||||
try {
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
const docRes = await docQuery.get(docId, { useMasterKey: true });
|
||||
const isDisableOTP = docRes?.get('IsDisableOTP') || false;
|
||||
let userId;
|
||||
if (!isDisableOTP) {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
userId = userRes.data && userRes.data.objectId;
|
||||
}
|
||||
if (isDisableOTP || userId) {
|
||||
if (event === 'viewed' && contactId) {
|
||||
if (docRes) {
|
||||
const _docRes = docRes.toJSON();
|
||||
const userPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: contactId,
|
||||
};
|
||||
const date = new Date().toISOString();
|
||||
const obj = {
|
||||
UserPtr: userPtr,
|
||||
SignedUrl: _docRes.SignedUrl,
|
||||
Activity: 'Viewed',
|
||||
ipAddress: request.headers['x-real-ip'],
|
||||
ViewedOn: date,
|
||||
};
|
||||
const isUserExist = _docRes?.AuditTrail?.some(
|
||||
x => x.UserPtr.objectId === contactId && x?.ViewedOn
|
||||
);
|
||||
if (!isUserExist) {
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = docRes.id;
|
||||
if (_docRes?.AuditTrail && _docRes?.AuditTrail?.length > 0) {
|
||||
updateDoc.set('AuditTrail', [..._docRes?.AuditTrail, obj]);
|
||||
} else {
|
||||
updateDoc.set('AuditTrail', [obj]);
|
||||
}
|
||||
await updateDoc.save(null, { useMasterKey: true });
|
||||
}
|
||||
await updateDoc.save(null, { useMasterKey: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
const resDoc = await docQuery.get(docId, { useMasterKey: true });
|
||||
const extendcls = new Parse.Query('contracts_Users');
|
||||
extendcls.equalTo('objectId', resDoc.get('ExtUserPtr')?.id);
|
||||
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const res = await extendcls.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const extUser = JSON.parse(JSON.stringify(res));
|
||||
if (extUser?.Webhook) {
|
||||
const params = {
|
||||
event: event,
|
||||
...body,
|
||||
};
|
||||
await axios
|
||||
.post(extUser?.Webhook, params, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
.then(res => {
|
||||
try {
|
||||
// console.log('res ', res);
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err.message);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
});
|
||||
const extendcls = new Parse.Query('contracts_Users');
|
||||
extendcls.equalTo('objectId', docRes.get('ExtUserPtr')?.id);
|
||||
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const resExt = await extendcls.first({ useMasterKey: true });
|
||||
if (resExt) {
|
||||
const extUser = JSON.parse(JSON.stringify(resExt));
|
||||
if (extUser?.Webhook) {
|
||||
const params = { event: event, ...body };
|
||||
await axios
|
||||
.post(extUser?.Webhook, params, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
.then(res => {
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err.message);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
return { message: 'webhook called!' };
|
||||
}
|
||||
return { message: 'webhook called!' };
|
||||
} else {
|
||||
return { message: 'User not found!' };
|
||||
}
|
||||
} else {
|
||||
return { message: 'User not found!' };
|
||||
} catch (err) {
|
||||
console.log('Err in callwebhook', err);
|
||||
return { message: 'Something went wrong!' };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ export default async function createBatchDocs(request) {
|
||||
TimeToCompleteDays: x.TimeToCompleteDays || 15,
|
||||
OriginIp: Ip,
|
||||
DocSentAt: { __type: 'Date', iso: isoDate },
|
||||
IsDisableOTP: x?.IsDisableOTP || false,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export default async function getContact(request) {
|
||||
const contactId = request.params.contactId;
|
||||
try {
|
||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||
const contactRes = await contactCls.get(contactId, { useMasterKey: true });
|
||||
return contactRes;
|
||||
} catch (err) {
|
||||
console.log('Err in contracts_Contactbook class ', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,7 @@ export default async function getDocument(request) {
|
||||
const docId = request.params.docId;
|
||||
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (docId && userId) {
|
||||
if (docId) {
|
||||
try {
|
||||
const query = new Parse.Query('contracts_Document');
|
||||
query.equalTo('objectId', docId);
|
||||
@@ -26,11 +19,32 @@ export default async function getDocument(request) {
|
||||
query.notEqualTo('IsArchive', true);
|
||||
const res = await query.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const acl = res.getACL();
|
||||
if (acl && acl.getReadAccess(userId)) {
|
||||
const IsDisableOTP = res?.get('IsDisableOTP') || false;
|
||||
if (IsDisableOTP) {
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
if (request?.headers?.['sessiontoken']) {
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data?.objectId;
|
||||
const acl = res.getACL();
|
||||
if (userId && acl && acl.getReadAccess(userId)) {
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err user in not authenticated', err);
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
|
||||
@@ -28,15 +28,42 @@ export default function getPresignedUrl(url) {
|
||||
|
||||
export async function getSignedUrl(request) {
|
||||
try {
|
||||
const docId = request.params.docId || '';
|
||||
const url = request.params.url;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
if (docId) {
|
||||
try {
|
||||
const query = new Parse.Query('contracts_Document');
|
||||
query.equalTo('objectId', docId);
|
||||
query.equalTo('IsDisableOTP', true);
|
||||
query.include('CreatedBy');
|
||||
query.include('Signers');
|
||||
query.include('AuditTrail.UserPtr');
|
||||
query.include('Placeholders');
|
||||
query.include('DeclineBy');
|
||||
query.notEqualTo('IsArchive', true);
|
||||
const res = await query.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
if (useLocal !== 'true') {
|
||||
const presignedUrl = getPresignedUrl(url);
|
||||
return presignedUrl;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in presigned url', err);
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
if (useLocal !== 'true') {
|
||||
const presignedUrl = getPresignedUrl(url);
|
||||
return presignedUrl;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
} else {
|
||||
return url;
|
||||
if (useLocal !== 'true') {
|
||||
const presignedUrl = getPresignedUrl(url);
|
||||
return presignedUrl;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -50,37 +50,24 @@ export default async function getSubscription(request) {
|
||||
}
|
||||
} else if (contactId) {
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||
const contactUser = await contactCls.get(contactId, { useMasterKey: true });
|
||||
if (contactUser) {
|
||||
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||
subscriptionCls.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: contactUser.get('TenantId').id,
|
||||
});
|
||||
subscriptionCls.descending('createdAt');
|
||||
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||
|
||||
if (subcripitions) {
|
||||
const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
|
||||
if (_subcripitions.PlanCode === 'freeplan') {
|
||||
return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } };
|
||||
} else if (_subcripitions?.Next_billing_date?.iso) {
|
||||
if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) {
|
||||
return { status: 'success', result: { isSubscribed: true } };
|
||||
} else {
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||
const contactUser = await contactCls.get(contactId, { useMasterKey: true });
|
||||
if (contactUser) {
|
||||
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||
subscriptionCls.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: contactUser.get('TenantId').id,
|
||||
});
|
||||
subscriptionCls.descending('createdAt');
|
||||
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||
if (subcripitions) {
|
||||
const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
|
||||
if (_subcripitions.PlanCode === 'freeplan') {
|
||||
return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } };
|
||||
} else if (_subcripitions?.Next_billing_date?.iso) {
|
||||
if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) {
|
||||
return { status: 'success', result: { isSubscribed: true } };
|
||||
} else {
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
@@ -88,10 +75,10 @@ export default async function getSubscription(request) {
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'User not found!' };
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid session token!' };
|
||||
return { status: 'error', result: 'User not found!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in get subscription2', err.message);
|
||||
|
||||
@@ -32,6 +32,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
const OriginIp = docDetails?.OriginIp || '';
|
||||
const company = docDetails?.ExtUserPtr?.Company || '';
|
||||
const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt;
|
||||
const isDisableOTP = docDetails?.IsDisableOTP || false;
|
||||
const auditTrail =
|
||||
docDetails?.Signers?.length > 0
|
||||
? docDetails.AuditTrail.map(x => {
|
||||
@@ -348,22 +349,22 @@ export default async function GenerateCertificate(docDetails) {
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('Security level :', {
|
||||
x: half + 55,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(`Email, OTP Auth`, {
|
||||
x: half + 125,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
if (!isDisableOTP) {
|
||||
page.drawText('Security level :', {
|
||||
x: half + 55,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText('Email, OTP Auth', {
|
||||
x: half + 125,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
}
|
||||
page.drawText('Signature :', {
|
||||
x: 30,
|
||||
y: yPosition5,
|
||||
|
||||
@@ -272,157 +272,160 @@ const sendMailsaveCertifcate = async (doc, P12Buffer, url, isCustomMail, mailPro
|
||||
*/
|
||||
async function PDF(req) {
|
||||
try {
|
||||
if (!req?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
const userIP = req.headers['x-real-ip']; // client IPaddress
|
||||
const docId = req.params.docId;
|
||||
const reqUserId = req.params.userId;
|
||||
const isCustomMail = req.params.isCustomCompletionMail || false;
|
||||
const mailProvider = req.params.mailProvider || '';
|
||||
const sign = req.params.signature || '';
|
||||
// below bode is used to get info of docId
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.include('ExtUserPtr,Signers');
|
||||
docQuery.equalTo('objectId', docId);
|
||||
const resDoc = await docQuery.first({ useMasterKey: true });
|
||||
if (!resDoc) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
|
||||
}
|
||||
const IsDisableOTP = resDoc?.get('IsDisableOTP') || false;
|
||||
// if `IsDisableOTP` is true then we don't have to check authentication
|
||||
if (!IsDisableOTP) {
|
||||
if (!req?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
}
|
||||
const _resDoc = resDoc?.toJSON();
|
||||
let signUser;
|
||||
let className;
|
||||
// `reqUserId` is send throught pdfrequest signing flow
|
||||
if (reqUserId) {
|
||||
// to get contracts_Contactbook details for currentuser from reqUserId
|
||||
const _contractUser = _resDoc.Signers.find(x => x.objectId === reqUserId);
|
||||
if (_contractUser) {
|
||||
signUser = _contractUser;
|
||||
className = 'contracts_Contactbook';
|
||||
}
|
||||
} else {
|
||||
const userIP = req.headers['x-real-ip']; // client IPaddress
|
||||
const docId = req.params.docId;
|
||||
const reqUserId = req.params.userId;
|
||||
const isCustomMail = req.params.isCustomCompletionMail || false;
|
||||
const mailProvider = req.params.mailProvider || '';
|
||||
const sign = req.params.signature || '';
|
||||
// below bode is used to get info of docId
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.include('ExtUserPtr,Signers');
|
||||
docQuery.equalTo('objectId', docId);
|
||||
const resDoc = await docQuery.first({ useMasterKey: true });
|
||||
if (!resDoc) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
|
||||
}
|
||||
const _resDoc = resDoc?.toJSON();
|
||||
let signUser;
|
||||
let className;
|
||||
// `reqUserId` is send throught pdfrequest signing flow
|
||||
if (reqUserId) {
|
||||
// to get contracts_Contactbook details for currentuser from reqUserId
|
||||
const _contractUser = _resDoc.Signers.find(x => x.objectId === reqUserId);
|
||||
if (_contractUser) {
|
||||
signUser = _contractUser;
|
||||
className = 'contracts_Contactbook';
|
||||
}
|
||||
className = 'contracts_Users';
|
||||
signUser = _resDoc.ExtUserPtr;
|
||||
}
|
||||
|
||||
const username = signUser.Name;
|
||||
const userEmail = signUser.Email;
|
||||
if (req.params.pdfFile) {
|
||||
// `PdfBuffer` used to create buffer from pdf file
|
||||
let PdfBuffer = Buffer.from(req.params.pdfFile, 'base64');
|
||||
// `P12Buffer` used to create buffer from p12 certificate
|
||||
const pfxFile = process.env.PFX_BASE64;
|
||||
// const P12Buffer = fs.readFileSync();
|
||||
const P12Buffer = Buffer.from(pfxFile, 'base64');
|
||||
const p12Cert = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null });
|
||||
const UserPtr = { __type: 'Pointer', className: className, objectId: signUser.objectId };
|
||||
const obj = { UserPtr: UserPtr, SignedUrl: '', Activity: 'Signed', ipAddress: userIP };
|
||||
let updateAuditTrail;
|
||||
if (_resDoc.AuditTrail && _resDoc.AuditTrail.length > 0) {
|
||||
updateAuditTrail = [..._resDoc.AuditTrail, obj];
|
||||
} else {
|
||||
className = 'contracts_Users';
|
||||
signUser = _resDoc.ExtUserPtr;
|
||||
updateAuditTrail = [obj];
|
||||
}
|
||||
|
||||
const username = signUser.Name;
|
||||
const userEmail = signUser.Email;
|
||||
if (req.params.pdfFile) {
|
||||
// `PdfBuffer` used to create buffer from pdf file
|
||||
let PdfBuffer = Buffer.from(req.params.pdfFile, 'base64');
|
||||
// `P12Buffer` used to create buffer from p12 certificate
|
||||
const pfxFile = process.env.PFX_BASE64;
|
||||
// const P12Buffer = fs.readFileSync();
|
||||
const P12Buffer = Buffer.from(pfxFile, 'base64');
|
||||
const p12Cert = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null });
|
||||
const UserPtr = { __type: 'Pointer', className: className, objectId: signUser.objectId };
|
||||
const obj = { UserPtr: UserPtr, SignedUrl: '', Activity: 'Signed', ipAddress: userIP };
|
||||
let updateAuditTrail;
|
||||
if (_resDoc.AuditTrail && _resDoc.AuditTrail.length > 0) {
|
||||
updateAuditTrail = [..._resDoc.AuditTrail, obj];
|
||||
} else {
|
||||
updateAuditTrail = [obj];
|
||||
}
|
||||
|
||||
const auditTrail = updateAuditTrail.filter(x => x.Activity === 'Signed');
|
||||
let isCompleted = false;
|
||||
if (_resDoc.Signers && _resDoc.Signers.length > 0) {
|
||||
if (auditTrail.length === _resDoc.Signers.length) {
|
||||
isCompleted = true;
|
||||
}
|
||||
} else {
|
||||
const auditTrail = updateAuditTrail.filter(x => x.Activity === 'Signed');
|
||||
let isCompleted = false;
|
||||
if (_resDoc.Signers && _resDoc.Signers.length > 0) {
|
||||
if (auditTrail.length === _resDoc.Signers.length) {
|
||||
isCompleted = true;
|
||||
}
|
||||
const randomNumber = Math.floor(Math.random() * 5000);
|
||||
const name = `exported_file_${randomNumber}.pdf`;
|
||||
const pdfName = `./exports/${name}`;
|
||||
let pdfSize = PdfBuffer.length;
|
||||
if (isCompleted) {
|
||||
const signersName = _resDoc.Signers?.map(x => x.Name + ' <' + x.Email + '>');
|
||||
if (signersName && signersName.length > 0) {
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + signersName?.join(', '),
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
} else {
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget (signyourself)
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + username + ' <' + userEmail + '>',
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
}
|
||||
//`new signPDF` create new instance of pdfBuffer and p12Buffer
|
||||
const OBJ = new SignPdf();
|
||||
// `signedDocs` is used to signpdf digitally
|
||||
const signedDocs = await OBJ.sign(PdfBuffer, p12Cert);
|
||||
|
||||
//`saveUrl` is used to save signed pdf in exports folder
|
||||
const saveUrl = fs.writeFileSync(pdfName, signedDocs);
|
||||
pdfSize = signedDocs.length;
|
||||
} else {
|
||||
//`saveUrl` is used to save signed pdf in exports folder
|
||||
const saveUrl = fs.writeFileSync(pdfName, PdfBuffer);
|
||||
pdfSize = PdfBuffer.length;
|
||||
}
|
||||
|
||||
// `uploadFile` is used to upload pdf to aws s3 and get it's url
|
||||
const data = await uploadFile(name, pdfName);
|
||||
|
||||
if (data && data.imageUrl) {
|
||||
// `axios` is used to update signed pdf url in contracts_Document classes for given DocId
|
||||
const updatedDoc = await updateDoc(
|
||||
req.params.docId, //docId
|
||||
data.imageUrl, // url
|
||||
signUser.objectId, // userID
|
||||
userIP, // client ipAddress,
|
||||
_resDoc, // auditTrail, signers, etc data
|
||||
className, // className based on flow
|
||||
sign // sign base64
|
||||
);
|
||||
sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser);
|
||||
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
|
||||
if (updatedDoc && updatedDoc.isCompleted) {
|
||||
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail };
|
||||
sendMailsaveCertifcate(
|
||||
doc,
|
||||
P12Buffer,
|
||||
data.imageUrl,
|
||||
isCustomMail,
|
||||
mailProvider,
|
||||
_resDoc?.CreatedBy?.objectId
|
||||
);
|
||||
}
|
||||
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
|
||||
fs.unlinkSync(pdfName);
|
||||
console.log(`New Signed PDF created called: ${pdfName}`);
|
||||
if (updatedDoc.message === 'success') {
|
||||
return { status: 'success', data: data.imageUrl };
|
||||
} else {
|
||||
const error = new Error('Please provide required parameters!');
|
||||
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const error = new Error('Pdf file not present!');
|
||||
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||
throw error;
|
||||
isCompleted = true;
|
||||
}
|
||||
const randomNumber = Math.floor(Math.random() * 5000);
|
||||
const name = `exported_file_${randomNumber}.pdf`;
|
||||
const pdfName = `./exports/${name}`;
|
||||
let pdfSize = PdfBuffer.length;
|
||||
if (isCompleted) {
|
||||
const signersName = _resDoc.Signers?.map(x => x.Name + ' <' + x.Email + '>');
|
||||
if (signersName && signersName.length > 0) {
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + signersName?.join(', '),
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
} else {
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget (signyourself)
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + username + ' <' + userEmail + '>',
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
}
|
||||
//`new signPDF` create new instance of pdfBuffer and p12Buffer
|
||||
const OBJ = new SignPdf();
|
||||
// `signedDocs` is used to signpdf digitally
|
||||
const signedDocs = await OBJ.sign(PdfBuffer, p12Cert);
|
||||
|
||||
//`saveUrl` is used to save signed pdf in exports folder
|
||||
const saveUrl = fs.writeFileSync(pdfName, signedDocs);
|
||||
pdfSize = signedDocs.length;
|
||||
} else {
|
||||
//`saveUrl` is used to save signed pdf in exports folder
|
||||
const saveUrl = fs.writeFileSync(pdfName, PdfBuffer);
|
||||
pdfSize = PdfBuffer.length;
|
||||
}
|
||||
|
||||
// `uploadFile` is used to upload pdf to aws s3 and get it's url
|
||||
const data = await uploadFile(name, pdfName);
|
||||
|
||||
if (data && data.imageUrl) {
|
||||
// `axios` is used to update signed pdf url in contracts_Document classes for given DocId
|
||||
const updatedDoc = await updateDoc(
|
||||
req.params.docId, //docId
|
||||
data.imageUrl, // url
|
||||
signUser.objectId, // userID
|
||||
userIP, // client ipAddress,
|
||||
_resDoc, // auditTrail, signers, etc data
|
||||
className, // className based on flow
|
||||
sign // sign base64
|
||||
);
|
||||
sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser);
|
||||
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
|
||||
if (updatedDoc && updatedDoc.isCompleted) {
|
||||
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail };
|
||||
sendMailsaveCertifcate(
|
||||
doc,
|
||||
P12Buffer,
|
||||
data.imageUrl,
|
||||
isCustomMail,
|
||||
mailProvider,
|
||||
_resDoc?.CreatedBy?.objectId
|
||||
);
|
||||
}
|
||||
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
|
||||
fs.unlinkSync(pdfName);
|
||||
console.log(`New Signed PDF created called: ${pdfName}`);
|
||||
if (updatedDoc.message === 'success') {
|
||||
return { status: 'success', data: data.imageUrl };
|
||||
} else {
|
||||
const error = new Error('Please provide required parameters!');
|
||||
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const error = new Error('Pdf file not present!');
|
||||
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||
throw error;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in signpdf', err);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
export default async function updateContactTour(request) {
|
||||
const contactId = request.params.contactId;
|
||||
try {
|
||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||
const contactRes = await contactCls.get(contactId, { useMasterKey: true });
|
||||
if (contactRes) {
|
||||
const _contactRes = JSON.parse(JSON.stringify(contactRes));
|
||||
const tourStatus = _contactRes?.TourStatus?.length > 0 ? _contactRes.TourStatus : [];
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
const requestSignIndex = tourStatus.findIndex(
|
||||
obj => obj['requestSign'] === false || obj['requestSign'] === true
|
||||
);
|
||||
if (requestSignIndex !== -1) {
|
||||
updatedTourStatus[requestSignIndex] = { requestSign: true };
|
||||
} else {
|
||||
updatedTourStatus.push({ requestSign: true });
|
||||
}
|
||||
} else {
|
||||
updatedTourStatus = [{ requestSign: true }];
|
||||
}
|
||||
contactRes.set('TourStatus', updatedTourStatus);
|
||||
const updateRes = await contactRes.save(null, { useMasterKey: true });
|
||||
return updateRes;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'contact not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in contracts_Contactbook class ', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
*
|
||||
* @param {Parse} Parse
|
||||
*/
|
||||
exports.up = async Parse => {
|
||||
const templateSchema = new Parse.Schema('contracts_Template');
|
||||
templateSchema.addBoolean('IsDisableOTP');
|
||||
await templateSchema.update();
|
||||
|
||||
const className = 'contracts_Document';
|
||||
const schema = new Parse.Schema(className);
|
||||
schema.addBoolean('IsDisableOTP');
|
||||
return schema.update();
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Parse} Parse
|
||||
*/
|
||||
exports.down = async Parse => {
|
||||
const templateSchema = new Parse.Schema('contracts_Template');
|
||||
templateSchema.deleteField('IsDisableOTP');
|
||||
await templateSchema.update();
|
||||
|
||||
const className = 'contracts_Document';
|
||||
const schema = new Parse.Schema(className);
|
||||
schema.deleteField('IsDisableOTP');
|
||||
return schema.update();
|
||||
};
|
||||
Generated
+108
-76
@@ -1770,11 +1770,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@google-cloud/firestore": {
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.9.0.tgz",
|
||||
"integrity": "sha512-c4ALHT3G08rV7Zwv8Z2KG63gZh66iKdhCBeDfCpIkLrjX6EAjTD/szMdj14M+FnQuClZLFfW5bAgoOjfNmLtJg==",
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.10.0.tgz",
|
||||
"integrity": "sha512-VFNhdHvfnmqcHHs6YhmSNHHxQqaaD64GwiL0c+e1qz85S8SWZPC2XFRf8p9yHRTF40Kow424s1KBU9f0fdQa+Q==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/api": "^1.3.0",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"google-gax": "^4.3.3",
|
||||
@@ -1866,9 +1867,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": {
|
||||
"version": "10.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.2.tgz",
|
||||
"integrity": "sha512-VZpw7wxwmQGcCGt8epw6fDb8LkoySbTJ/MU565ibKivPqCkH96XK36Et/N0RlRCYGN6QAXn5UIaSbOYYHrnpAA==",
|
||||
"version": "10.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz",
|
||||
"integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==",
|
||||
"dependencies": {
|
||||
"@graphql-typed-document-node/core": "^3.1.1",
|
||||
"cross-inspect": "1.0.1",
|
||||
@@ -1900,9 +1901,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@graphql-tools/schema/node_modules/@graphql-tools/utils": {
|
||||
"version": "10.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.2.tgz",
|
||||
"integrity": "sha512-VZpw7wxwmQGcCGt8epw6fDb8LkoySbTJ/MU565ibKivPqCkH96XK36Et/N0RlRCYGN6QAXn5UIaSbOYYHrnpAA==",
|
||||
"version": "10.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz",
|
||||
"integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==",
|
||||
"dependencies": {
|
||||
"@graphql-typed-document-node/core": "^3.1.1",
|
||||
"cross-inspect": "1.0.1",
|
||||
@@ -1936,9 +1937,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@grpc/grpc-js": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.1.tgz",
|
||||
"integrity": "sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw==",
|
||||
"version": "1.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.2.tgz",
|
||||
"integrity": "sha512-DWp92gDD7/Qkj7r8kus6/HCINeo3yPZWZ3paKgDgsbKbSpoxKg1yvN8xe2Q8uE3zOsPe3bX8FQX2+XValq2yTw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@grpc/proto-loader": "^0.7.13",
|
||||
@@ -2625,6 +2626,15 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/api": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
|
||||
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@parse/fs-files-adapter": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-3.0.0.tgz",
|
||||
@@ -3771,11 +3781,11 @@
|
||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz",
|
||||
"integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==",
|
||||
"version": "22.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
||||
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.13.0"
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
@@ -3793,9 +3803,9 @@
|
||||
"integrity": "sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw=="
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
|
||||
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg=="
|
||||
"version": "6.9.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
|
||||
"integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A=="
|
||||
},
|
||||
"node_modules/@types/range-parser": {
|
||||
"version": "1.2.7",
|
||||
@@ -4157,9 +4167,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/aws4": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz",
|
||||
"integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA=="
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
|
||||
"integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.7",
|
||||
@@ -4270,9 +4280,9 @@
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
@@ -4282,7 +4292,7 @@
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
@@ -4305,6 +4315,20 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/body-parser/node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/bowser": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz",
|
||||
@@ -5797,29 +5821,6 @@
|
||||
"express": "^4 || ^5"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
@@ -6142,11 +6143,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/firebase-admin/node_modules/@types/node": {
|
||||
"version": "20.14.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
|
||||
"integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==",
|
||||
"version": "20.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
|
||||
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/firebase-admin/node_modules/long": {
|
||||
@@ -6154,11 +6155,6 @@
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||
},
|
||||
"node_modules/firebase-admin/node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||
},
|
||||
"node_modules/flat-cache": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
|
||||
@@ -6600,9 +6596,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/google-gax": {
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.9.tgz",
|
||||
"integrity": "sha512-tcjQr7sXVGMdlvcG25wSv98ap1dtF4Z6mcV0rztGIddOcezw4YMb/uTXg72JPrLep+kXcVjaJjg6oo3KLf4itQ==",
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz",
|
||||
"integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.10.9",
|
||||
@@ -7845,9 +7841,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/loglevel": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
|
||||
"integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
|
||||
"integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
},
|
||||
@@ -8518,9 +8514,9 @@
|
||||
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.65.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
|
||||
"integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
|
||||
"version": "3.67.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz",
|
||||
"integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
@@ -9414,6 +9410,42 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-server/node_modules/body-parser": {
|
||||
"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.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-server/node_modules/body-parser/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-server/node_modules/body-parser/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/parse-server/node_modules/bson": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz",
|
||||
@@ -10417,9 +10449,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz",
|
||||
"integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==",
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
|
||||
"integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -10475,9 +10507,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
@@ -11970,9 +12002,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz",
|
||||
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg=="
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
|
||||
Reference in New Issue
Block a user