diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js
index e7183f4ce..91fb8eb5f 100644
--- a/apps/OpenSign/src/App.js
+++ b/apps/OpenSign/src/App.js
@@ -35,6 +35,7 @@ const GenerateToken = lazy(() => import("./pages/GenerateToken"));
const Webhook = lazy(() => import("./pages/Webhook"));
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
+const DraftTemplate = lazy(() => import("./pages/DraftTemplate"));
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
const AppLoader = () => {
@@ -200,6 +201,10 @@ function App() {
} />
} />
+ }
+ />
} />
diff --git a/apps/OpenSign/src/components/BulkSendUi.js b/apps/OpenSign/src/components/BulkSendUi.js
index 4a4b872e7..49883fbad 100644
--- a/apps/OpenSign/src/components/BulkSendUi.js
+++ b/apps/OpenSign/src/components/BulkSendUi.js
@@ -69,7 +69,21 @@ const BulkSendUi = (props) => {
if (subscription?.plan === "freeplan") {
setIsFreePlan(true);
}
- const resCredits = await Parse.Cloud.run("allowedcredits");
+ const token = props.jwttoken
+ ? { jwttoken: props.jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const axiosres = await axios.post(
+ `${localStorage.getItem("baseUrl")}functions/allowedcredits`,
+ {},
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ }
+ }
+ );
+ const resCredits = axiosres.data && axiosres.data.result;
if (resCredits) {
const allowedcredits = resCredits?.allowedcredits || 0;
const addoncredits = resCredits?.addoncredits || 0;
@@ -81,7 +95,7 @@ const BulkSendUi = (props) => {
}
setAmount((obj) => ({ ...obj, totalcredits: totalcredits }));
}
- const getPlaceholder = props.item?.Placeholders;
+ const getPlaceholder = props?.Placeholders;
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
placeholderObj?.placeHolder?.some((holder) =>
holder?.pos?.some((posItem) => posItem?.type === "signature")
@@ -97,7 +111,7 @@ const BulkSendUi = (props) => {
} else {
setIsBulkAvailable(true);
setAdmin((obj) => ({ ...obj, isAdmin: true }));
- const getPlaceholder = props.item?.Placeholders;
+ const getPlaceholder = props?.Placeholders;
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
placeholderObj?.placeHolder?.some((holder) =>
holder?.pos?.some((posItem) => posItem?.type === "signature")
@@ -194,7 +208,7 @@ const BulkSendUi = (props) => {
setIsSubmit(true);
// Create a copy of Placeholders array from props.item
- let Placeholders = [...props.item.Placeholders];
+ let Placeholders = [...props.Placeholders];
// Initialize an empty array to store updated documents
let Documents = [];
// Loop through each form
@@ -251,12 +265,16 @@ const BulkSendUi = (props) => {
};
const batchQuery = async (Documents) => {
- const serverUrl = localStorage.getItem("baseUrl");
- const functionsUrl = `${serverUrl}functions/batchdocuments`;
+ const token = props.jwttoken
+ ? { jwttoken: props.jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const functionsUrl = `${localStorage.getItem(
+ "baseUrl"
+ )}functions/batchdocuments`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
- sessionToken: localStorage.getItem("accesstoken")
+ ...token
};
const params = { Documents: JSON.stringify(Documents) };
try {
@@ -362,6 +380,7 @@ const BulkSendUi = (props) => {
fieldIndex
)
}
+ jwttoken={props?.jwttoken}
/>
))}
diff --git a/apps/OpenSign/src/components/shared/fields/SelectSigners.js b/apps/OpenSign/src/components/shared/fields/SelectSigners.js
index b38cd71cd..b4d95db72 100644
--- a/apps/OpenSign/src/components/shared/fields/SelectSigners.js
+++ b/apps/OpenSign/src/components/shared/fields/SelectSigners.js
@@ -1,7 +1,7 @@
import React, { useState } from "react";
-import Parse from "parse";
import AsyncSelect from "react-select/async";
import { useTranslation } from "react-i18next";
+import axios from "axios";
const SelectSigners = (props) => {
const { t } = useTranslation();
@@ -31,17 +31,19 @@ const SelectSigners = (props) => {
const loadOptions = async (inputValue) => {
try {
- const currentUser = Parse.User.current();
- const contactbook = new Parse.Query("contracts_Contactbook");
- contactbook.equalTo(
- "CreatedBy",
- Parse.User.createWithoutData(currentUser.id)
- );
- if (inputValue.length > 1) {
- contactbook.matches("Name", new RegExp(inputValue, "i"));
- }
- contactbook.notEqualTo("IsDeleted", true);
- const contactRes = await contactbook.find();
+ const baseURL = localStorage.getItem("baseUrl");
+ const url = `${baseURL}functions/getsigners`;
+ const token = props?.jwttoken
+ ? { jwttoken: props?.jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ };
+ const search = inputValue;
+ const axiosRes = await axios.post(url, { search }, { headers });
+ const contactRes = axiosRes?.data?.result || [];
if (contactRes) {
const res = JSON.parse(JSON.stringify(contactRes));
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
diff --git a/apps/OpenSign/src/components/shared/fields/SuggestionInput.js b/apps/OpenSign/src/components/shared/fields/SuggestionInput.js
index 07fc11cbf..797515aec 100644
--- a/apps/OpenSign/src/components/shared/fields/SuggestionInput.js
+++ b/apps/OpenSign/src/components/shared/fields/SuggestionInput.js
@@ -25,7 +25,7 @@ const SuggestionInput = (props) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
(async () => {
- const res = await findContact(inputValue);
+ const res = await findContact(inputValue, props.jwttoken);
if (res?.length > 0) {
setSuggestions(res);
setShowSuggestions(true);
@@ -37,6 +37,7 @@ const SuggestionInput = (props) => {
}, 1000);
}
return () => clearTimeout(timer);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputValue]);
const handleInputChange = async (e) => {
diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js
index 5a86efe33..d5efe160d 100644
--- a/apps/OpenSign/src/constant/Utils.js
+++ b/apps/OpenSign/src/constant/Utils.js
@@ -34,7 +34,8 @@ export async function fetchSubscription(
extUserId,
contactObjId,
isGuestSign = false,
- isPublic = false
+ isPublic = false,
+ jwtToken
) {
try {
const Extand_Class = localStorage.getItem("Extand_Class");
@@ -48,10 +49,13 @@ export async function fetchSubscription(
}
const baseURL = localStorage.getItem("baseUrl");
const url = `${baseURL}functions/getsubscriptions`;
+ const token = jwtToken
+ ? { jwttoken: jwtToken }
+ : { sessionToken: localStorage.getItem("accesstoken") };
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
- sessionToken: localStorage.getItem("accesstoken")
+ ...token
};
const params = isGuestSign
? { contactId: contactObjId }
@@ -226,12 +230,25 @@ export const pdfNewWidthFun = (divRef) => {
};
//`contractUsers` function is used to get contract_User details
-export const contractUsers = async () => {
+export const contractUsers = async (jwttoken) => {
try {
- const userDetails = await Parse.Cloud.run("getUserDetails");
+ const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`;
+ const parseAppId = localStorage.getItem("parseAppId");
+ const accesstoken = localStorage.getItem("accesstoken");
+ const token = jwttoken
+ ? { jwttoken: jwttoken }
+ : { "X-Parse-Session-Token": accesstoken };
+ const headers = {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": parseAppId,
+ ...token
+ }
+ };
+ const userDetails = await axios.post(url, {}, headers);
let data = [];
- if (userDetails) {
- const json = JSON.parse(JSON.stringify(userDetails));
+ if (userDetails?.data?.result) {
+ const json = JSON.parse(JSON.stringify(userDetails.data.result));
data.push(json);
}
return data;
@@ -1762,14 +1779,17 @@ export const contactBook = async (objectId) => {
};
//function for getting document details from contract_Documents class
-export const contractDocument = async (documentId) => {
+export const contractDocument = async (documentId, JwtToken) => {
const data = { docId: documentId };
+ const token = JwtToken
+ ? { jwtToken: JwtToken }
+ : { sessionToken: localStorage.getItem("accesstoken") };
const documentDeatils = await axios
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
- sessionToken: localStorage.getItem("accesstoken")
+ ...token
}
})
.then((Listdata) => {
@@ -1969,20 +1989,28 @@ export const getAppLogo = async () => {
}
};
-export const getTenantDetails = async (objectId) => {
+export const getTenantDetails = async (objectId, jwttoken) => {
try {
- const tenantCreditsQuery = new Parse.Query("partners_Tenant");
- tenantCreditsQuery.equalTo("UserId", {
- __type: "Pointer",
- className: "_User",
- objectId: objectId
+ const url = `${localStorage.getItem("baseUrl")}functions/gettenant`;
+ const parseAppId = localStorage.getItem("parseAppId");
+ const accesstoken = localStorage.getItem("accesstoken");
+ const token = jwttoken
+ ? { jwttoken: jwttoken }
+ : { "X-Parse-Session-Token": accesstoken };
+ const data = jwttoken ? {} : { userId: objectId };
+ const res = await axios.post(url, data, {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": parseAppId,
+ ...token
+ }
});
- const res = await tenantCreditsQuery.first();
if (res) {
- const updateRes = JSON.parse(JSON.stringify(res));
+ const updateRes = JSON.parse(JSON.stringify(res.data.result));
return updateRes;
}
- } catch (e) {
+ } catch (err) {
+ console.log("err in gettenant", err);
return "user does not exist!";
}
};
@@ -2231,18 +2259,21 @@ export const handleDownloadCertificate = async (
}
}
};
-export async function findContact(value) {
+export async function findContact(value, jwttoken) {
try {
- const currentUser = Parse.User.current();
- const contactbook = new Parse.Query("contracts_Contactbook");
- contactbook.equalTo(
- "CreatedBy",
- Parse.User.createWithoutData(currentUser.id)
- );
- contactbook.notEqualTo("IsDeleted", true);
- contactbook.matches("Email", new RegExp(value, "i"));
-
- const contactRes = await contactbook.find();
+ const baseURL = localStorage.getItem("baseUrl");
+ const url = `${baseURL}functions/getsigners`;
+ const token = jwttoken
+ ? { jwttoken: jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ };
+ const searchEmail = value;
+ const axiosRes = await axios.post(url, { searchEmail }, { headers });
+ const contactRes = axiosRes?.data?.result || [];
if (contactRes) {
const res = JSON.parse(JSON.stringify(contactRes));
return res;
diff --git a/apps/OpenSign/src/pages/DraftTemplate.js b/apps/OpenSign/src/pages/DraftTemplate.js
new file mode 100644
index 000000000..593563780
--- /dev/null
+++ b/apps/OpenSign/src/pages/DraftTemplate.js
@@ -0,0 +1,1829 @@
+import React, { useEffect, useState, useRef } from "react";
+import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
+import { useParams } from "react-router-dom";
+import axios from "axios";
+import "../styles/signature.css";
+import { isEnableSubscription, isStaging } from "../constant/const";
+import { DndProvider } from "react-dnd";
+import { HTML5Backend } from "react-dnd-html5-backend";
+import { useDrag, useDrop } from "react-dnd";
+import WidgetComponent from "../components/pdf/WidgetComponent";
+import Tour from "reactour";
+import SignerListPlace from "../components/pdf/SignerListPlace";
+import Header from "../components/pdf/PdfHeader";
+import WidgetNameModal from "../components/pdf/WidgetNameModal";
+import {
+ pdfNewWidthFun,
+ contractUsers,
+ randomId,
+ addZIndex,
+ defaultWidthHeight,
+ addWidgetOptions,
+ textInputWidget,
+ radioButtonWidget,
+ fetchSubscription,
+ getContainerScale,
+ convertBase64ToFile,
+ rotatePdfPage,
+ onClickZoomOut,
+ onClickZoomIn,
+ handleRemoveWidgets,
+ handleRotateWarning,
+ color,
+ copytoData
+} from "../constant/Utils";
+import RenderPdf from "../components/pdf/RenderPdf";
+import "../styles/AddUser.css";
+import Title from "../components/Title";
+import EditTemplate from "../components/pdf/EditTemplate";
+import AddRoleModal from "../components/pdf/AddRoleModal";
+import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
+import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
+import { useSelector } from "react-redux";
+import PdfZoom from "../components/pdf/PdfZoom";
+import { useTranslation } from "react-i18next";
+import RotateAlert from "../components/RotateAlert";
+import ModalUi from "../primitives/ModalUi";
+import TourContentWithBtn from "../primitives/TourContentWithBtn";
+import HandleError from "../primitives/HandleError";
+import LoaderWithMsg from "../primitives/LoaderWithMsg";
+import LinkUserModal from "../primitives/LinkUserModal";
+import { jwtDecode } from "jwt-decode";
+import BulkSendUi from "../components/BulkSendUi";
+import Alert from "../primitives/Alert";
+import { RWebShare } from "react-web-share";
+
+const DraftTemplate = () => {
+ const { t } = useTranslation();
+ const isHeader = useSelector((state) => state.showHeader);
+ const { jwttoken } = useParams();
+ const signRef = useRef(null);
+ const dragRef = useRef(null);
+ const divRef = useRef(null);
+ const numPages = 1;
+ const isMobile = window.innerWidth < 767;
+ const [pdfDetails, setPdfDetails] = useState([]);
+ const [isMailSend, setIsMailSend] = useState(false);
+ const [allPages, setAllPages] = useState(null);
+ const [pageNumber, setPageNumber] = useState(1);
+ const [signBtnPosition, setSignBtnPosition] = useState([]);
+ const [xySignature, setXYSignature] = useState({});
+ const [dragKey, setDragKey] = useState();
+ const [signersdata, setSignersData] = useState([]);
+ const [signerPos, setSignerPos] = useState([]);
+ const [isSelectListId, setIsSelectId] = useState();
+ const [isSendAlert, setIsSendAlert] = useState(false);
+ const [isCreateDocModal, setIsCreateDocModal] = useState(false);
+ const [isSubscribe, setIsSubscribe] = useState(false);
+ const [isRotate, setIsRotate] = useState({ status: false, degree: 0 });
+ const [isLoading, setIsLoading] = useState({
+ isLoad: true,
+ message: t("loading-mssg")
+ });
+ const [handleError, setHandleError] = useState();
+ const [pdfNewWidth, setPdfNewWidth] = useState();
+ const [templateTour, setTemplateTour] = useState(true);
+ const [checkTourStatus, setCheckTourStatus] = useState(false);
+ const [tourStatus, setTourStatus] = useState([]);
+ const [signerUserId, setSignerUserId] = useState();
+ const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
+ const [containerWH, setContainerWH] = useState();
+ const [isShowEmail, setIsShowEmail] = useState(false);
+ const [selectedEmail, setSelectedEmail] = useState(false);
+ const [isResize, setIsResize] = useState(false);
+ const [isSigners, setIsSigners] = useState(false);
+ const [zIndex, setZIndex] = useState(1);
+ const [showDropdown, setShowDropdown] = useState(false);
+ const [widgetType, setWidgetType] = useState("");
+ const [isRadio, setIsRadio] = useState(false);
+ const [blockColor, setBlockColor] = useState("");
+ const [selectWidgetId, setSelectWidgetId] = useState("");
+ const [isNameModal, setIsNameModal] = useState(false);
+ const [isTextSetting, setIsTextSetting] = useState(false);
+ const [pdfLoad, setPdfLoad] = useState(false);
+ const [pdfRotateBase64, setPdfRotatese64] = useState("");
+ const [uniqueId, setUniqueId] = useState("");
+ const [isModalRole, setIsModalRole] = useState(false);
+ const [roleName, setRoleName] = useState("");
+ const [isAddUser, setIsAddUser] = useState({});
+ const [isEditTemplate, setIsEditTemplate] = useState(false);
+ const [isPageCopy, setIsPageCopy] = useState(false);
+ const [signKey, setSignKey] = useState();
+ const [IsReceipent, setIsReceipent] = useState(true);
+ const [isDontShow, setIsDontShow] = useState(false);
+ const [isDragging, setIsDragging] = useState(false);
+ const [currWidgetsDetails, setCurrWidgetsDetails] = useState([]);
+ const [isCheckbox, setIsCheckbox] = useState(false);
+ const [widgetName, setWidgetName] = useState(false);
+ const [isAddRole, setIsAddRole] = useState(false);
+ const [fontSize, setFontSize] = useState();
+ const [fontColor, setFontColor] = useState();
+ const [zoomPercent, setZoomPercent] = useState(0);
+ const [scale, setScale] = useState(1);
+ const [isSubscriptionExpired, setIsSubscriptionExpired] = useState(false);
+ const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
+ const [isPublic, setIsPublic] = useState("");
+ const [copied, setCopied] = useState(false);
+ // const [isPublicErr, setIsPublicError] = useState(false);
+ const [isAllRoleLinked, setIsAllRolelinked] = useState(false);
+ const [, drop] = useDrop({
+ accept: "BOX",
+ drop: (item, monitor) => addPositionOfSignature(item, monitor),
+ collect: (monitor) => ({ isOver: !!monitor.isOver() })
+ });
+ const [{ isDragSign }, dragSignature] = useDrag({
+ type: "BOX",
+ item: { type: "BOX", id: 1, text: "signature" },
+ collect: (monitor) => ({ isDragSign: !!monitor.isDragging() })
+ });
+ const [{ isDragStamp }, dragStamp] = useDrag({
+ type: "BOX",
+ item: { type: "BOX", id: 2, text: "stamp" },
+ collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() })
+ });
+ const decode = jwtDecode(jwttoken);
+ const templateId = decode?.template_id;
+ useEffect(() => {
+ fetchTemplate();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ useEffect(() => {
+ const updateSize = () => {
+ if (divRef.current) {
+ const pdfWidth = pdfNewWidthFun(divRef);
+ setPdfNewWidth(pdfWidth);
+ setContainerWH({
+ width: divRef.current.offsetWidth,
+ height: divRef.current.offsetHeight
+ });
+ setScale(1);
+ setZoomPercent(0);
+ }
+ };
+
+ // Use setTimeout to wait for the transition to complete
+ const timer = setTimeout(updateSize, 100); // match the transition duration
+
+ return () => clearTimeout(timer);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [divRef.current, isHeader]);
+
+ const handleNavigation = () => {
+ // navigate("/subscription");
+ setIsSubscriptionExpired(true);
+ };
+ async function checkIsSubscribed() {
+ const res = await fetchSubscription("", "", false, false, jwttoken);
+ const plan = res.plan;
+ const billingDate = res.billingDate;
+ if (plan === "freeplan") {
+ return true;
+ } else if (billingDate) {
+ if (new Date(billingDate) > new Date()) {
+ setIsSubscribe(true);
+ return true;
+ } else {
+ handleNavigation(plan);
+ }
+ } else {
+ handleNavigation(plan);
+ }
+ }
+ // `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
+ const fetchTemplate = async () => {
+ try {
+ const params = { templateId: templateId };
+ const token = jwttoken
+ ? { jwttoken: jwttoken }
+ : { sessionToken: localStorage.getItem("accesstoken") };
+ const templateDeatils = await axios.post(
+ `${localStorage.getItem("baseUrl")}functions/getTemplate`,
+ params,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ }
+ }
+ );
+ const documentData =
+ templateDeatils.data && templateDeatils.data.result
+ ? [templateDeatils.data.result]
+ : [];
+ if (templateDeatils?.data?.result?.IsPublic !== undefined) {
+ if (templateDeatils?.data?.result?.IsPublic === true) {
+ setIsPublic("true");
+ } else {
+ setIsPublic("false");
+ }
+ } else {
+ setIsPublic("undefined");
+ }
+
+ if (documentData && documentData.length > 0) {
+ if (isEnableSubscription) {
+ checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
+ }
+ setPdfDetails(documentData);
+ setIsSigners(true);
+ if (documentData[0].Signers && documentData[0].Signers.length > 0) {
+ setIsSelectId(0);
+ if (
+ documentData[0].Placeholders &&
+ documentData[0].Placeholders.length > 0
+ ) {
+ setSignerPos(documentData[0].Placeholders);
+ let signers = [...documentData[0].Signers];
+ let updatedSigners = documentData[0].Placeholders.map((x) => {
+ let matchingSigner = signers.find(
+ (y) => x.signerObjId && x.signerObjId === y.objectId
+ );
+
+ if (matchingSigner) {
+ return {
+ ...matchingSigner,
+ Role: x.Role ? x.Role : matchingSigner.Role,
+ Id: x.Id,
+ blockColor: x.blockColor
+ };
+ } else {
+ return { Role: x.Role, Id: x.Id, blockColor: x.blockColor };
+ }
+ });
+ setSignersData(updatedSigners);
+ setUniqueId(updatedSigners[0].Id);
+ setBlockColor(updatedSigners[0].blockColor);
+ } else {
+ const updatedSigners = documentData[0].Signers.map((x, index) => ({
+ ...x,
+ Id: randomId(),
+ Role: "User " + (index + 1)
+ }));
+ setSignersData(updatedSigners);
+ setUniqueId(updatedSigners[0].Id);
+ setBlockColor(updatedSigners[0].blockColor);
+ }
+ } else {
+ setRoleName("User 1");
+ if (
+ documentData[0].Placeholders &&
+ documentData[0].Placeholders.length > 0
+ ) {
+ let updatedSigners = documentData[0].Placeholders.map((x) => {
+ return { Role: x.Role, Id: x.Id, blockColor: x.blockColor };
+ });
+ setSignerPos(documentData[0].Placeholders);
+ setUniqueId(updatedSigners[0].Id);
+ setSignersData(updatedSigners);
+ setIsSelectId(0);
+ setBlockColor(updatedSigners[0].blockColor);
+ }
+ }
+ } else if (
+ documentData === "Error: Something went wrong!" ||
+ (documentData.result && documentData.result.error)
+ ) {
+ setHandleError(t("something-went-wrong-mssg"));
+ setIsLoading({ isLoad: false });
+ } else {
+ setHandleError(t("no-data-avaliable"));
+ setIsLoading({ isLoad: false });
+ }
+ } catch (err) {
+ console.log("err ", err);
+ if (err?.response?.data?.code === 101) {
+ setHandleError(t("no-data-avaliable"));
+ } else {
+ setHandleError(t("something-went-wrong-mssg"));
+ }
+ }
+ const res = await contractUsers(jwttoken);
+ if (res[0] && res.length) {
+ setSignerUserId(res[0].objectId);
+ const tourstatus = res[0].TourStatus && res[0].TourStatus;
+ if (tourstatus && tourstatus.length > 0) {
+ setTourStatus(tourstatus);
+ const checkTourRecipients = tourstatus.filter(
+ (data) => data.templateTour
+ );
+ if (checkTourRecipients && checkTourRecipients.length > 0) {
+ setCheckTourStatus(checkTourRecipients[0].templateTour);
+ }
+ }
+ setIsLoading({ isLoad: false });
+ } else if (res === "Error: Something went wrong!") {
+ setHandleError(t("something-went-wrong-mssg"));
+ setIsLoading({ isLoad: false });
+ } else if (res.length === 0) {
+ setHandleError(t("no-data-avaliable"));
+ setIsLoading({ isLoad: false });
+ }
+ };
+ //function for setting position after drop signature button over pdf
+ const addPositionOfSignature = (item, monitor) => {
+ if (item && item.text) {
+ setWidgetName(item.text);
+ }
+ getSignerPos(item, monitor);
+ };
+
+ // `getSignerPos` is used to get placeholder position when user place it and save it in array
+ const getSignerPos = (item, monitor) => {
+ if (uniqueId) {
+ const signer = signersdata.find((x) => x.Id === uniqueId);
+ if (signer) {
+ const posZIndex = zIndex + 1;
+ setZIndex(posZIndex);
+ const containerScale = getContainerScale(
+ pdfOriginalWH,
+ pageNumber,
+ containerWH
+ );
+ const key = randomId();
+ const dragTypeValue = item?.text ? item.text : monitor.type;
+ const widgetWidth = defaultWidthHeight(dragTypeValue).width;
+ const widgetHeight = defaultWidthHeight(dragTypeValue).height;
+ let dropData = [],
+ currentPagePosition;
+ let placeHolder;
+ if (item === "onclick") {
+ // `getBoundingClientRect()` is used to get accurate measurement height of the div
+ const divHeight = divRef.current.getBoundingClientRect().height;
+ const dropObj = {
+ //onclick put placeholder center on pdf
+ xPosition: widgetWidth / 4 + containerWH.width / 2,
+ yPosition: widgetHeight + divHeight / 2,
+ isStamp:
+ (dragTypeValue === "stamp" || dragTypeValue === "image") && true,
+ key: key,
+ scale: containerScale,
+ zIndex: posZIndex,
+ type: dragTypeValue,
+ options: addWidgetOptions(dragTypeValue),
+ Width: widgetWidth / (containerScale * scale),
+ Height: widgetHeight / (containerScale * scale)
+ };
+ dropData.push(dropObj);
+ placeHolder = { pageNumber: pageNumber, pos: dropData };
+ } else {
+ const offset = monitor.getClientOffset();
+ //adding and updating drop position in array when user drop signature button in div
+ const containerRect = document
+ .getElementById("container")
+ .getBoundingClientRect();
+ const x = offset.x - containerRect.left;
+ const y = offset.y - containerRect.top;
+ const getXPosition = signBtnPosition[0]
+ ? x - signBtnPosition[0].xPos
+ : x;
+ const getYPosition = signBtnPosition[0]
+ ? y - signBtnPosition[0].yPos
+ : y;
+ const dropObj = {
+ xPosition: getXPosition / (containerScale * scale),
+ yPosition: getYPosition / (containerScale * scale),
+ isStamp:
+ (dragTypeValue === "stamp" || dragTypeValue === "image") && true,
+ key: key,
+ scale: containerScale,
+ // isMobile: isMobile,
+ zIndex: posZIndex,
+ type: item.text,
+ options: addWidgetOptions(dragTypeValue),
+ Width: widgetWidth / (containerScale * scale),
+ Height: widgetHeight / (containerScale * scale)
+ };
+
+ dropData.push(dropObj);
+ placeHolder = { pageNumber: pageNumber, pos: dropData };
+ }
+ let filterSignerPos = signerPos.find((data) => data.Id === uniqueId);
+ const getPlaceHolder = filterSignerPos?.placeHolder;
+ if (getPlaceHolder) {
+ //checking exist placeholder on same page
+ currentPagePosition = getPlaceHolder.find(
+ (data) => data.pageNumber === pageNumber
+ );
+ }
+ //checking current page has already some placeholders then update that placeholder and add upcoming placehoder position
+ if (getPlaceHolder && currentPagePosition) {
+ const updatePlace = getPlaceHolder.filter(
+ (data) => data.pageNumber !== pageNumber
+ );
+ const getPos = currentPagePosition?.pos;
+ const newSignPos = getPos.concat(dropData);
+ let xyPos = { pageNumber: pageNumber, pos: newSignPos };
+ updatePlace.push(xyPos);
+ const updatesignerPos = signerPos.map((x) =>
+ x.Id === uniqueId ? { ...x, placeHolder: updatePlace } : x
+ );
+ setSignerPos(updatesignerPos);
+ } else {
+ //else condition to add placeholder widgets on multiple page first time
+ const updatesignerPos = signerPos.map((x) =>
+ x.Id === uniqueId && x?.placeHolder
+ ? { ...x, placeHolder: [...x.placeHolder, placeHolder] }
+ : x.Id === uniqueId
+ ? { ...x, placeHolder: [placeHolder] }
+ : x
+ );
+ setSignerPos(updatesignerPos);
+ }
+
+ if (dragTypeValue === "dropdown") {
+ setShowDropdown(true);
+ } else if (dragTypeValue === "checkbox") {
+ setIsCheckbox(true);
+ } else if (dragTypeValue === radioButtonWidget) {
+ setIsRadio(true);
+ } else if (
+ [textInputWidget, "name", "company", "job title", "email"].includes(
+ dragTypeValue
+ )
+ ) {
+ setFontSize(12);
+ setFontColor("black");
+ }
+ setCurrWidgetsDetails({});
+ setWidgetType(dragTypeValue);
+ setSignKey(key);
+ setSelectWidgetId(key);
+ setIsMailSend(false);
+ } else {
+ setIsReceipent(false);
+ }
+ } else {
+ setIsAddRole(true);
+ }
+ };
+
+ const tourAddRole = [
+ {
+ selector: '[data-tut="reactourAddbtn"]',
+ content: t("add-user-template"),
+ position: "top",
+ style: { fontSize: "13px" }
+ }
+ ];
+
+ //function for get pdf page details
+ const pageDetails = async (pdf) => {
+ let pdfWHObj = [];
+ const totalPages = pdf?.numPages;
+ for (let index = 0; index < totalPages; index++) {
+ const getPage = await pdf.getPage(index + 1);
+ const scale = 1;
+ const { width, height } = getPage.getViewport({ scale });
+ pdfWHObj.push({ pageNumber: index + 1, width, height });
+ }
+ setPdfOriginalWH(pdfWHObj);
+ setPdfLoad(true);
+ };
+ //function for save x and y position and show signature tab on that position
+ const handleTabDrag = (key) => {
+ setDragKey(key);
+ setIsDragging(true);
+ };
+
+ //function for set and update x and y postion after drag and drop signature tab
+ const handleStop = (event, dragElement, signerId, key) => {
+ setFontColor();
+ setFontSize();
+ if (!isResize && isDragging) {
+ const dataNewPlace = addZIndex(signerPos, key, setZIndex);
+ let updateSignPos = [...signerPos];
+ updateSignPos.splice(0, updateSignPos.length, ...dataNewPlace);
+ const signId = signerId; //? signerId : signerObjId;
+ const keyValue = key ? key : dragKey;
+ const containerScale = getContainerScale(
+ pdfOriginalWH,
+ pageNumber,
+ containerWH
+ );
+ if (keyValue >= 0) {
+ const filterSignerPos = updateSignPos.filter(
+ (data) => data.Id === signId
+ );
+
+ if (filterSignerPos.length > 0) {
+ const getPlaceHolder = filterSignerPos[0].placeHolder;
+
+ const getPageNumer = getPlaceHolder.filter(
+ (data) => data.pageNumber === pageNumber
+ );
+
+ if (getPageNumer.length > 0) {
+ const getXYdata = getPageNumer[0].pos;
+ const getPosData = getXYdata;
+ const addSignPos = getPosData.map((url) => {
+ if (url.key === keyValue) {
+ return {
+ ...url,
+ xPosition: dragElement.x / (containerScale * scale),
+ yPosition: dragElement.y / (containerScale * scale)
+ };
+ }
+ return url;
+ });
+
+ const newUpdateSignPos = getPlaceHolder.map((obj) => {
+ if (obj.pageNumber === pageNumber) {
+ return { ...obj, pos: addSignPos };
+ }
+ return obj;
+ });
+ const newUpdateSigner = updateSignPos.map((obj) => {
+ if (obj.Id === signId) {
+ return { ...obj, placeHolder: newUpdateSignPos };
+ }
+ return obj;
+ });
+ setSignerPos(newUpdateSigner);
+ }
+ }
+ }
+ }
+ setIsMailSend(false);
+ setTimeout(() => setIsDragging(false), 200);
+ };
+ //function for delete signature block
+ const handleDeleteSign = (key, Id) => {
+ const updateData = [];
+ const filterSignerPos = signerPos.filter((data) => data.Id === Id);
+
+ if (filterSignerPos.length > 0) {
+ const getPlaceHolder = filterSignerPos[0].placeHolder;
+
+ const getPageNumer = getPlaceHolder.filter(
+ (data) => data.pageNumber === pageNumber
+ );
+
+ if (getPageNumer.length > 0) {
+ const getXYdata = getPageNumer[0].pos.filter(
+ (data) => data.key !== key
+ );
+
+ if (getXYdata.length > 0) {
+ updateData.push(getXYdata);
+ const newUpdatePos = getPlaceHolder.map((obj) => {
+ if (obj.pageNumber === pageNumber) {
+ return { ...obj, pos: updateData[0] };
+ }
+ return obj;
+ });
+
+ const newUpdateSigner = signerPos.map((obj) => {
+ if (obj.Id === Id) {
+ return { ...obj, placeHolder: newUpdatePos };
+ }
+ return obj;
+ });
+
+ setSignerPos(newUpdateSigner);
+ } else {
+ const getRemainPage = filterSignerPos[0].placeHolder.filter(
+ (data) => data.pageNumber !== pageNumber
+ );
+ //condition to check placeholder length is greater than 1 do not need to remove whole placeholder
+ //array only resove particular widgets
+ if (getRemainPage && getRemainPage.length > 0) {
+ const newUpdatePos = filterSignerPos.map((obj) => {
+ if (obj.Id === Id) {
+ return { ...obj, placeHolder: getRemainPage };
+ }
+ return obj;
+ });
+ let signerupdate = [];
+ signerupdate = signerPos.filter((data) => data.Id !== Id);
+ signerupdate.push(newUpdatePos[0]);
+
+ setSignerPos(signerupdate);
+ } else {
+ const updatedData = signerPos.map((item) => {
+ if (item.Id === Id) {
+ // Create a copy of the item object and delete the placeHolder field
+ const updatedItem = { ...item };
+ delete updatedItem.placeHolder;
+ return updatedItem;
+ }
+ return item;
+ });
+ setSignerPos(updatedData);
+ }
+ }
+ }
+ }
+ };
+
+ //function for change page
+ function changePage(offset) {
+ setSignBtnPosition([]);
+ setPageNumber((prevPageNumber) => prevPageNumber + offset);
+ }
+
+ //function for capture position on hover or touch widgets
+ const handleDivClick = (e) => {
+ const isTouchEvent = e.type.startsWith("touch");
+ const divRect = e.currentTarget.getBoundingClientRect();
+ let mouseX, mouseY;
+ if (isTouchEvent) {
+ const touch = e.touches[0]; // Get the first touch point
+ mouseX = touch.clientX - divRect.left;
+ mouseY = touch.clientY - divRect.top;
+ setSignBtnPosition([{ xPos: mouseX, yPos: mouseY }]);
+ } else {
+ mouseX = e.clientX - divRect.left;
+ mouseY = e.clientY - divRect.top;
+ const xyPosition = { xPos: mouseX, yPos: mouseY };
+ setXYSignature(xyPosition);
+ }
+ };
+
+ //function for capture position of x and y on hover signature button last position
+ const handleMouseLeave = () => setSignBtnPosition([xySignature]);
+ const alertSendEmail = async () => {
+ const isPlaceholderExist = signerPos.every((data) => data.placeHolder);
+ if (isPlaceholderExist) {
+ handleSaveTemplate();
+ } else {
+ setIsSendAlert(true);
+ }
+ };
+
+ // `saveTemplate` is used to update template on server using savetemplate endpoint
+ const saveTemplate = async () => {
+ if (signersdata?.length) {
+ const loadObj = { isLoad: true, message: t("loading-mssg") };
+ setIsLoading(loadObj);
+ setIsSendAlert(false);
+ let signers = [];
+ if (signersdata?.length > 0) {
+ signersdata.forEach((x) => {
+ if (x.objectId) {
+ const obj = {
+ __type: "Pointer",
+ className: "contracts_Contactbook",
+ objectId: x.objectId
+ };
+ signers.push(obj);
+ }
+ });
+ }
+ let pdfUrl = pdfDetails[0]?.URL;
+ if (pdfRotateBase64) {
+ try {
+ pdfUrl = await convertBase64ToFile(
+ pdfDetails[0].Name,
+ pdfRotateBase64
+ );
+ } catch (e) {
+ console.log("error to convertBase64ToFile", e);
+ }
+ }
+ try {
+ const data = {
+ templateId: templateId,
+ Placeholders: signerPos,
+ Signers: signers,
+ URL: pdfUrl,
+ Name: pdfDetails[0]?.Name || "",
+ Note: pdfDetails[0]?.Note || "",
+ Description: pdfDetails[0]?.Description || "",
+ SendinOrder: pdfDetails[0]?.SendinOrder || false,
+ AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
+ RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
+ NextReminderDate: pdfDetails[0]?.NextReminderDate,
+ IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
+ IsTourEnabled: pdfDetails[0]?.IsTourEnabled === true ? true : false
+ };
+ const baseURL = localStorage.getItem("baseUrl");
+ const url = `${baseURL}functions/savetemplate`;
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ jwttoken: jwttoken
+ };
+ await axios.post(url, data, { headers });
+ // console.log("savetemplate", res.data);
+ const isSignersLinked =
+ signerPos?.some((x) => !x.signerObjId) === false;
+ setIsAllRolelinked(isSignersLinked);
+ setIsCreateDocModal(true);
+ setIsLoading({ isLoad: false });
+ } catch (e) {
+ setIsLoading(false);
+ alert(t("something-went-wrong-mssg"));
+ console.log("error", e);
+ }
+ } else {
+ setIsReceipent(false);
+ }
+ };
+ // `handleSaveTemplate` is used to save template based of validation
+ const handleSaveTemplate = async () => {
+ const isPublicTemplate = isPublic === "true";
+ if (isPublicTemplate) {
+ const unlinkSignerIndex = signerPos?.findIndex((x) => !x?.signerObjId);
+ const unlinkSigners = signerPos?.filter((x) => !x?.signerObjId)?.length; // unLink with role
+ if (unlinkSignerIndex === 0 && unlinkSigners === 1) {
+ await saveTemplate();
+ } else {
+ // setIsPublicError(true);
+ alert(
+ "Only one signer without a role is allowed, and it should be at the first index."
+ );
+ }
+ } else {
+ await saveTemplate();
+ }
+ };
+
+ const handleDontShow = (isChecked) => setIsDontShow(isChecked);
+
+ //here you can add your messages in content and selector is key of particular steps
+ const tourConfig = [
+ {
+ selector: '[data-tut="reactourAddbtn"]',
+ content: () => (
+
+ ),
+ position: "top",
+ observe: '[data-tut="reactourAddbtn--observe"]',
+ style: { fontSize: "13px" }
+ },
+ {
+ selector: '[data-tut="reactourFirst"]',
+ content: () => (
+
+ ),
+ position: "top",
+ style: { fontSize: "13px" },
+ action: () => handleCloseRoleModal()
+ },
+ {
+ selector: '[data-tut="addWidgets"]',
+ content: () => (
+
+ ),
+ position: "top",
+ style: { fontSize: "13px" }
+ },
+ {
+ selector: '[data-tut="reactourThird"]',
+ content: () => (
+
+ ),
+ position: "top",
+ style: { fontSize: "13px" }
+ },
+ {
+ selector: '[data-tut="headerArea"]',
+ content: () => (
+
+ ),
+ position: "top",
+ style: { fontSize: "13px" }
+ }
+ ];
+
+ //function for update TourStatus
+ const closeTour = async () => {
+ setTemplateTour(false);
+ if (isDontShow) {
+ let updatedTourStatus = [];
+ if (tourStatus.length > 0) {
+ updatedTourStatus = [...tourStatus];
+ const templatetourIndex = tourStatus.findIndex(
+ (obj) => obj["templateTour"] === false || obj["templateTour"] === true
+ );
+ if (templatetourIndex !== -1) {
+ updatedTourStatus[templatetourIndex] = { templateTour: true };
+ } else {
+ updatedTourStatus.push({ templateTour: true });
+ }
+ } else {
+ updatedTourStatus = [{ templateTour: true }];
+ }
+ try {
+ const url = `${localStorage.getItem(
+ "baseUrl"
+ )}functions/updatetourstatus`;
+ const parseAppId = localStorage.getItem("parseAppId");
+ const accesstoken = localStorage.getItem("accesstoken");
+ const token = jwttoken
+ ? { jwttoken: jwttoken }
+ : { "X-Parse-Session-Token": accesstoken };
+ const data = { TourStatus: updatedTourStatus, ExtUserId: signerUserId };
+ await axios.post(url, data, {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": parseAppId,
+ ...token
+ }
+ });
+ } catch (err) {
+ console.log("axios err while update tourstatus", err);
+ }
+ }
+ };
+
+ // `handleAddSigner` is used to open Add Role Modal
+ const handleAddSigner = () => {
+ setIsModalRole(true);
+ setRoleName("");
+ };
+
+ // `handleAddRole` function is called when use click on add button in addRole modal
+ // save Role in entry in signerList and user
+ const handleAddRole = (e) => {
+ e.preventDefault();
+ const count = signersdata.length > 0 ? signersdata.length + 1 : 1;
+ const Id = randomId();
+ const index = signersdata.length;
+ const obj = {
+ Role: roleName || "User " + count,
+ Id: Id,
+ blockColor: color[index]
+ };
+ setSignersData((prevArr) => [...prevArr, obj]);
+ const signerPosObj = {
+ signerPtr: {},
+ signerObjId: "",
+ blockColor: color[index],
+ Role: roleName || "User " + count,
+ Id: Id
+ };
+ setSignerPos((prev) => [...prev, signerPosObj]);
+ setIsModalRole(false);
+ setRoleName("");
+ setUniqueId(Id);
+ setBlockColor(color[index]);
+ setIsSelectId(index);
+ setIsMailSend(false);
+ };
+ // `handleDeleteUser` function is used to delete record and placeholder when user click on delete which is place next user name in recipients list
+ const handleDeleteUser = (Id) => {
+ const updateSigner = signersdata
+ .filter((x) => x.Id !== Id)
+ .map((x, i) => ({ ...x, blockColor: color[i] }));
+ setSignersData(updateSigner);
+ const updatePlaceholderUser = signerPos
+ .filter((x) => x.Id !== Id)
+ .map((x, i) => ({ ...x, blockColor: color[i] }));
+ const index = signersdata.findIndex((x) => x.Id === Id);
+ if (index === signersdata.length - 1) {
+ setUniqueId(updateSigner[updateSigner.length - 1]?.Id || "");
+ setIsSelectId(index - 1 || 0);
+ setBlockColor(color[index - 1 || 0]);
+ } else {
+ setUniqueId(updateSigner[index]?.Id || "");
+ setIsSelectId(index);
+ setBlockColor(color[index]);
+ }
+
+ setSignerPos(updatePlaceholderUser);
+ setIsMailSend(false);
+ };
+
+ // `handleLinkUser` is used to open Add/Choose Signer Modal when user can link existing or new User with placeholder
+ // and update entry in signersList
+ const handleLinkUser = (id) => {
+ setIsAddUser({ [id]: true });
+ };
+ // `handleAddUser` is used to adduser
+ const handleAddUser = (data) => {
+ const signerPtr = {
+ __type: "Pointer",
+ className: "contracts_Contactbook",
+ objectId: data.objectId
+ };
+
+ const updatePlaceHolder = signerPos.map((x) => {
+ if (x.Id === uniqueId) {
+ return { ...x, signerPtr: signerPtr, signerObjId: data.objectId };
+ }
+ return { ...x };
+ });
+ setSignerPos(updatePlaceHolder);
+
+ const updateSigner = signersdata.map((x) => {
+ if (x.Id === uniqueId) {
+ return { ...x, ...data, className: "contracts_Contactbook" };
+ }
+ return { ...x };
+ });
+ setSignersData(updateSigner);
+ setIsMailSend(false);
+ const index = signersdata.findIndex((x) => x.Id === uniqueId);
+ setIsSelectId(index);
+ };
+
+ // `closePopup` is used to close Add/Choose signer modal
+ const closePopup = () => setIsAddUser({});
+
+ // `handleRoleChange` function is call when user update Role name from recipients list
+ const handleRoleChange = (event, roleId) => {
+ // Update the role when the content changes
+ const updatedRoles = signersdata.map((role) =>
+ role.Id === roleId ? { ...role, Role: event.target.value } : role
+ );
+ setSignersData(updatedRoles);
+ const updatedPlaceholder = signerPos.map((role) =>
+ role.Id === roleId ? { ...role, Role: event.target.value } : role
+ );
+ setSignerPos(updatedPlaceholder);
+ setIsMailSend(false);
+ };
+
+ // `handleOnBlur` function is call when user click outside input box
+ const handleOnBlur = (updateRole, roleId) => {
+ // Update the role when the content changes
+ if (!updateRole) {
+ const updatedRoles = signersdata.map((role) =>
+ role.Id === roleId ? { ...role, Role: roleName } : role
+ );
+ setSignersData(updatedRoles);
+ const updatedPlaceholder = signerPos?.map((role) =>
+ role.Id === roleId ? { ...role, Role: roleName } : role
+ );
+ setSignerPos(updatedPlaceholder);
+ }
+ };
+
+ const handleEditTemplateModal = () => setIsEditTemplate(!isEditTemplate);
+
+ const handleEditTemplateForm = (data) => {
+ setIsEditTemplate(false);
+ const updateTemplate = pdfDetails.map((x) => {
+ return { ...x, ...data };
+ });
+ setPdfDetails(updateTemplate);
+ setIsMailSend(false);
+ };
+
+ const handleCloseRoleModal = () => {
+ setIsModalRole(false);
+ };
+
+ const handleSaveWidgetsOptions = (
+ dropdownName,
+ dropdownOptions,
+ minCount,
+ maxCount,
+ isReadOnly,
+ addOption,
+ deleteOption,
+ status,
+ defaultValue,
+ isHideLabel
+ ) => {
+ const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
+ if (filterSignerPos.length > 0) {
+ const getPlaceHolder = filterSignerPos[0].placeHolder;
+
+ const getPageNumer = getPlaceHolder.filter(
+ (data) => data.pageNumber === pageNumber
+ );
+
+ if (getPageNumer.length > 0) {
+ const getXYdata = getPageNumer[0].pos;
+
+ const getPosData = getXYdata;
+ const addSignPos = getPosData.map((position) => {
+ if (position.key === signKey) {
+ if (widgetType === radioButtonWidget) {
+ if (addOption) {
+ return {
+ ...position,
+ Height: position.Height
+ ? position.Height + 15
+ : defaultWidthHeight(widgetType).height + 15
+ };
+ } else if (deleteOption) {
+ return {
+ ...position,
+ Height: position.Height
+ ? position.Height - 15
+ : defaultWidthHeight(widgetType).height - 15
+ };
+ } else {
+ return {
+ ...position,
+ options: {
+ ...position.options,
+ name: dropdownName,
+ values: dropdownOptions,
+ status: status,
+ defaultValue: defaultValue,
+ isReadOnly: isReadOnly || false,
+ isHideLabel: isHideLabel || false,
+ fontSize:
+ fontSize || currWidgetsDetails?.options?.fontSize || "12",
+ fontColor:
+ fontColor ||
+ currWidgetsDetails?.options?.fontColor ||
+ "black"
+ }
+ };
+ }
+ } else if (widgetType === "checkbox") {
+ if (addOption) {
+ return {
+ ...position,
+ Height: position.Height
+ ? position.Height + 15
+ : defaultWidthHeight(widgetType).height + 15
+ };
+ } else if (deleteOption) {
+ return {
+ ...position,
+ Height: position.Height
+ ? position.Height - 15
+ : defaultWidthHeight(widgetType).height - 15
+ };
+ } else {
+ return {
+ ...position,
+ options: {
+ ...position.options,
+ name: dropdownName,
+ values: dropdownOptions,
+ validation: {
+ minRequiredCount: minCount,
+ maxRequiredCount: maxCount
+ },
+ isReadOnly: isReadOnly || false,
+ defaultValue: defaultValue,
+ isHideLabel: isHideLabel || false,
+ fontSize:
+ fontSize || currWidgetsDetails?.options?.fontSize || "12",
+ fontColor:
+ fontColor ||
+ currWidgetsDetails?.options?.fontColor ||
+ "black"
+ }
+ };
+ }
+ } else {
+ return {
+ ...position,
+ options: {
+ ...position.options,
+ name: dropdownName,
+ status: status,
+ values: dropdownOptions,
+ defaultValue: defaultValue,
+ fontSize:
+ fontSize || currWidgetsDetails?.options?.fontSize || "12",
+ fontColor:
+ fontColor ||
+ currWidgetsDetails?.options?.fontColor ||
+ "black"
+ }
+ };
+ }
+ }
+ return position;
+ });
+
+ const newUpdateSignPos = getPlaceHolder.map((obj) => {
+ if (obj.pageNumber === pageNumber) {
+ return { ...obj, pos: addSignPos };
+ }
+ return obj;
+ });
+ const newUpdateSigner = signerPos.map((obj) => {
+ if (obj.Id === uniqueId) {
+ return { ...obj, placeHolder: newUpdateSignPos };
+ }
+ return obj;
+ });
+
+ setSignerPos(newUpdateSigner);
+ if (!addOption && !deleteOption) {
+ handleNameModal();
+ }
+ }
+ }
+ setFontSize();
+ setFontColor();
+ };
+
+ const handleWidgetdefaultdata = (defaultdata) => {
+ const options = ["email", "number", "text"];
+ let inputype;
+ if (defaultdata.textvalidate) {
+ inputype = options.includes(defaultdata.textvalidate)
+ ? defaultdata.textvalidate
+ : "regex";
+ }
+
+ const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
+ if (filterSignerPos.length > 0) {
+ const getPlaceHolder = filterSignerPos[0].placeHolder;
+
+ const getPageNumer = getPlaceHolder.filter(
+ (data) => data.pageNumber === pageNumber
+ );
+
+ if (getPageNumer.length > 0) {
+ const getXYdata = getPageNumer[0].pos;
+ const getPosData = getXYdata;
+ const addSignPos = getPosData.map((position) => {
+ if (position.key === signKey) {
+ if (position.type === textInputWidget) {
+ return {
+ ...position,
+ options: {
+ ...position.options,
+ name: defaultdata?.name || "text",
+ status: defaultdata?.status || "required",
+ hint: defaultdata?.hint || "",
+ defaultValue: defaultdata?.defaultValue || "",
+ validation:
+ isSubscribe && inputype
+ ? {
+ type: inputype,
+ pattern:
+ inputype === "regex" ? defaultdata.textvalidate : ""
+ }
+ : {},
+ fontSize:
+ fontSize || currWidgetsDetails?.options?.fontSize || "12",
+ fontColor:
+ fontColor ||
+ currWidgetsDetails?.options?.fontColor ||
+ "black"
+ }
+ };
+ } else {
+ return {
+ ...position,
+ options: {
+ ...position.options,
+ name: defaultdata.name,
+ status: defaultdata.status,
+ defaultValue: defaultdata.defaultValue,
+ fontSize:
+ fontSize || currWidgetsDetails?.options?.fontSize || "12",
+ fontColor:
+ fontColor ||
+ currWidgetsDetails?.options?.fontColor ||
+ "black"
+ }
+ };
+ }
+ }
+ return position;
+ });
+
+ const newUpdateSignPos = getPlaceHolder.map((obj) => {
+ if (obj.pageNumber === pageNumber) {
+ return { ...obj, pos: addSignPos };
+ }
+ return obj;
+ });
+ const newUpdateSigner = signerPos.map((obj) => {
+ if (obj.Id === uniqueId) {
+ return { ...obj, placeHolder: newUpdateSignPos };
+ }
+ return obj;
+ });
+ setSignerPos(newUpdateSigner);
+ }
+ }
+ setFontSize();
+ setFontColor();
+ setCurrWidgetsDetails({});
+ handleNameModal();
+ };
+
+ const handleNameModal = () => {
+ setIsNameModal(false);
+ setCurrWidgetsDetails({});
+ setShowDropdown(false);
+ setIsRadio(false);
+ setIsCheckbox(false);
+ };
+
+ const clickOnZoomIn = () => {
+ onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
+ };
+ const clickOnZoomOut = () => {
+ onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
+ };
+ //`handleRotationFun` function is used to roatate pdf particular page
+ const handleRotationFun = async (rotateDegree) => {
+ const isRotate = handleRotateWarning(signerPos, pageNumber);
+ if (isRotate) {
+ setIsRotate({ status: true, degree: rotateDegree });
+ } else {
+ const urlDetails = await rotatePdfPage(
+ pdfDetails[0].URL,
+ rotateDegree,
+ pageNumber - 1,
+ pdfRotateBase64
+ );
+ setPdfRotatese64(urlDetails.base64);
+ }
+ };
+ const handleRemovePlaceholder = async () => {
+ handleRemoveWidgets(setSignerPos, signerPos, pageNumber, setIsRotate);
+ const urlDetails = await rotatePdfPage(
+ pdfDetails[0].URL,
+ isRotate.degree,
+ pageNumber - 1,
+ pdfRotateBase64
+ );
+ setPdfRotatese64(urlDetails.base64);
+ };
+ // `handleQuickSendClose` is trigger when bulk send component trigger close event
+ const handleQuickSendClose = (status, count) => {
+ if (status === "success") {
+ setIsCreateDocModal(false);
+ if (count > 1) {
+ setIsAlert({
+ type: "success",
+ msg: count + " " + t("document-sent-alert")
+ });
+ setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
+ } else {
+ setIsAlert({
+ type: "success",
+ msg: count + " " + t("document-sent-alert")
+ });
+ setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
+ }
+ } else {
+ setIsAlert({
+ type: "danger",
+ message: t("something-went-wrong-mssg")
+ });
+ setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
+ }
+ };
+ const handleGeneratePublic = async () => {
+ const unlinkSignerIndex = signerPos?.findIndex((x) => !x?.signerObjId);
+ const unlinkSigners = signerPos?.filter((x) => !x?.signerObjId)?.length; // unLink with role
+ if (unlinkSignerIndex === 0 && unlinkSigners === 1) {
+ try {
+ const data = { templateId: templateId, IsPublic: true };
+ const baseURL = localStorage.getItem("baseUrl");
+ const url = `${baseURL}functions/updatetopublictemplate`;
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ jwttoken: jwttoken
+ };
+ await axios.post(url, data, { headers });
+ // console.log("updatetopublictemplate", res.data);
+ setIsPublic("true");
+ } catch (e) {
+ alert(t("something-went-wrong-mssg"));
+ console.log("error", e);
+ }
+ } else {
+ // setIsPublicError(true);
+ alert(
+ "Only one signer without a role is allowed, and it should be at the first index."
+ );
+ }
+ };
+ const copytoclipboard = (publicUrl) => {
+ copytoData(publicUrl);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 1500); // Reset copied state after 1.5 seconds
+ };
+
+ // `handleSendDocument` is trigger when users are linked to all role
+ const handleSendDocument = async () => {
+ setIsLoading({ isLoad: true, message: t("loading-mssg") });
+ const signers = signersdata?.filter((x) => x.objectId) || [];
+ let pdfUrl = pdfDetails[0]?.URL;
+ if (pdfRotateBase64) {
+ try {
+ pdfUrl = await convertBase64ToFile(pdfDetails[0].Name, pdfRotateBase64);
+ } catch (e) {
+ console.log("error to convertBase64ToFile", e);
+ }
+ }
+ let template = pdfDetails[0];
+ template.URL = pdfUrl;
+ template.Signers = signers;
+ template.Placeholders = signerPos;
+ const Documents = [template];
+ const token = jwttoken
+ ? { jwttoken: jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ };
+ const functionsUrl = `${localStorage.getItem(
+ "baseUrl"
+ )}functions/batchdocuments`;
+ const params = { Documents: JSON.stringify(Documents) };
+ try {
+ const res = await axios.post(functionsUrl, params, { headers: headers });
+ if (res.data && res.data.result === "success") {
+ setIsAlert({
+ type: "success",
+ msg: Documents?.length + " " + t("document-sent-alert")
+ });
+ }
+ } catch (err) {
+ console.log("err in send document ", err);
+ setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
+ } finally {
+ setIsLoading({ isLoad: false });
+ setIsCreateDocModal(false);
+ setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
+ }
+ };
+ //function show signer list and share link to share signUrl
+ const handlePublicShare = () => {
+ let publicUrl;
+ if (isStaging) {
+ publicUrl = `https://staging.opensign.me/publicsign?templateid=${templateId}`;
+ } else {
+ publicUrl = `https://opensign.me/publicsign?templateid=${templateId}`;
+ }
+ return (
+
+ {copied &&
{t("copied")} }
+
+ {publicUrl}
+
+
+ copytoclipboard(publicUrl)}
+ type="button"
+ className="flex flex-row items-center op-link op-link-primary"
+ >
+
+ {t("copy-link")}
+
+
+
+
+
+
+ );
+ };
+
+ return (
+ <>
+
+ {isAlert.msg && {isAlert.msg} }
+
+ {isLoading.isLoad ? (
+
+ ) : isSubscriptionExpired ? (
+
+
+
+ {t("owner-subscription-expired")}
+
+
+
+ ) : handleError ? (
+
+ ) : (
+
+
+ {/* this component used for UI interaction and show their functionality */}
+ {!checkTourStatus && (
+ //this tour component used in your html component where you want to put
+ //onRequestClose function to close tour
+ //steps is defined what will be your messages and style also
+ //isOpen is takes boolean value to open
+
+ )}
+ {isAddRole && (
+
setIsAddRole(false)}
+ steps={tourAddRole}
+ isOpen={isAddRole}
+ rounded={5}
+ closeWithMask={false}
+ />
+ )}
+ {/* this component used to render all pdf pages in left side */}
+
+
+ {/* pdf render view */}
+
+
+
+ {/* this modal is used show alert set placeholder for all signers before send mail */}
+
setIsSendAlert(false)}
+ >
+
+
{t("template-signature-field")}
+
+
+
setIsReceipent(true)}
+ >
+
+
{t("template-role-alert")}
+
+
+ {/* this modal is used show send mail message and after send mail success message */}
+ {isCreateDocModal && (
+
setIsCreateDocModal(false)}
+ >
+ {isAllRoleLinked ? (
+
+
+ Are you sure want to send document?
+
+
+ handleSendDocument()}
+ >
+ Yes
+
+ setIsCreateDocModal(false)}
+ >
+ No
+
+
+
+ ) : (
+ <>
+
+ {isPublic !== "false" && (
+
+
+
+
+ {t("or")}
+
+
+
+
+
+ Copy/share signing link
+
+
+ {isPublic === "undefined" ? (
+ handleGeneratePublic()}
+ >
+ Generate Public Link
+
+ ) : (
+ handlePublicShare()
+ )}
+
+
+ )}
+ >
+ )}
+
+ )}
+
setIsShowEmail(false)}
+ >
+
+
{t("template-creation-alert-1")}
+
+
setIsShowEmail(false)}
+ type="button"
+ className="op-btn op-btn-primary"
+ >
+ {t("ok")}
+
+
+
+
+
+
+
+ {/* pdf header which contain funish back button */}
+
+
+ {containerWH && (
+
+ )}
+
+
+
+ {/* signature button */}
+ {isMobile ? (
+
+
+
+ ) : (
+
+ )}
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default DraftTemplate;
diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js
index 6d9d98211..0e0748d3f 100644
--- a/apps/OpenSign/src/pages/PdfRequestFiles.js
+++ b/apps/OpenSign/src/pages/PdfRequestFiles.js
@@ -132,12 +132,10 @@ function PdfRequestFiles(props) {
const [publicRes, setPublicRes] = useState({});
const [documentId, setDocumentId] = useState("");
const [isPublicContact, setIsPublicContact] = useState(false);
- const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
const [plancode, setPlanCode] = useState("");
const isHeader = useSelector((state) => state.showHeader);
const divRef = useRef(null);
const [isDownloadModal, setIsDownloadModal] = useState(false);
-
const isMobile = window.innerWidth < 767;
let isGuestSignFlow = false;
@@ -323,8 +321,6 @@ function PdfRequestFiles(props) {
const arrayBuffer = await convertPdfArrayBuffer(url);
if (arrayBuffer === "Error") {
setHandleError(t("something-went-wrong-mssg"));
- } else {
- setPdfArrayBuffer(arrayBuffer);
}
} else {
setHandleError(t("something-went-wrong-mssg"));
@@ -408,8 +404,6 @@ function PdfRequestFiles(props) {
const arrayBuffer = await convertPdfArrayBuffer(url);
if (arrayBuffer === "Error") {
setHandleError(t("something-went-wrong-mssg"));
- } else {
- setPdfArrayBuffer(arrayBuffer);
}
} else {
setHandleError(t("something-went-wrong-mssg"));
diff --git a/apps/OpenSign/src/primitives/AddContact.js b/apps/OpenSign/src/primitives/AddContact.js
index c25024c85..0365c2b5b 100644
--- a/apps/OpenSign/src/primitives/AddContact.js
+++ b/apps/OpenSign/src/primitives/AddContact.js
@@ -1,7 +1,8 @@
import React, { useState, useEffect } from "react";
-import Parse from "parse";
import Loader from "./Loader";
import { useTranslation } from "react-i18next";
+import axios from "axios";
+import { getTenantDetails } from "../constant/Utils";
const AddContact = (props) => {
const { t } = useTranslation();
const [name, setName] = useState("");
@@ -12,6 +13,7 @@ const AddContact = (props) => {
const [isUserExist, setIsUserExist] = useState(false);
useEffect(() => {
checkUserExist();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Load user details from localStorage when the component mounts
useEffect(() => {
@@ -26,19 +28,24 @@ const AddContact = (props) => {
}, [addYourself]);
const checkUserExist = async () => {
- const user = Parse.User.current();
try {
- const query = new Parse.Query("contracts_Contactbook");
- query.equalTo("CreatedBy", user);
- query.notEqualTo("IsDeleted", true);
- query.equalTo("Email", user.getEmail());
- const res = await query.first();
- // console.log(res);
- if (!res) {
+ const baseURL = localStorage.getItem("baseUrl");
+ const url = `${baseURL}functions/isuserincontactbook`;
+ const token = props?.jwttoken
+ ? { jwttoken: props?.jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ };
+ const axiosRes = await axios.post(url, {}, { headers });
+ const contactRes = axiosRes?.data?.result || {};
+ if (!contactRes?.objectId) {
setIsUserExist(true);
}
} catch (err) {
- console.log("err", err);
+ console.log("err ", err);
}
};
// Define a function to handle form submission
@@ -46,123 +53,51 @@ const AddContact = (props) => {
e.preventDefault();
e.stopPropagation();
setIsLoader(true);
- if (localStorage.getItem("TenantId")) {
+ const user = JSON.parse(
+ localStorage.getItem(
+ `Parse/${localStorage.getItem("parseAppId")}/currentUser`
+ )
+ );
+ const userId = user?.objectId || "";
+ const tenantDetails = await getTenantDetails(userId, props.jwttoken);
+ console.log("tenantDetails", tenantDetails);
+ const tenantId = tenantDetails?.objectId || "";
+ if (tenantId) {
try {
- const user = Parse.User.current();
- const query = new Parse.Query("contracts_Contactbook");
- query.equalTo("CreatedBy", user);
- query.notEqualTo("IsDeleted", true);
- query.equalTo("Email", email);
- const res = await query.first();
- if (!res) {
- const contactQuery = new Parse.Object("contracts_Contactbook");
- contactQuery.set("Name", name);
- if (phone) {
- contactQuery.set("Phone", phone);
+ const baseURL = localStorage.getItem("baseUrl");
+ const url = `${baseURL}functions/savecontact`;
+ const token = props?.jwttoken
+ ? { jwttoken: props?.jwttoken }
+ : { "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
+ const data = { name, email, phone, tenantId };
+ const headers = {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ ...token
+ };
+ const axiosRes = await axios.post(url, data, { headers });
+ const contactRes = axiosRes?.data?.result || {};
+ if (contactRes?.objectId) {
+ console.log("contactRes ", contactRes);
+ props.details(contactRes);
+ if (props.closePopup) {
+ props.closePopup();
+ setIsLoader(false);
+ // Reset the form fields
+ setAddYourself(false);
+ setName("");
+ setPhone("");
+ setEmail("");
}
- contactQuery.set("Email", email);
- contactQuery.set("UserRole", "contracts_Guest");
-
- if (localStorage.getItem("TenantId")) {
- contactQuery.set("TenantId", {
- __type: "Pointer",
- className: "partners_Tenant",
- objectId: localStorage.getItem("TenantId")
- });
- }
-
- try {
- const _users = Parse.Object.extend("User");
- const _user = new _users();
- _user.set("name", name);
- _user.set("username", email);
- _user.set("email", email);
- _user.set("password", email);
- if (phone) {
- _user.set("phone", phone);
- }
-
- const user = await _user.save();
- if (user) {
- const currentUser = Parse.User.current();
- contactQuery.set(
- "CreatedBy",
- Parse.User.createWithoutData(currentUser.id)
- );
-
- contactQuery.set("UserId", user);
- const acl = new Parse.ACL();
- acl.setPublicReadAccess(true);
- acl.setPublicWriteAccess(true);
- acl.setReadAccess(currentUser.id, true);
- acl.setWriteAccess(currentUser.id, true);
-
- contactQuery.setACL(acl);
-
- const res = await contactQuery.save();
-
- const parseData = JSON.parse(JSON.stringify(res));
- props.details(parseData);
- if (props.closePopup) {
- props.closePopup();
- }
-
- setIsLoader(false);
- // Reset the form fields
- setAddYourself(false);
- setName("");
- setPhone("");
- setEmail("");
- }
- } catch (err) {
- console.log("err ", err);
- if (err.code === 202) {
- const params = { email: email };
- const userRes = await Parse.Cloud.run("getUserId", params);
- const currentUser = Parse.User.current();
- contactQuery.set(
- "CreatedBy",
- Parse.User.createWithoutData(currentUser.id)
- );
-
- contactQuery.set("UserId", {
- __type: "Pointer",
- className: "_User",
- objectId: userRes.id
- });
- const acl = new Parse.ACL();
- acl.setPublicReadAccess(true);
- acl.setPublicWriteAccess(true);
- acl.setReadAccess(currentUser.id, true);
- acl.setWriteAccess(currentUser.id, true);
-
- contactQuery.setACL(acl);
- const res = await contactQuery.save();
-
- const parseData = JSON.parse(JSON.stringify(res));
- if (props.details) {
- props.details(parseData);
- }
-
- if (props.closePopup) {
- props.closePopup();
- }
- setIsLoader(false);
- // Reset the form fields
- setAddYourself(false);
- setName("");
- setPhone("");
- setEmail("");
- }
- }
- } else {
- alert(t("add-signer-alert"));
- setIsLoader(false);
}
} catch (err) {
- // console.log("err", err);
+ console.log("Err", err);
setIsLoader(false);
- alert(t("something-went-wrong-mssg"));
+ if (err?.response?.data?.error?.includes("already exists")) {
+ alert(t("add-signer-alert"));
+ } else {
+ alert(t("something-went-wrong-mssg"));
+ }
}
} else {
setIsLoader(false);
diff --git a/apps/OpenSign/src/primitives/LinkUserModal.js b/apps/OpenSign/src/primitives/LinkUserModal.js
index ed3bef0db..dd7479ff9 100644
--- a/apps/OpenSign/src/primitives/LinkUserModal.js
+++ b/apps/OpenSign/src/primitives/LinkUserModal.js
@@ -19,11 +19,16 @@ const LinkUserModal = (props) => {
details={props.handleAddUser}
closePopup={props.closePopup}
signersData={props?.signersData}
+ jwttoken={props?.jwttoken}
/>
{t("or")}
-
+
);
};
diff --git a/apps/OpenSignServer/Utils.js b/apps/OpenSignServer/Utils.js
index a721fff43..776aca636 100644
--- a/apps/OpenSignServer/Utils.js
+++ b/apps/OpenSignServer/Utils.js
@@ -234,3 +234,7 @@ export const planCredits = {
'teams-monthly': 100,
'teams-yearly': 500,
};
+
+export function parseJwt(token) {
+ return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
+}
diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js
index 2ccd5a1c7..dbac393b4 100644
--- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js
+++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js
@@ -9,7 +9,6 @@ import getDocument from './routes/getDocument.js';
import getContact from './routes/getContact.js';
import deleteContact from './routes/deleteContact.js';
import getContactList from './routes/getContactList.js';
-import draftDocument from './routes/draftDocument.js';
import getTemplate from './routes/getTemplate.js';
import deletedTemplate from './routes/deleteTemplate.js';
import getTemplatetList from './routes/getTemplateList.js';
@@ -30,6 +29,7 @@ import createFolder from './routes/createFolder.js';
import updateFolder from './routes/updateFolder.js';
import getFolderList from './routes/getFolderList.js';
import deleteFolder from './routes/deleteFolder.js';
+import draftTemplate from './routes/draftTemplate.js';
dotenv.config();
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
@@ -59,9 +59,6 @@ app.post('/createdocumentwithbinary', upload.array('file', 1), createDocumentwit
// create Document with co-ordinate
app.post('/createdocument', createDocumentwithCoordinate);
-// create Document with base64 without placeholder
-app.post('/draftdocument', draftDocument);
-
// create Document with templateId
app.post('/createdocument/:template_id', createDocumentWithTemplate);
@@ -77,6 +74,9 @@ app.delete('/document/:document_id', deleteDocument);
// get all types of documents on the basis of doctype
app.get('/documentlist/:doctype', getDocumentList);
+// create draft template with file base64
+app.post('/drafttemplate', draftTemplate);
+
// create Template with co-ordinate
app.post('/createtemplate', createTemplatewithCoordinate);
diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js
index 988d97efa..72e119ff1 100644
--- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js
+++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js
@@ -49,7 +49,7 @@ export default async function createDocumentWithTemplate(request, response) {
const send_email = request.body.send_email;
const email_subject = request.body.email_subject;
const email_body = request.body.email_body;
- const sendInOrder = request.body.sendInOrder || false;
+ const sendInOrder = request.body.sendInOrder || true;
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
try {
diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js
index a6d061266..3ed23217d 100644
--- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js
+++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js
@@ -62,7 +62,7 @@ export default async function createDocumentwithCoordinate(request, response) {
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const email_subject = request.body.email_subject;
const email_body = request.body.email_body;
- const sendInOrder = request.body.sendInOrder || false;
+ const sendInOrder = request.body.sendInOrder || true;
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
const IsEnableOTP = request.body?.enableOTP === true ? true : false;
const isTourEnabled = request.body?.enableTour || false;
diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js
index 04e87e5fe..d93c1dce0 100644
--- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js
+++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js
@@ -17,7 +17,7 @@ export default async function createTemplatewithCoordinate(request, response) {
const folderId = request.body.folderId;
const base64File = request.body.file;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
- const SendinOrder = request.body.sendInOrder || false;
+ const SendinOrder = request.body.sendInOrder || true;
const isEnableOTP = request.body?.enableOTP === true ? true : false;
const isTourEnabled = request.body?.enableTour || false;
diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/draftDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/draftDocument.js
deleted file mode 100644
index 9a04bbbfd..000000000
--- a/apps/OpenSignServer/cloud/customRoute/v1/routes/draftDocument.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import axios from 'axios';
-import { customAPIurl, saveFileUsage } from '../../../../Utils.js';
-
-// const randomId = () => Math.floor(1000 + Math.random() * 9000);
-export default async function draftDocument(request, response) {
- const name = request.body.title;
- const note = request.body.note;
- const description = request.body.description;
- const signers = request.body.signers;
- const folderId = request.body.folderId;
- const base64File = request.body.file;
- const send_email = request.body.send_email || true;
- const fileData = request.files?.[0] ? request.files[0].buffer : null;
- const SendinOrder = request.body.sendInOrder || false;
- const isEnableOTP = request.body?.enableOTP === true ? true : false;
- const isTourEnabled = request.body?.enableTour || false;
-
- // console.log('fileData ', fileData);
- const protocol = customAPIurl();
- const baseUrl = new URL(process.env.PUBLIC_URL);
-
- try {
- const reqToken = request.headers['x-api-token'];
- if (!reqToken) {
- return response.status(400).json({ error: 'Please Provide API Token' });
- }
- const tokenQuery = new Parse.Query('appToken');
- tokenQuery.equalTo('token', reqToken);
- tokenQuery.include('userId');
- const token = await tokenQuery.first({ useMasterKey: true });
- if (token !== undefined) {
- const parseUser = JSON.parse(JSON.stringify(token));
- const userPtr = {
- __type: 'Pointer',
- className: '_User',
- objectId: parseUser.userId.objectId,
- };
- // Valid Token then proceed request
- if (signers && signers.length > 0) {
- let fileUrl;
- if (request.files?.[0]) {
- const base64 = fileData?.toString('base64');
- const file = new Parse.File(request.files?.[0]?.originalname, {
- base64: base64,
- });
- await file.save({ useMasterKey: true });
- fileUrl = file.url();
- const buffer = Buffer.from(base64, 'base64');
- saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
- } else {
- const file = new Parse.File(`${name}.pdf`, {
- base64: base64File,
- });
- await file.save({ useMasterKey: true });
- fileUrl = file.url();
- const buffer = Buffer.from(base64File, 'base64');
- saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
- }
- const contractsUser = new Parse.Query('contracts_Users');
- contractsUser.equalTo('UserId', userPtr);
- const extUser = await contractsUser.first({ useMasterKey: true });
- const extUserPtr = {
- __type: 'Pointer',
- className: 'contracts_Users',
- objectId: extUser.id,
- };
-
- const folderPtr = {
- __type: 'Pointer',
- className: 'contracts_Document',
- objectId: folderId,
- };
-
- const object = new Parse.Object('contracts_Document');
- object.set('Name', name);
- if (note) {
- object.set('Note', note);
- }
- if (description) {
- object.set('Description', description);
- }
- if (SendinOrder) {
- object.set('SendinOrder', SendinOrder);
- }
- object.set('URL', fileUrl);
- object.set('CreatedBy', userPtr);
- object.set('ExtUserPtr', extUserPtr);
- object.set('IsSendMail', send_email);
- object.set('IsEnableOTP', isEnableOTP);
- object.set('IsTourEnabled', isTourEnabled);
- if (signers && signers.length > 0) {
- let parseSigners;
- if (base64File) {
- parseSigners = signers;
- } else {
- parseSigners = JSON.parse(signers);
- }
- let createContactUrl = protocol + '/v1/createcontact';
-
- let contact = [];
- for (const obj of parseSigners) {
- const body = {
- name: obj?.name || '',
- email: obj?.email || '',
- phone: obj?.phone || '',
- };
- try {
- const res = await axios.post(createContactUrl, body, {
- headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
- });
- // console.log('res ', res.data);
- contact.push({
- __type: 'Pointer',
- className: 'contracts_Contactbook',
- objectId: res.data?.objectId,
- });
- } catch (err) {
- // console.log('err ', err.response);
- if (err?.response?.data?.objectId) {
- contact.push({
- __type: 'Pointer',
- className: 'contracts_Contactbook',
- objectId: err.response.data?.objectId,
- });
- }
- }
- }
- object.set('Signers', contact);
- }
- if (folderId) {
- object.set('Folder', folderPtr);
- }
- const newACL = new Parse.ACL();
- newACL.setPublicReadAccess(false);
- newACL.setPublicWriteAccess(false);
- newACL.setReadAccess(userPtr.objectId, true);
- newACL.setWriteAccess(userPtr.objectId, true);
- object.setACL(newACL);
- const res = await object.save(null, { useMasterKey: true });
- if (request.posthog) {
- request.posthog?.capture({
- distinctId: parseUser.userId.email,
- event: 'api_draft_document',
- properties: { response_code: 200 },
- });
- }
- return response.json({
- objectId: res.id,
- url: `${baseUrl.origin}/placeholdersign/${res.id}`,
- });
- } else {
- if (request.posthog) {
- request.posthog?.capture({
- distinctId: parseUser.userId.email,
- event: 'api_draft_document',
- properties: { response_code: 400 },
- });
- }
- return response.status(400).json({ error: 'Please provide signers!' });
- }
- } else {
- return response.status(405).json({ error: 'Invalid API Token!' });
- }
- } catch (err) {
- console.log('err ', err);
- return response.status(400).json({ error: 'Something went wrong, please try again later!' });
- }
-}
diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/draftTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/draftTemplate.js
new file mode 100644
index 000000000..135ad7ec3
--- /dev/null
+++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/draftTemplate.js
@@ -0,0 +1,238 @@
+import axios from 'axios';
+import {
+ color,
+ customAPIurl,
+ saveFileUsage,
+ formatWidgetOptions,
+ sanitizeFileName,
+} from '../../../../Utils.js';
+import uploadFileToS3 from '../../../parsefunction/uploadFiletoS3.js';
+import jwt from 'jsonwebtoken';
+
+const randomId = () => Math.floor(1000 + Math.random() * 9000);
+export default async function draftTemplate(request, response) {
+ const name = request.body.title;
+ const note = request.body.note;
+ const description = request.body.description;
+ const signers = request.body.signers;
+ const folderId = request.body.folderId;
+ const base64File = request.body.file;
+ const fileData = request.files?.[0] ? request.files[0].buffer : null;
+ const SendinOrder = request.body.sendInOrder || true;
+ const isEnableOTP = request.body?.enableOTP === true ? true : false;
+ const isTourEnabled = request.body?.enableTour || false;
+ const isPublic = request.body?.isPublic;
+ const protocol = customAPIurl();
+ const baseUrl = new URL(process.env.PUBLIC_URL).origin;
+
+ try {
+ const reqToken = request.headers['x-api-token'];
+ if (!reqToken) {
+ return response.status(400).json({ error: 'Please Provide API Token' });
+ }
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('token', reqToken);
+ tokenQuery.include('userId');
+ const token = await tokenQuery.first({ useMasterKey: true });
+ if (token !== undefined) {
+ // Valid Token then proceed request
+ const parseUser = JSON.parse(JSON.stringify(token));
+ const userPtr = {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: parseUser.userId.objectId,
+ };
+ const contractsUser = new Parse.Query('contracts_Users');
+ contractsUser.equalTo('UserId', userPtr);
+ contractsUser.include('TenantId');
+ const extUser = await contractsUser.first({ useMasterKey: true });
+ const parseExtUser = JSON.parse(JSON.stringify(extUser));
+ let fileUrl;
+ if (request.files?.[0]) {
+ const base64 = fileData?.toString('base64');
+ const file = new Parse.File(request.files?.[0]?.originalname, {
+ base64: base64,
+ });
+ await file.save({ useMasterKey: true });
+ fileUrl = file.url();
+ const buffer = Buffer.from(base64, 'base64');
+ saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
+ } else {
+ const filename = sanitizeFileName(`${name}.pdf`);
+ let adapter = {};
+ const ActiveFileAdapter = parseExtUser?.TenantId?.ActiveFileAdapter || '';
+ if (ActiveFileAdapter) {
+ adapter =
+ parseExtUser?.TenantId?.FileAdapters?.find(x => (x.id = ActiveFileAdapter)) || {};
+ }
+ if (adapter?.id) {
+ const filedata = Buffer.from(base64File, 'base64');
+ // `uploadFileToS3` is used to save document in user's file storage
+ fileUrl = await uploadFileToS3(filedata, filename, 'application/pdf', adapter);
+ } else {
+ const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
+ await file.save({ useMasterKey: true });
+ fileUrl = file.url();
+ }
+ const buffer = Buffer.from(base64File, 'base64');
+ saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
+ }
+ const extUserPtr = {
+ __type: 'Pointer',
+ className: 'contracts_Users',
+ objectId: extUser.id,
+ };
+ const object = new Parse.Object('contracts_Template');
+ object.set('Name', name);
+ if (note) {
+ object.set('Note', note);
+ }
+ if (description) {
+ object.set('Description', description);
+ }
+ if (SendinOrder) {
+ object.set('SendinOrder', SendinOrder);
+ }
+ object.set('URL', fileUrl);
+ object.set('CreatedBy', userPtr);
+ object.set('ExtUserPtr', extUserPtr);
+ object.set('IsEnableOTP', isEnableOTP);
+ object.set('IsTourEnabled', isTourEnabled);
+ const Public = isPublic !== undefined ? template?.IsPublic : false;
+ if (template?.IsPublic !== undefined) {
+ object.set('IsPublic', Public);
+ }
+ let contact = [];
+ if (signers && signers.length > 0) {
+ let parseSigners;
+ if (base64File) {
+ parseSigners = signers;
+ } else {
+ parseSigners = JSON.parse(signers);
+ }
+ let createContactUrl = protocol + '/v1/createcontact';
+
+ for (const [index, element] of parseSigners.entries()) {
+ if (element?.name && element?.email) {
+ const body = {
+ name: element?.name,
+ email: element?.email,
+ phone: element?.phone || '',
+ };
+ try {
+ const res = await axios.post(createContactUrl, body, {
+ headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
+ });
+ // console.log('res ', res.data);
+ const contactPtr = {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: res.data?.objectId,
+ };
+ const newObj = { ...element, contactPtr: contactPtr, index: index };
+ contact.push(newObj);
+ } catch (err) {
+ // console.log('err ', err.response);
+ if (err?.response?.data?.objectId) {
+ const contactPtr = {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: err.response.data?.objectId,
+ };
+ const newObj = { ...element, contactPtr: contactPtr, index: index };
+ contact.push(newObj);
+ }
+ }
+ } else {
+ const newObj = { ...element, contactPtr: {}, index: index };
+ contact.push(newObj);
+ }
+ }
+ const updatedSigners = contact?.filter(x => x.contactPtr && x.contactPtr.objectId);
+ if (updatedSigners && updatedSigners.length > 0) {
+ object.set(
+ 'Signers',
+ updatedSigners?.map(x => x.contactPtr)
+ );
+ }
+ let updatePlaceholders = [];
+ for (const signer of contact) {
+ const placeHolder = [];
+ if (signer.widgets?.length > 0) {
+ for (const widget of signer.widgets) {
+ const pageNumber = widget.page;
+ const page = placeHolder.find(page => page.pageNumber === pageNumber);
+ const options = formatWidgetOptions(widget.type, widget.options);
+ const widgetData = {
+ isStamp: widget.type === 'stamp' || widget.type === 'image',
+ key: randomId(),
+ isDrag: false,
+ scale: 1,
+ isMobile: false,
+ zIndex: 1,
+ type: widget.type === 'textbox' ? 'text input' : widget.type,
+ options: options,
+ Width: widget.w,
+ Height: widget.h,
+ xPosition: widget.x,
+ yPosition: widget.y,
+ };
+
+ if (page) {
+ page.pos.push(widgetData);
+ } else {
+ placeHolder.push({ pageNumber, pos: [widgetData] });
+ }
+ }
+ }
+ updatePlaceholders.push({
+ signerObjId: signer?.contactPtr?.objectId || '',
+ signerPtr: signer?.contactPtr,
+ Role: signer.role,
+ Id: randomId(),
+ blockColor: color[signer?.index],
+ placeHolder,
+ });
+ }
+ if (updatePlaceholders?.length > 0) {
+ object.set('Placeholders', updatePlaceholders);
+ }
+ }
+ if (folderId) {
+ object.set('Folder', {
+ __type: 'Pointer',
+ className: 'contracts_Template',
+ objectId: folderId,
+ });
+ }
+ if (parseExtUser?.TenantId?.ActiveFileAdapter) {
+ object.set('FileAdapterId', parseExtUser?.TenantId?.ActiveFileAdapter);
+ }
+ const newACL = new Parse.ACL();
+ newACL.setPublicReadAccess(false);
+ newACL.setPublicWriteAccess(false);
+ newACL.setReadAccess(userPtr.objectId, true);
+ newACL.setWriteAccess(userPtr.objectId, true);
+ object.setACL(newACL);
+ const res = await object.save(null, { useMasterKey: true });
+ if (request.posthog) {
+ request.posthog?.capture({
+ distinctId: parseUser.userId.email,
+ event: 'api_draft_template',
+ properties: { response_code: 200 },
+ });
+ }
+ const JwtToken = jwt.sign(
+ { user_email: parseUser.userId.email, template_id: res.id },
+ reqToken
+ );
+
+ return response.json({ objectId: res.id, url: `${baseUrl}/drafttemplate/${JwtToken}` });
+ } else {
+ return response.status(405).json({ error: 'Invalid API Token!' });
+ }
+ } catch (err) {
+ console.log('err ', err);
+ return response.status(400).json({ error: 'Something went wrong, please try again later!' });
+ }
+}
diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js
index b2f55d90a..343bc979b 100644
--- a/apps/OpenSignServer/cloud/main.js
+++ b/apps/OpenSignServer/cloud/main.js
@@ -75,6 +75,14 @@ import saveToFileAdapter from './parsefunction/saveToFileAdapter.js';
import getFileAdapter from './parsefunction/getFileAdapter.js';
import addPfxFile from './parsefunction/addPfxFile.js';
import getPfxFile from './parsefunction/getPfxFile.js';
+import getTenant from './parsefunction/getTenant.js';
+import getSigners from './parsefunction/getSigners.js';
+import saveFile from './parsefunction/saveFile.js';
+import savecontact from './parsefunction/savecontact.js';
+import isUserInContactBook from './parsefunction/isUserInContactBook.js';
+import updateTourStatus from './parsefunction/updateTourStatus.js';
+import saveTemplate from './parsefunction/saveTemplate.js';
+import updateToPublicTemplate from './parsefunction/updateToPublicTemplate.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);
@@ -162,3 +170,11 @@ Parse.Cloud.define('addfileadapter', addFileAdapter);
Parse.Cloud.define('getfileadapter', getFileAdapter);
Parse.Cloud.define('addpfx', addPfxFile);
Parse.Cloud.define('getpfx', getPfxFile);
+Parse.Cloud.define('gettenant', getTenant);
+Parse.Cloud.define('getsigners', getSigners);
+Parse.Cloud.define('savetemplate', saveTemplate);
+Parse.Cloud.define('savefile', saveFile);
+Parse.Cloud.define('savecontact', savecontact);
+Parse.Cloud.define('isuserincontactbook', isUserInContactBook);
+Parse.Cloud.define('updatetourstatus', updateTourStatus);
+Parse.Cloud.define('updatetopublictemplate', updateToPublicTemplate);
diff --git a/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js b/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js
index 04b0eb79e..dc9dfe1cc 100644
--- a/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js
+++ b/apps/OpenSignServer/cloud/parsefunction/AllowedCredits.js
@@ -1,33 +1,64 @@
-export default async function AllowedCredits(request) {
- if (!request?.user) {
- throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
- }
- try {
- const extUser = new Parse.Query('contracts_Users');
- extUser.equalTo('UserId', {
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+async function checkCredits(userId) {
+ const extUser = new Parse.Query('contracts_Users');
+ extUser.equalTo('UserId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const resExtUser = await extUser.first({ useMasterKey: true });
+ if (resExtUser) {
+ const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
+ const subscription = new Parse.Query('contracts_Subscriptions');
+ subscription.equalTo('TenantId', {
__type: 'Pointer',
- className: '_User',
- objectId: request.user.id,
+ className: 'partners_Tenant',
+ objectId: _resExtUser.TenantId.objectId,
});
- const resExtUser = await extUser.first({ useMasterKey: true });
- if (resExtUser) {
- const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
- const subscription = new Parse.Query('contracts_Subscriptions');
- subscription.equalTo('TenantId', {
- __type: 'Pointer',
- className: 'partners_Tenant',
- objectId: _resExtUser.TenantId.objectId,
- });
- subscription.include('ExtUserPtr');
- const resSub = await subscription.first({ useMasterKey: true });
- if (resSub) {
- const _resSub = JSON.parse(JSON.stringify(resSub));
- const AllowedCredits = _resSub?.AllowedCredits || 0;
- const AddonCredits = _resSub?.AddonCredits || 0;
- return { allowedcredits: AllowedCredits, addoncredits: AddonCredits };
+ subscription.include('ExtUserPtr');
+ const resSub = await subscription.first({ useMasterKey: true });
+ if (resSub) {
+ const _resSub = JSON.parse(JSON.stringify(resSub));
+ const AllowedCredits = _resSub?.AllowedCredits || 0;
+ const AddonCredits = _resSub?.AddonCredits || 0;
+ return { allowedcredits: AllowedCredits, addoncredits: AddonCredits };
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ }
+}
+export default async function AllowedCredits(request) {
+ const jwttoken = request?.headers?.jwttoken || '';
+
+ try {
+ if (request?.user) {
+ return await checkCredits(request.user.id);
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ return await checkCredits(userId);
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.');
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.');
}
} else {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
} catch (err) {
console.log('err in allowedCredits', err);
diff --git a/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js
index 7e2821a6a..9ca1a7af6 100644
--- a/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js
+++ b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js
@@ -1,21 +1,54 @@
import axios from 'axios';
-import { cloudServerUrl } from '../../Utils.js';
+import { cloudServerUrl, parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
export default async function GetTemplate(request) {
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const templateId = request.params.templateId;
const ispublic = request.params.ispublic;
-
+ const jwttoken = request.headers?.jwttoken;
+ const sessiontoken = request.headers?.sessiontoken;
try {
if (!ispublic) {
- 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 (templateId && userId) {
+ let userEmail;
+ if (jwttoken) {
+ try {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ userEmail = decoded?.user_email;
+ } else {
+ return { error: 'Invalid token!' };
+ }
+ } else {
+ return { error: 'Invalid token!' };
+ }
+ } catch (err) {
+ console.log('err in jwt', err);
+ return { error: "You don't have access of this document!" };
+ }
+ } else if (sessiontoken) {
+ const userRes = await axios.get(serverUrl + '/users/me', {
+ headers: {
+ 'X-Parse-Application-Id': process.env.APP_ID,
+ 'X-Parse-Session-Token': sessiontoken,
+ },
+ });
+ userEmail = userRes.data && userRes.data.email;
+ }
+ if (templateId && userEmail) {
try {
let template = new Parse.Query('contracts_Template');
template.equalTo('objectId', templateId);
@@ -24,7 +57,7 @@ export default async function GetTemplate(request) {
template.include('CreatedBy');
template.include('ExtUserPtr.TenantId');
const extUserQuery = new Parse.Query('contracts_Users');
- extUserQuery.equalTo('Email', userRes.data.email);
+ extUserQuery.equalTo('Email', userEmail);
extUserQuery.include('TeamIds');
const extUser = await extUserQuery.first({ useMasterKey: true });
if (extUser) {
@@ -64,6 +97,8 @@ export default async function GetTemplate(request) {
console.log('err', err);
return err;
}
+ } else {
+ return { error: "You don't have access of this document!" };
}
} else if (templateId && ispublic) {
try {
@@ -92,7 +127,7 @@ export default async function GetTemplate(request) {
}
} catch (err) {
console.log('err', err);
- if (err.code == 209) {
+ if (err?.response?.data?.code === 209 || err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access of this document!" };
diff --git a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js
index d81f67786..1be43db49 100644
--- a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js
+++ b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js
@@ -1,6 +1,6 @@
import axios from 'axios';
-import { cloudServerUrl } from '../../Utils.js';
-
+import { cloudServerUrl, parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = process.env.APP_ID;
const licenseKey = process.env.LICENSE_KEY;
@@ -30,7 +30,8 @@ async function deductcount(docsCount, extUserId, subscription) {
console.log('Err in deduct in quick send', err);
}
}
-async function sendMail(document, sessionToken) {
+async function sendMail(document) {
+ //sessionToken
const baseUrl = new URL(process.env.PUBLIC_URL);
// console.log("pdfDetails", pdfDetails);
@@ -57,7 +58,7 @@ async function sendMail(document, sessionToken) {
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
- sessionToken: sessionToken,
+ // sessionToken: sessionToken,
};
const objectId = signerMail[i]?.signerObjId;
const hostUrl = baseUrl.origin;
@@ -112,13 +113,161 @@ async function sendMail(document, sessionToken) {
}
}
}
+async function batchQuery(userId, Documents, Ip, parseConfig) {
+ const extCls = new Parse.Query('contracts_Users');
+ extCls.equalTo('UserId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const resExt = await extCls.first({ useMasterKey: true });
+ if (resExt) {
+ const _resExt = JSON.parse(JSON.stringify(resExt));
+ try {
+ const requests = Documents.map(x => {
+ const Signers = x.Signers;
+ const allSigner = x?.Placeholders?.map(
+ item => Signers?.find(e => item?.signerPtr?.objectId === e?.objectId) || item?.signerPtr
+ ).filter(signer => Object.keys(signer).length > 0);
+ const date = new Date();
+ const isoDate = date.toISOString();
+ let Acl = { [x.CreatedBy.objectId]: { read: true, write: true } };
+ if (allSigner && allSigner.length > 0) {
+ allSigner.forEach(x => {
+ const obj = { [x.CreatedBy.objectId]: { read: true, write: true } };
+ Acl = { ...Acl, ...obj };
+ });
+ }
+ return {
+ method: 'POST',
+ path: '/app/classes/contracts_Document',
+ body: {
+ Name: x.Name,
+ URL: x.URL,
+ Note: x.Note,
+ Description: x.Description,
+ CreatedBy: x.CreatedBy,
+ SendinOrder: x.SendinOrder || true,
+ ExtUserPtr: {
+ __type: 'Pointer',
+ className: x.ExtUserPtr.className,
+ objectId: x.ExtUserPtr?.objectId,
+ },
+ Placeholders: x.Placeholders.map(y =>
+ y?.signerPtr?.objectId
+ ? {
+ ...y,
+ signerPtr: {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: y.signerPtr.objectId,
+ },
+ signerObjId: y.signerObjId,
+ }
+ : { ...y, signerPtr: {}, signerObjId: '' }
+ ),
+ SignedUrl: x.URL || x.SignedUrl,
+ SentToOthers: true,
+ Signers: allSigner?.map(y => ({
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: y.objectId,
+ })),
+ ACL: Acl,
+ SentToOthers: true,
+ RemindOnceInEvery: x.RemindOnceInEvery || 5,
+ AutomaticReminders: x.AutomaticReminders || false,
+ TimeToCompleteDays: x.TimeToCompleteDays || 15,
+ OriginIp: Ip,
+ DocSentAt: { __type: 'Date', iso: isoDate },
+ IsEnableOTP: x?.IsEnableOTP || false,
+ IsTourEnabled: x?.IsTourEnabled || false,
+ FileAdapterId: x?.FileAdapterId || '',
+ },
+ };
+ });
+ // console.log('requests ', requests);
+ if (licenseKey) {
+ const subscription = new Parse.Query('contracts_Subscriptions');
+ subscription.equalTo('TenantId', {
+ __type: 'Pointer',
+ className: 'partners_Tenant',
+ objectId: _resExt.TenantId.objectId,
+ });
+ subscription.include('ExtUserPtr');
+ subscription.greaterThanOrEqualTo('Next_billing_date', new Date());
+ const resSub = await subscription.first({ useMasterKey: true });
+ if (resSub) {
+ const _resSub = JSON.parse(JSON.stringify(resSub));
+ const allowedCredits = _resSub?.AllowedCredits || 0;
+ const addonCredits = _resSub?.AddonCredits || 0;
+ const totalcredits = allowedCredits + addonCredits;
+ if (requests?.length <= totalcredits) {
+ const response = await axios.post('batch', { requests: requests }, parseConfig);
+ // Handle the batch query response
+ // console.log('Batch query response:', response.data);
+ if (response.data && response.data.length > 0) {
+ const updateDocuments = Documents.map((x, i) => ({
+ ...x,
+ objectId: response.data[i]?.success?.objectId,
+ createdAt: response.data[i]?.success?.createdAt,
+ }));
+ deductcount(response.data.length, resExt.id, _resSub);
+ for (let i = 0; i < updateDocuments.length; i++) {
+ sendMail(updateDocuments[i], ''); //sessionToken
+ }
+ return 'success';
+ }
+ } else {
+ throw new Parse.Error(429, 'Quota reached, Please buy credits and try again later.');
+ }
+ } else {
+ throw new Parse.Error(
+ Parse.Error.INVALID_QUERY,
+ 'Please purchase or renew your subscription.'
+ );
+ }
+ } else {
+ if (requests?.length > 0) {
+ const newrequests = [requests?.[0]];
+ const response = await axios.post('batch', { requests: newrequests }, parseConfig);
+ // Handle the batch query response
+ // console.log('Batch query response:', response.data);
+ if (response.data && response.data.length > 0) {
+ const document = Documents?.[0];
+ const updateDocuments = {
+ ...document,
+ objectId: response.data[0]?.success?.objectId,
+ createdAt: response.data[0]?.success?.createdAt,
+ };
+ deductcount(response.data.length, resExt.id);
+ sendMail(updateDocuments); //sessionToken
+ return 'success';
+ }
+ }
+ }
+ } catch (error) {
+ const code = error?.response?.data?.code || error?.response?.status || error?.code || 400;
+ const msg =
+ error?.response?.data?.error ||
+ error?.response?.data ||
+ error?.message ||
+ 'Something went wrong.';
+ console.log('Error performing batch query:', code, msg);
+ throw new Parse.Error(code, msg);
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ }
+}
export default async function createBatchDocs(request) {
const strDocuments = request.params.Documents;
- const sessionToken = request.headers['sessiontoken'];
+ const sessionToken = request.headers?.sessiontoken;
+ const jwttoken = request.headers?.jwttoken;
const Documents = JSON.parse(strDocuments);
const Ip = request?.headers?.['x-real-ip'] || '';
const parseConfig = {
- baseURL: serverUrl, //localStorage.getItem('baseUrl'),
+ baseURL: serverUrl,
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': sessionToken,
@@ -126,167 +275,38 @@ export default async function createBatchDocs(request) {
},
};
try {
- const user = await axios.get(serverUrl + '/users/me', {
- headers: {
- 'X-Parse-Application-Id': appId,
- 'X-Parse-Session-Token': request.headers['sessiontoken'],
- },
- });
- if (user.data) {
- const extCls = new Parse.Query('contracts_Users');
- extCls.equalTo('UserId', {
- __type: 'Pointer',
- className: '_User',
- objectId: user.data.objectId,
- });
- const resExt = await extCls.first({ useMasterKey: true });
- if (resExt) {
- const _resExt = JSON.parse(JSON.stringify(resExt));
- try {
- const requests = Documents.map(x => {
- const Signers = x.Signers;
- const allSigner = x?.Placeholders?.map(
- item =>
- Signers?.find(e => item?.signerPtr?.objectId === e?.objectId) || item?.signerPtr
- ).filter(signer => Object.keys(signer).length > 0);
- const date = new Date();
- const isoDate = date.toISOString();
- let Acl = { [x.CreatedBy.objectId]: { read: true, write: true } };
- if (allSigner && allSigner.length > 0) {
- allSigner.forEach(x => {
- const obj = { [x.CreatedBy.objectId]: { read: true, write: true } };
- Acl = { ...Acl, ...obj };
- });
- }
- return {
- method: 'POST',
- path: '/app/classes/contracts_Document',
- body: {
- Name: x.Name,
- URL: x.URL,
- Note: x.Note,
- Description: x.Description,
- CreatedBy: x.CreatedBy,
- SendinOrder: x.SendinOrder || true,
- ExtUserPtr: {
- __type: 'Pointer',
- className: x.ExtUserPtr.className,
- objectId: x.ExtUserPtr.objectId,
- },
- Placeholders: x.Placeholders.map(y =>
- y?.signerPtr?.objectId
- ? {
- ...y,
- signerPtr: {
- __type: 'Pointer',
- className: 'contracts_Contactbook',
- objectId: y.signerPtr.objectId,
- },
- signerObjId: y.signerObjId,
- }
- : { ...y, signerPtr: {}, signerObjId: '' }
- ),
- SignedUrl: x.URL || x.SignedUrl,
- SentToOthers: true,
- Signers: allSigner?.map(y => ({
- __type: 'Pointer',
- className: 'contracts_Contactbook',
- objectId: y.objectId,
- })),
- ACL: Acl,
- SentToOthers: true,
- RemindOnceInEvery: x.RemindOnceInEvery || 5,
- AutomaticReminders: x.AutomaticReminders || false,
- TimeToCompleteDays: x.TimeToCompleteDays || 15,
- OriginIp: Ip,
- DocSentAt: { __type: 'Date', iso: isoDate },
- IsEnableOTP: x?.IsEnableOTP || false,
- IsTourEnabled: x?.IsTourEnabled || false,
- FileAdapterId: x?.FileAdapterId || '',
- },
- };
- });
- // console.log('requests ', requests);
- if (licenseKey) {
- const subscription = new Parse.Query('contracts_Subscriptions');
- subscription.equalTo('TenantId', {
- __type: 'Pointer',
- className: 'partners_Tenant',
- objectId: _resExt.TenantId.objectId,
- });
- subscription.include('ExtUserPtr');
- subscription.greaterThanOrEqualTo('Next_billing_date', new Date());
- const resSub = await subscription.first({ useMasterKey: true });
- if (resSub) {
- const _resSub = JSON.parse(JSON.stringify(resSub));
- const allowedCredits = _resSub?.AllowedCredits || 0;
- const addonCredits = _resSub?.AddonCredits || 0;
- const totalcredits = allowedCredits + addonCredits;
- if (requests?.length <= totalcredits) {
- const response = await axios.post('batch', { requests: requests }, parseConfig);
- // // Handle the batch query response
- // console.log('Batch query response:', response.data);
- if (response.data && response.data.length > 0) {
- const updateDocuments = Documents.map((x, i) => ({
- ...x,
- objectId: response.data[i]?.success?.objectId,
- createdAt: response.data[i]?.success?.createdAt,
- }));
- deductcount(response.data.length, resExt.id, _resSub);
- for (let i = 0; i < updateDocuments.length; i++) {
- sendMail(updateDocuments[i], sessionToken);
- }
- return 'success';
- }
- } else {
- throw new Parse.Error(
- 429,
- 'Quota reached, Please buy credits and try again later.'
- );
- }
- } else {
- throw new Parse.Error(
- Parse.Error.INVALID_QUERY,
- 'Please purchase or renew your subscription.'
- );
- }
- } else {
- if (requests?.length > 0) {
- const newrequests = [requests?.[0]];
- const response = await axios.post('batch', { requests: newrequests }, parseConfig);
- // Handle the batch query response
- // console.log('Batch query response:', response.data);
- if (response.data && response.data.length > 0) {
- const document = Documents?.[0];
- const updateDocuments = {
- ...document,
- objectId: response.data[0]?.success?.objectId,
- createdAt: response.data[0]?.success?.createdAt,
- };
- deductcount(response.data.length, resExt.id);
- sendMail(updateDocuments, sessionToken);
- return 'success';
- }
- }
- }
- } catch (error) {
- const code = error?.response?.data?.code || error?.response?.status || error?.code || 400;
- const msg =
- error?.response?.data?.error ||
- error?.response?.data ||
- error?.message ||
- 'Something went wrong.';
- console.log('Error performing batch query:', code, msg);
- throw new Parse.Error(code, msg);
+ if (request?.user) {
+ return await batchQuery(request.user.id, Documents, Ip, parseConfig);
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ return await batchQuery(userId, Documents, Ip, parseConfig);
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.');
}
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.');
}
} else {
- throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
} catch (err) {
console.log('err in createbatchdoc', err);
const code = err?.code || 400;
const msg = err?.message || 'Something went wrong.';
- new Parse.Error(code, msg);
+ throw new Parse.Error(code, msg);
}
}
diff --git a/apps/OpenSignServer/cloud/parsefunction/getDocument.js b/apps/OpenSignServer/cloud/parsefunction/getDocument.js
index 8096ee915..112374e46 100644
--- a/apps/OpenSignServer/cloud/parsefunction/getDocument.js
+++ b/apps/OpenSignServer/cloud/parsefunction/getDocument.js
@@ -1,10 +1,12 @@
import axios from 'axios';
-import { cloudServerUrl } from '../../Utils.js';
+import { cloudServerUrl, parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
export default async function getDocument(request) {
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const docId = request.params.docId;
-
+ const jwttoken = request?.headers?.jwttoken || '';
+ const sessiontoken = request?.headers?.sessiontoken || '';
try {
if (docId) {
try {
@@ -27,12 +29,12 @@ export default async function getDocument(request) {
if (!IsEnableOTP) {
return document;
} else {
- if (request?.headers?.['sessiontoken']) {
+ if (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'],
+ 'X-Parse-Session-Token': sessiontoken,
},
});
const userId = userRes.data && userRes.data?.objectId;
@@ -46,6 +48,37 @@ export default async function getDocument(request) {
console.log('err user in not authenticated', err);
return { error: "You don't have access of this document!" };
}
+ } else if (jwttoken) {
+ try {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ const acl = res.getACL();
+ if (userId && acl && acl.getReadAccess(userId)) {
+ return document;
+ } else {
+ return { error: "You don't have access of this document!" };
+ }
+ } else {
+ return { status: 'error', result: 'Invalid token!' };
+ }
+ }
+ } catch (err) {
+ console.log('err in jwt', err);
+ return { error: "You don't have access of this document!" };
+ }
} else {
return { error: "You don't have access of this document!" };
}
diff --git a/apps/OpenSignServer/cloud/parsefunction/getSigners.js b/apps/OpenSignServer/cloud/parsefunction/getSigners.js
new file mode 100644
index 000000000..a8b1f9bb4
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/getSigners.js
@@ -0,0 +1,66 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
+export default async function getSigners(request) {
+ const jwttoken = request.headers.jwttoken || '';
+ const search = request.params.search || '';
+ const searchEmail = request.params.searchEmail || '';
+ try {
+ if (request.user) {
+ const contactbook = new Parse.Query('contracts_Contactbook');
+ contactbook.equalTo('CreatedBy', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: request?.user?.id,
+ });
+
+ if (search) {
+ contactbook.matches('Name', new RegExp(search, 'i'));
+ } else if (searchEmail) {
+ contactbook.matches('Email', new RegExp(searchEmail, 'i'));
+ }
+ contactbook.notEqualTo('IsDeleted', true);
+ const contactRes = await contactbook.find();
+ const _contactRes = JSON.parse(JSON.stringify(contactRes));
+ return _contactRes;
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ const contactbook = new Parse.Query('contracts_Contactbook');
+ contactbook.equalTo('CreatedBy', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ if (search) {
+ contactbook.matches('Name', new RegExp(search, 'i'));
+ } else if (searchEmail) {
+ contactbook.matches('Email', new RegExp(searchEmail, 'i'));
+ }
+ contactbook.notEqualTo('IsDeleted', true);
+ const contactRes = await contactbook.find({ useMasterKey: true });
+ const _contactRes = JSON.parse(JSON.stringify(contactRes));
+ return _contactRes;
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token');
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
+ }
+ } catch (err) {
+ console.log('err in get signers', err);
+ throw err;
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js b/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js
index 201acdc46..0538ae757 100644
--- a/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js
+++ b/apps/OpenSignServer/cloud/parsefunction/getSubscriptions.js
@@ -1,13 +1,57 @@
import axios from 'axios';
-import { cloudServerUrl } from '../../Utils.js';
+import { cloudServerUrl, parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = process.env.APP_ID;
export default async function getSubscription(request) {
const extUserId = request.params.extUserId || '';
const contactId = request.params.contactId || '';
const ispublic = request.params.ispublic || false;
+ const jwttoken = request.headers?.jwttoken || '';
- if (extUserId) {
+ if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const verifyToken = jwttoken;
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(verifyToken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ const extCls = new Parse.Query('contracts_Users');
+ extCls.equalTo('Email', decoded?.user_email);
+ const exUser = await extCls.first({ useMasterKey: true });
+ if (exUser) {
+ const subscriptionCls = new Parse.Query('contracts_Subscriptions');
+ subscriptionCls.equalTo('TenantId', {
+ __type: 'Pointer',
+ className: 'partners_Tenant',
+ objectId: exUser.get('TenantId').id,
+ });
+ subscriptionCls.descending('createdAt');
+ const subcripitions = await subscriptionCls.first({ useMasterKey: true });
+ if (subcripitions) {
+ const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
+ return { status: 'success', result: _subcripitions };
+ } else {
+ return { status: 'success', result: {} };
+ }
+ } else {
+ return { status: 'error', result: 'User not found!' };
+ }
+ } else {
+ return { status: 'error', result: 'Invalid token!' };
+ }
+ }
+ } else if (extUserId) {
try {
let userId;
//`ispublic` is used in public profile to get subscription details
diff --git a/apps/OpenSignServer/cloud/parsefunction/getTenant.js b/apps/OpenSignServer/cloud/parsefunction/getTenant.js
new file mode 100644
index 000000000..2b5957a0a
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/getTenant.js
@@ -0,0 +1,59 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+export default async function getTenant(request) {
+ const jwttoken = request.headers.jwttoken || '';
+ const userId = request.params.userId || '';
+ if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const verifyToken = jwttoken;
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(verifyToken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ try {
+ const tenantCreditsQuery = new Parse.Query('partners_Tenant');
+ tenantCreditsQuery.equalTo('UserId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ tenantCreditsQuery.exclude('FileAdapters');
+ tenantCreditsQuery.exclude('PfxFile');
+ const res = await tenantCreditsQuery.first({ useMasterKey: true });
+ if (res) {
+ return res;
+ }
+ } catch (e) {
+ return 'user does not exist!';
+ }
+ } else {
+ return { status: 'error', result: 'Invalid token!' };
+ }
+ }
+ } else if (userId) {
+ try {
+ const tenantCreditsQuery = new Parse.Query('partners_Tenant');
+ tenantCreditsQuery.equalTo('UserId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const res = await tenantCreditsQuery.first();
+ if (res) {
+ return res;
+ }
+ } catch (e) {
+ return 'user does not exist!';
+ }
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js b/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js
index 5feb7e16c..fa8228ed0 100644
--- a/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js
+++ b/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js
@@ -1,5 +1,9 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
async function getUserDetails(request) {
const reqEmail = request.params.email;
+ const jwttoken = request?.headers?.jwttoken || '';
if (reqEmail || request.user) {
try {
const userId = request.params.userId;
@@ -36,6 +40,48 @@ async function getUserDetails(request) {
const msg = err?.message || 'Something went wrong.';
throw new Parse.Error(code, msg);
}
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ try {
+ const userQuery = new Parse.Query('contracts_Users');
+ userQuery.equalTo('Email', decoded?.user_email);
+ userQuery.include('TenantId');
+ userQuery.include('UserId');
+ userQuery.include('CreatedBy');
+ userQuery.exclude('CreatedBy.authData');
+ userQuery.exclude('TenantId.FileAdapters');
+ userQuery.exclude('google_refresh_token');
+ userQuery.exclude('TenantId.PfxFile');
+ const res = await userQuery.first({ useMasterKey: true });
+ if (res) {
+ return res;
+ } else {
+ return '';
+ }
+ } catch (err) {
+ console.log('Err ', err);
+ const code = err?.code || 400;
+ const msg = err?.message || 'Something went wrong.';
+ throw new Parse.Error(code, msg);
+ }
+ } else {
+ return { status: 'error', result: 'Invalid token!' };
+ }
+ }
} else {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
diff --git a/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js b/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js
new file mode 100644
index 000000000..f9bcfe849
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js
@@ -0,0 +1,47 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
+export default async function isUserInContactBook(request) {
+ try {
+ const jwttoken = request.headers.jwttoken;
+ if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ const email = userRes?.get('email');
+ const userPtr = { __type: 'Pointer', className: '_User', objectId: userId };
+ const query = new Parse.Query('contracts_Contactbook');
+ query.equalTo('CreatedBy', userPtr);
+ query.notEqualTo('IsDeleted', true);
+ query.equalTo('Email', email);
+ const res = await query.first({ useMasterKey: true });
+ return res;
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token');
+ }
+ } else if (request.user) {
+ const email = request.user.get('email');
+ const userPtr = { __type: 'Pointer', className: '_User', objectId: request.user?.id };
+ const query = new Parse.Query('contracts_Contactbook');
+ query.equalTo('CreatedBy', userPtr);
+ query.notEqualTo('IsDeleted', true);
+ query.equalTo('Email', email);
+ const res = await query.first();
+ return res;
+ }
+ } catch (err) {
+ console.log('err', err);
+ throw err;
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/saveFile.js b/apps/OpenSignServer/cloud/parsefunction/saveFile.js
new file mode 100644
index 000000000..6538f70ab
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/saveFile.js
@@ -0,0 +1,131 @@
+import uploadFileToS3 from './uploadFiletoS3.js';
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+export default async function saveFile(request) {
+ const jwttoken = request.headers.jwttoken || '';
+
+ if (!request.params.fileBase64) {
+ throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide file.');
+ }
+ const fileBase64 = request.params.fileBase64;
+ const id = request.params.id;
+ try {
+ if (request.user) {
+ const extCls = new Parse.Query('contracts_Users');
+ extCls.equalTo('UserId', request.user);
+ extCls.include('TenantId');
+ const resExt = await extCls.first({ useMasterKey: true });
+ if (resExt) {
+ const _resExt = JSON.parse(JSON.stringify(resExt));
+ const fileAdapters = _resExt?.TenantId.FileAdapters || [];
+ const fileAdapter = fileAdapters?.find(x => x.id === id) || {};
+ if (fileAdapter?.accessKeyId) {
+ const adapterConfig = {
+ id: id,
+ fileAdapter: fileAdapter?.fileAdapter,
+ bucketName: fileAdapter?.bucketName,
+ region: fileAdapter?.region,
+ endpoint: fileAdapter?.endpoint,
+ accessKeyId: fileAdapter?.accessKeyId,
+ secretAccessKey: fileAdapter?.secretAccessKey,
+ baseUrl: fileAdapter?.baseUrl,
+ };
+ const buffer = Buffer.from(fileBase64, 'base64');
+ const fileName = request.params.fileName;
+ const ext = request.params.fileName?.split('.')?.pop();
+ let mimeType;
+ if (ext === 'pdf') {
+ mimeType = 'application/pdf';
+ } else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') {
+ mimeType = `image/${ext}`;
+ }
+ try {
+ const presignedUrl = await uploadFileToS3(buffer, fileName, mimeType, adapterConfig);
+ return { url: presignedUrl };
+ } catch (err) {
+ console.error('Error generate presigned url:', err);
+ const msg = 'Fileadapter credentials are invalid.';
+ throw new Parse.Error(400, msg);
+ }
+ } else {
+ const fileName = request.params.fileName;
+ const pdfFile = new Parse.File(fileName, { base64: fileBase64 });
+ // Save the Parse File if needed
+ const pdfData = await pdfFile.save({ useMasterKey: true });
+ const presignedUrl = pdfData.url();
+ return { url: presignedUrl };
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ }
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ const extCls = new Parse.Query('contracts_Users');
+ extCls.equalTo('Email', decoded?.user_email);
+ extCls.include('TenantId');
+ const resExt = await extCls.first({ useMasterKey: true });
+ if (resExt) {
+ const _resExt = JSON.parse(JSON.stringify(resExt));
+ const fileAdapters = _resExt?.TenantId.FileAdapters || [];
+ const fileAdapter = fileAdapters?.find(x => x.id === id) || {};
+ if (fileAdapter?.accessKeyId) {
+ const adapterConfig = {
+ id: id,
+ fileAdapter: fileAdapter?.fileAdapter,
+ bucketName: fileAdapter?.bucketName,
+ region: fileAdapter?.region,
+ endpoint: fileAdapter?.endpoint,
+ accessKeyId: fileAdapter?.accessKeyId,
+ secretAccessKey: fileAdapter?.secretAccessKey,
+ baseUrl: fileAdapter?.baseUrl,
+ };
+ const buffer = Buffer.from(fileBase64, 'base64');
+ const fileName = request.params.fileName;
+ const ext = request.params.fileName?.split('.')?.pop();
+ let mimeType;
+ if (ext === 'pdf') {
+ mimeType = 'application/pdf';
+ } else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') {
+ mimeType = `image/${ext}`;
+ }
+ try {
+ const presignedUrl = await uploadFileToS3(buffer, fileName, mimeType, adapterConfig);
+ return { url: presignedUrl };
+ } catch (err) {
+ console.error('Error generate presigned url:', err);
+ const msg = 'Fileadapter credentials are invalid.';
+ throw new Parse.Error(400, msg);
+ }
+ } else {
+ const fileName = request.params.fileName;
+ const pdfFile = new Parse.File(fileName, { base64: fileBase64 });
+ // Save the Parse File if needed
+ const pdfData = await pdfFile.save({ useMasterKey: true });
+ const presignedUrl = pdfData.url();
+ return { url: presignedUrl };
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ }
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
+ }
+ } catch (err) {
+ console.log('err in savetoS3', err);
+ throw err;
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/saveTemplate.js b/apps/OpenSignServer/cloud/parsefunction/saveTemplate.js
new file mode 100644
index 000000000..687a3e334
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/saveTemplate.js
@@ -0,0 +1,110 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
+async function updateTemplate(template, isJwt = false) {
+ try {
+ if (template?.Id) {
+ const updateTemplate = new Parse.Object('contracts_Template');
+ updateTemplate.id = template.Id;
+ if (template?.URL) {
+ updateTemplate.set('URL', template.URL);
+ }
+ if (template?.Name) {
+ updateTemplate.set('Name', template.Name);
+ }
+ if (template?.Note) {
+ updateTemplate.set('Note', template.Note);
+ }
+ if (template?.Description) {
+ updateTemplate.set('Description', template.Description);
+ }
+ if (template?.SendinOrder) {
+ updateTemplate.set('SendinOrder', template.SendinOrder);
+ }
+ if (template?.AutomaticReminders) {
+ updateTemplate.set('AutomaticReminders', template.AutomaticReminders);
+ }
+ if (template?.RemindOnceInEvery) {
+ updateTemplate.set('RemindOnceInEvery', template.RemindOnceInEvery);
+ }
+ if (template?.NextReminderDate) {
+ updateTemplate.set('NextReminderDate', new Date(template.NextReminderDate));
+ }
+ if (template?.IsEnableOTP) {
+ updateTemplate.set('IsEnableOTP', template.IsEnableOTP);
+ }
+ if (template?.IsTourEnabled) {
+ updateTemplate.set('IsTourEnabled', template.IsTourEnabled);
+ }
+ const isPublic = template?.IsPublic !== undefined ? template?.IsPublic : false;
+ if (template?.IsPublic !== undefined) {
+ updateTemplate.set('IsPublic', isPublic);
+ }
+ updateTemplate.set('Placeholders', template.Placeholders);
+ updateTemplate.set('Signers', template.Signers);
+
+ let updateTemplateRes;
+ if (isJwt) {
+ updateTemplateRes = await updateTemplate.save(null, { useMasterKey: true });
+ } else {
+ updateTemplateRes = await updateTemplate.save();
+ }
+ return updateTemplateRes;
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide Id.');
+ }
+ } catch (err) {
+ console.log('err in update template', err);
+ throw err;
+ }
+}
+export default async function saveTemplate(request) {
+ const jwttoken = request.headers.jwttoken || '';
+ const template = {
+ Id: request.params?.templateId,
+ URL: request.params?.URL || '',
+ Name: request.params?.Name,
+ Note: request.params?.Note,
+ Description: request.params?.Description,
+ Placeholders: request.params?.Placeholders,
+ Signers: request.params?.Signers,
+ SendMail: request.params?.SendMail || false,
+ SendinOrder: request.params?.SendinOrder || true,
+ AutomaticReminders: request.params?.AutomaticReminders,
+ RemindOnceInEvery: parseInt(request.params.RemindOnceInEvery) || 15,
+ NextReminderDate: request.params?.NextReminderDate,
+ IsEnableOTP: request.params?.IsEnableOTP === true ? true : false,
+ IsTourEnabled: request.params?.IsTourEnabled === true ? true : false,
+ IsPublic: request.params?.IsPublic,
+ };
+
+ try {
+ if (request.user) {
+ return await updateTemplate(template);
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ return await updateTemplate(template, true);
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token');
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
+ }
+ } catch (err) {
+ console.log('err in get signers', err);
+ throw err;
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/savecontact.js b/apps/OpenSignServer/cloud/parsefunction/savecontact.js
new file mode 100644
index 000000000..6cf16b5b2
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/savecontact.js
@@ -0,0 +1,180 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
+export default async function savecontact(request) {
+ const name = request.params.name;
+ const phone = request.params.phone;
+ const email = request.params.email;
+ const tenantId = request.params.tenantId;
+ const jwttoken = request.headers.jwttoken;
+
+ if (request.user) {
+ const currentUser = request?.user;
+ const currentUserPtr = { __type: 'Pointer', className: '_User', objectId: currentUser?.id };
+ const query = new Parse.Query('contracts_Contactbook');
+ query.equalTo('CreatedBy', currentUserPtr);
+ query.notEqualTo('IsDeleted', true);
+ query.equalTo('Email', email);
+ const res = await query.first();
+ if (!res) {
+ const contactQuery = new Parse.Object('contracts_Contactbook');
+ contactQuery.set('Name', name);
+ if (phone) {
+ contactQuery.set('Phone', phone);
+ }
+ contactQuery.set('Email', email);
+ contactQuery.set('UserRole', 'contracts_Guest');
+
+ if (tenantId) {
+ contactQuery.set('TenantId', {
+ __type: 'Pointer',
+ className: 'partners_Tenant',
+ objectId: tenantId,
+ });
+ }
+
+ try {
+ const _users = Parse.Object.extend('User');
+ const _user = new _users();
+ _user.set('name', name);
+ _user.set('username', email);
+ _user.set('email', email);
+ _user.set('password', email);
+ if (phone) {
+ _user.set('phone', phone);
+ }
+
+ const user = await _user.save();
+ if (user) {
+ contactQuery.set('CreatedBy', currentUserPtr);
+ contactQuery.set('UserId', user);
+ const acl = new Parse.ACL();
+ acl.setPublicReadAccess(true);
+ acl.setPublicWriteAccess(true);
+ acl.setReadAccess(currentUser.id, true);
+ acl.setWriteAccess(currentUser.id, true);
+ contactQuery.setACL(acl);
+
+ const res = await contactQuery.save();
+ const parseData = JSON.parse(JSON.stringify(res));
+ return parseData;
+ }
+ } catch (err) {
+ console.log('err ', err);
+ if (err.code === 202) {
+ const params = { email: email };
+ const userRes = await Parse.Cloud.run('getUserId', params);
+ contactQuery.set('CreatedBy', currentUserPtr);
+ contactQuery.set('UserId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userRes.id,
+ });
+ const acl = new Parse.ACL();
+ acl.setPublicReadAccess(true);
+ acl.setPublicWriteAccess(true);
+ acl.setReadAccess(currentUser.id, true);
+ acl.setWriteAccess(currentUser.id, true);
+ contactQuery.setACL(acl);
+ const res = await contactQuery.save();
+ const parseData = JSON.parse(JSON.stringify(res));
+ return parseData;
+ }
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
+ }
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ const currentUser = userRes;
+ const currentUserPtr = { __type: 'Pointer', className: '_User', objectId: userId };
+ if (decoded?.user_email) {
+ const query = new Parse.Query('contracts_Contactbook');
+ query.equalTo('CreatedBy', currentUserPtr);
+ query.notEqualTo('IsDeleted', true);
+ query.equalTo('Email', email);
+ const res = await query.first();
+ if (!res) {
+ const contactQuery = new Parse.Object('contracts_Contactbook');
+ contactQuery.set('Name', name);
+ if (phone) {
+ contactQuery.set('Phone', phone);
+ }
+ contactQuery.set('Email', email);
+ contactQuery.set('UserRole', 'contracts_Guest');
+
+ if (tenantId) {
+ contactQuery.set('TenantId', {
+ __type: 'Pointer',
+ className: 'partners_Tenant',
+ objectId: tenantId,
+ });
+ }
+ try {
+ const _users = Parse.Object.extend('User');
+ const _user = new _users();
+ _user.set('name', name);
+ _user.set('username', email);
+ _user.set('email', email);
+ _user.set('password', email);
+ if (phone) {
+ _user.set('phone', phone);
+ }
+
+ const user = await _user.save();
+ if (user) {
+ contactQuery.set('CreatedBy', currentUserPtr);
+ contactQuery.set('UserId', user);
+ const acl = new Parse.ACL();
+ acl.setPublicReadAccess(true);
+ acl.setPublicWriteAccess(true);
+ acl.setReadAccess(currentUser.id, true);
+ acl.setWriteAccess(currentUser.id, true);
+ contactQuery.setACL(acl);
+
+ const res = await contactQuery.save();
+ const parseData = JSON.parse(JSON.stringify(res));
+ return parseData;
+ }
+ } catch (err) {
+ console.log('err ', err);
+ if (err.code === 202) {
+ const params = { email: email };
+ const userRes = await Parse.Cloud.run('getUserId', params);
+ contactQuery.set('CreatedBy', currentUserPtr);
+ contactQuery.set('UserId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userRes.id,
+ });
+ const acl = new Parse.ACL();
+ acl.setPublicReadAccess(true);
+ acl.setPublicWriteAccess(true);
+ acl.setReadAccess(currentUser.id, true);
+ acl.setWriteAccess(currentUser.id, true);
+ contactQuery.setACL(acl);
+ const res = await contactQuery.save();
+ const parseData = JSON.parse(JSON.stringify(res));
+ return parseData;
+ }
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.');
+ }
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js b/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js
index fc3aab26b..5c44e5b88 100644
--- a/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js
+++ b/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js
@@ -65,7 +65,7 @@ async function sendMailProvider(req, plan, monthchange) {
const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`;
const file = {
filename: pdfName || 'exported.pdf',
- content: smtpenable ? PdfBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'),
+ content: smtpenable ? PdfBuffer : undefined,
data: smtpenable ? undefined : PdfBuffer,
};
diff --git a/apps/OpenSignServer/cloud/parsefunction/updateToPublicTemplate.js b/apps/OpenSignServer/cloud/parsefunction/updateToPublicTemplate.js
new file mode 100644
index 000000000..40af4f876
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/updateToPublicTemplate.js
@@ -0,0 +1,63 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
+async function updateTemplate(template, isJwt = false) {
+ try {
+ if (template?.Id) {
+ const updateTemplate = new Parse.Object('contracts_Template');
+ updateTemplate.id = template.Id;
+
+ const isPublic = template?.IsPublic !== undefined ? template?.IsPublic : false;
+ if (template?.IsPublic !== undefined) {
+ updateTemplate.set('IsPublic', isPublic);
+ }
+
+ let updateTemplateRes;
+ if (isJwt) {
+ updateTemplateRes = await updateTemplate.save(null, { useMasterKey: true });
+ } else {
+ updateTemplateRes = await updateTemplate.save();
+ }
+ return updateTemplateRes;
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide Id.');
+ }
+ } catch (err) {
+ console.log('err in update template', err);
+ throw err;
+ }
+}
+export default async function updateToPublicTemplate(request) {
+ const jwttoken = request.headers.jwttoken || '';
+ const template = { Id: request.params.templateId, IsPublic: request.params?.IsPublic };
+
+ try {
+ if (request.user) {
+ return await updateTemplate(template);
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ return await updateTemplate(template, true);
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token');
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
+ }
+ } catch (err) {
+ console.log('err in get signers', err);
+ throw err;
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js b/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js
new file mode 100644
index 000000000..1636ac278
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js
@@ -0,0 +1,58 @@
+import { parseJwt } from '../../Utils.js';
+import jwt from 'jsonwebtoken';
+
+export default async function updateTourStatus(request) {
+ const tourstatus = request.params.TourStatus;
+ const extUserId = request.params.ExtUserId;
+ const jwttoken = request?.headers?.jwttoken || '';
+ if (request.user) {
+ try {
+ const updateUser = new Parse.Object('contracts_Users');
+ updateUser.id = extUserId;
+ updateUser.set('TourStatus', tourstatus);
+ const res = await updateUser.save();
+ return res;
+ } catch (err) {
+ console.log('Err ', err);
+ const code = err?.code || 400;
+ const msg = err?.message || 'Something went wrong.';
+ throw new Parse.Error(code, msg);
+ }
+ } else if (jwttoken) {
+ const jwtDecode = parseJwt(jwttoken);
+ if (jwtDecode?.user_email) {
+ const userCls = new Parse.Query(Parse.User);
+ userCls.equalTo('email', jwtDecode?.user_email);
+ const userRes = await userCls.first({ useMasterKey: true });
+ const userId = userRes?.id;
+ const tokenQuery = new Parse.Query('appToken');
+ tokenQuery.equalTo('userId', {
+ __type: 'Pointer',
+ className: '_User',
+ objectId: userId,
+ });
+ const appRes = await tokenQuery.first({ useMasterKey: true });
+ const decoded = jwt.verify(jwttoken, appRes?.get('token'));
+ if (decoded?.user_email) {
+ try {
+ const updateUser = new Parse.Object('contracts_Users');
+ updateUser.id = extUserId;
+ updateUser.set('TourStatus', tourstatus);
+ const res = await updateUser.save(null, { useMasterKey: true });
+ return res;
+ } catch (err) {
+ console.log('Err ', err);
+ const code = err?.code || 400;
+ const msg = err?.message || 'Something went wrong.';
+ throw new Parse.Error(code, msg);
+ }
+ } else {
+ return { status: 'error', result: 'Invalid token!' };
+ }
+ } else {
+ return { status: 'error', result: 'Invalid token!' };
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
+ }
+}