);
};
+ // `handleQuickSendClose` is trigger when bulk send component trigger close event
+ const handleQuickSendClose = (status, count) => {
+ setIsBulkSend({});
+ setIsAlert(true);
+ if (status === "success") {
+ if (count > 1) {
+ setAlertMsg({
+ type: "success",
+ message: count + " Document sent successfully!"
+ });
+ setTimeout(() => setIsAlert(false), 1500);
+ } else {
+ setAlertMsg({
+ type: "success",
+ message: count + " Document sent successfully!"
+ });
+ setTimeout(() => setIsAlert(false), 1500);
+ }
+ } else {
+ setAlertMsg({
+ type: "danger",
+ message: "Something went wrong, Please try again later!"
+ });
+ setTimeout(() => setIsAlert(false), 1500);
+ }
+ };
+
+ // `handleBulkSend` is used to open modal as well as fetch template
+ // and show Ui on the basis template response
+ const handleBulkSend = async (template) => {
+ setIsBulkSend({ [template.objectId]: true });
+ setIsLoader({ [template.objectId]: true });
+ try {
+ const params = {
+ templateId: template.objectId,
+ include: ["Placeholders.signerPtr"]
+ };
+ const axiosRes = await axios.post(
+ `${localStorage.getItem("baseUrl")}functions/getTemplate`,
+ params,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
+ sessionToken: localStorage.getItem("accesstoken")
+ }
+ }
+ );
+ const templateRes = axiosRes.data && axiosRes.data.result;
+ if (templateRes?.Placeholders?.length > 0) {
+ setPlaceholders(templateRes?.Placeholders);
+ setTemplateDetails(templateRes);
+ setIsLoader({});
+ } else {
+ setIsLoader(false);
+ setIsDocErr(true);
+ }
+ } catch (err) {
+ console.log("err in fetch template in bulk modal", err);
+ setIsBulkSend({});
+ setIsDocErr(false);
+ setIsAlert(true);
+ setAlertMsg({
+ type: "danger",
+ message: "Something went wrong, Please try again later!"
+ });
+ setTimeout(() => setIsAlert(false), 1500);
+ }
+ };
return (
{Object.keys(actLoader)?.length > 0 && (
@@ -793,11 +869,11 @@ const ReportTable = (props) => {
)}
{isOption[item.objectId] &&
act.action === "option" && (
-
+
{act.subaction?.map((subact) => (
handleActionBtn(subact, item)
}
@@ -849,6 +925,36 @@ const ReportTable = (props) => {
)}
+ {isBulkSend[item.objectId] && (
+
setIsBulkSend({})}
+ >
+ {isLoader[item.objectId] ? (
+
+ ) : (
+ <>
+ {isDocErr ? (
+
+ Please add Signers or Roles in template
+
+ ) : (
+
+ )}
+ >
+ )}
+
+ )}
{isShare[item.objectId] && (
{
closePopup={handleContactFormModal}
/>
-
setIsDocErr(false)}
- >
-
-
Please add receipent in template!
-
-
);
diff --git a/apps/OpenSign/src/styles/loginPage.css b/apps/OpenSign/src/styles/loginPage.css
deleted file mode 100644
index 0c18fe779..000000000
--- a/apps/OpenSign/src/styles/loginPage.css
+++ /dev/null
@@ -1,197 +0,0 @@
-.loginInput {
- padding: 10px;
- border-radius: 4px;
- width: 100%;
- font-size: 0.75rem;
- border: 1px solid #e2dddd;
- background-color: #e0e5f5;
- color: black;
- padding-left: 1rem !important;
- padding-right: 1rem !important;
- padding-top: 0.5rem !important;
- font-family: inherit;
- font-feature-settings: inherit;
- font-variation-settings: inherit;
- font-weight: inherit;
- overflow: visible;
-}
-.loginInput:focus {
- outline: none;
- border: none;
-}
-.verifyBtn {
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
- padding: 3px 30px;
- color: white;
- font-weight: 500 !important;
- font-size: 14px !important;
- border: none;
-}
-.verifyBtn:focus {
- border: none;
- outline: none;
-}
-
-.verifyBtn:hover {
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
- color: white;
-}
-.fakeimg {
- height: 200px;
- background: #aaa;
-}
-
-.GTRY {
- border: 1px solid #dee2e6;
- margin-top: 75px;
- padding-bottom: 20px;
- background-color: #fff;
-}
-
-.main_head {
- width: 100%;
- height: 66px;
- background-color: #fff;
- margin-bottom: 52px;
- padding-top: 10px;
-}
-
-.main-logo {
- width: 250px;
- height: 66px;
- display: inline-block;
-}
-
-.card-box {
- background: #fff;
- min-height: 50px;
- box-shadow: 0 20px 20px rgba(0, 0, 0, 0.1);
- position: relative;
- margin-bottom: 20px;
- transition: 0.5s;
- border: 1px solid #f2f2f2;
- border-radius: 7px;
- margin-top: 10px;
-}
-
-.LKJH {
- display: flex;
-}
-
-.GTR {
- text-align: left;
-}
-
-.JUI {
- text-align: right;
-}
-
-.btn-info {
- color: #fff;
- background-color: #15b4e9;
- border-color: #15b4e9;
-}
-
-.btn-info:hover {
- color: #fff;
- background-color: #15b4e9;
- border-color: #15b4e9;
-}
-
-.btn-reg {
- color: #15b4e9;
- background-color: #ffffff;
- border-color: #15b4e9;
-}
-
-.btn-reg:hover {
- color: #15b4e9;
- background-color: #ffffff;
- border-color: #15b4e9;
-}
-
-.SYTU {
- display: flex;
-}
-
-.MLKI {
- float: right;
- margin-bottom: 12px;
-}
-
-.login-btn {
- width: 100% !important;
- display: block !important;
-}
-
-@media only screen and (max-width: 667px) {
- .MLKI {
- float: inherit;
- }
-
- .login-btn {
- width: 210px !important;
- }
-}
-
-.MLKI a {
- color: #212529;
-}
-
-.KNLO {
- color: #878787;
- font-size: 13px;
-}
-
-.form-check-label {
- margin-left: 17px;
- margin-bottom: 12px;
-}
-.welcomeText {
- font-size: 30px;
-}
-
-@media only screen and (max-width: 600px) {
- .KLO1 {
- display: none;
- }
-
- .MLKI a {
- font-size: 12px;
- }
-
- .form-check-label {
- font-size: 12px;
- margin-bottom: 14px;
- }
-
- .MKUY {
- text-align: center;
- padding-top: 10px;
- }
-
- .main_head {
- margin-bottom: 12px;
- padding-top: 10px;
- border-bottom: 1px dashed #eeeeee;
- }
-}
-@media screen and (max-width: 366px) {
- .main-logo {
- width: 150px;
- height: 46px;
- display: inline-block;
- }
- .welcomeText {
- font-size: 20px;
- }
- .KNLO {
- color: #878787;
- font-size: 10px;
- }
- .btnContainer {
- display: flex;
- justify-content: center;
- align-items: center;
- }
-}
diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js
index bc6cb66a2..32a047a3f 100644
--- a/apps/OpenSignServer/cloud/main.js
+++ b/apps/OpenSignServer/cloud/main.js
@@ -37,7 +37,27 @@ import saveSubscription from './parsefunction/saveSubscription.js';
import VerifyEmail from './parsefunction/VerifyEmail.js';
import encryptedpdf from './parsefunction/encryptedPdf.js';
import { getSignedUrl } from './parsefunction/getSignedUrl.js';
+import createBatchDocs from './parsefunction/createBatchDocs.js';
+import linkContactToDoc from './parsefunction/linkContactToDoc.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);
+Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
+Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
+Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
+
+// This beforeSave function triggers before an object is added or updated in the specified class, allowing for validation or modification.
+Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
+Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
+
+// This afterFind function triggers after a query retrieves objects from the specified class, allowing for post-processing of the results.
+Parse.Cloud.afterFind(Parse.User, UserAfterFind);
+Parse.Cloud.afterFind('contracts_Document', DocumentBeforeFind);
+Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind);
+Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
+Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
+
+// This define function creates a custom Cloud Function that can be called from the client-side, enabling custom business logic on the server.
Parse.Cloud.define('AddUserToRole', addUserToGroups);
Parse.Cloud.define('UserGroups', getUserGroups);
Parse.Cloud.define('signPdf', PDF);
@@ -62,18 +82,9 @@ Parse.Cloud.define('freesubscription', SubscribeFree);
Parse.Cloud.define('getinvoices', getInvoices);
Parse.Cloud.define('getpayments', getPayments);
Parse.Cloud.define('getsubscriptions', getSubscriptions);
-Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
-Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
-Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
-Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
-Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
-Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
-Parse.Cloud.afterFind(Parse.User, UserAfterFind);
-Parse.Cloud.afterFind('contracts_Document', DocumentBeforeFind);
-Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind);
-Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
-Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
Parse.Cloud.define('savesubscription', saveSubscription);
Parse.Cloud.define('verifyemail', VerifyEmail);
Parse.Cloud.define('encryptedpdf', encryptedpdf);
Parse.Cloud.define('getsignedurl', getSignedUrl);
+Parse.Cloud.define('batchdocuments', createBatchDocs);
+Parse.Cloud.define('linkcontacttodoc', linkContactToDoc);
diff --git a/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js
new file mode 100644
index 000000000..b18f70a91
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/createBatchDocs.js
@@ -0,0 +1,173 @@
+import axios from 'axios';
+
+const serverUrl = process.env.SERVER_URL;
+const appId = process.env.APP_ID;
+
+async function sendMail(document, sessionToken) {
+ const baseUrl = new URL(process.env.PUBLIC_URL);
+
+ // console.log("pdfDetails", pdfDetails);
+ const timeToCompleteDays = document?.TimeToCompleteDays || 15;
+ const ExpireDate = new Date(document.createdAt);
+ ExpireDate.setDate(ExpireDate.getDate() + timeToCompleteDays);
+ const newDate = ExpireDate;
+ const localExpireDate = newDate.toLocaleDateString('en-US', {
+ day: 'numeric',
+ month: 'long',
+ year: 'numeric',
+ });
+ const sender = document.ExtUserPtr.Email;
+ const signerMail = document.Placeholders;
+ for (let i = 0; i < signerMail.length; i++) {
+ try {
+ const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
+ let url = `${serverUrl}/functions/sendmailv3`;
+ const headers = {
+ 'Content-Type': 'application/json',
+ 'X-Parse-Application-Id': appId,
+ sessionToken: sessionToken,
+ };
+ const objectId = signerMail[i]?.signerObjId;
+ const hostUrl = baseUrl.origin;
+ let encodeBase64;
+ if (objectId) {
+ encodeBase64 = btoa(`${document.objectId}/${signerMail[i].signerPtr.Email}/${objectId}`);
+ } else {
+ encodeBase64 = btoa(`${document.objectId}/${signerMail[i].email}`);
+ }
+ let signPdf = `${hostUrl}/login/${encodeBase64}`;
+ const openSignUrl = 'https://www.opensignlabs.com/';
+ const orgName = document.ExtUserPtr.Company ? document.ExtUserPtr.Company : '';
+ const themeBGcolor = '#47a3ad';
+ let params = {
+ extUserId: document.ExtUserPtr.objectId,
+ recipient: objectId ? signerMail[i].signerPtr.Email : signerMail[i].email,
+ subject: `${document.ExtUserPtr.Name} has requested you to sign ${document.Name}`,
+ from: sender,
+ html:
+ "
Digital Signature Request
" +
+ document.ExtUserPtr.Name +
+ ' has requested you to review and sign ' +
+ document.Name +
+ ".
| Sender | | " +
+ sender +
+ " |
| Organization | | " +
+ orgName +
+ " |
| Expires on | | " +
+ localExpireDate +
+ " |
| |
This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
+ sender +
+ ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ here.
',
+ };
+ const sendMail = await axios.post(url, params, { headers: headers });
+ // if (sendMail.data.result.status === 'success') {
+ // console.log('batch login mail sent');
+ // }
+ } catch (error) {
+ console.log('error', error);
+ }
+ }
+}
+export default async function createBatchDocs(request) {
+ const strDocuments = request.params.Documents;
+ const sessionToken = request.headers['sessiontoken'];
+ const Documents = JSON.parse(strDocuments);
+ const Ip = request?.headers?.['x-real-ip'] || '';
+ // console.log('Documents ', Documents);
+ const parseConfig = {
+ baseURL: serverUrl, //localStorage.getItem('baseUrl'),
+ headers: {
+ 'X-Parse-Application-Id': appId,
+ 'X-Parse-Session-Token': sessionToken,
+ 'Content-Type': 'application/json',
+ },
+ };
+ 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,
+ Signers: allSigner?.map(y => ({
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: y.objectId,
+ })),
+ ACL: Acl,
+ RemindOnceInEvery: x.RemindOnceInEvery || 5,
+ AutomaticReminders: x.AutomaticReminders || false,
+ TimeToCompleteDays: x.TimeToCompleteDays || 15,
+ OriginIp: Ip,
+ DocSentAt: { __type: 'Date', iso: isoDate },
+ },
+ };
+ });
+ // console.log('requests ', requests);
+
+ 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,
+ }));
+ for (let i = 0; i < updateDocuments.length; i++) {
+ // console.log('updateDocuments ', updateDocuments);
+ sendMail(updateDocuments[i], sessionToken);
+ }
+ return 'success';
+ }
+
+ // Handle individual responses within response.data.results
+ } catch (error) {
+ console.error('Error performing batch query:', error);
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/getReport.js b/apps/OpenSignServer/cloud/parsefunction/getReport.js
index 8749c2b28..cd101f7c2 100644
--- a/apps/OpenSignServer/cloud/parsefunction/getReport.js
+++ b/apps/OpenSignServer/cloud/parsefunction/getReport.js
@@ -30,7 +30,7 @@ export default async function getReport(request) {
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
- const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`;
+ const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr`;
const res = await axios.get(url, { headers: headers });
if (res.data && res.data.results) {
return res.data.results;
diff --git a/apps/OpenSignServer/cloud/parsefunction/linkContactToDoc.js b/apps/OpenSignServer/cloud/parsefunction/linkContactToDoc.js
new file mode 100644
index 000000000..5b0f03442
--- /dev/null
+++ b/apps/OpenSignServer/cloud/parsefunction/linkContactToDoc.js
@@ -0,0 +1,276 @@
+// `saveRoleContact` is used to save user in contracts_Guest role and create contact
+const saveRoleContact = async contact => {
+ try {
+ const Role = new Parse.Query(Parse.Role);
+ const guestRole = await Role.equalTo('name', 'contracts_Guest').first();
+ if (guestRole) {
+ // Check if the user is already in the role
+ const relation = guestRole.relation('users');
+ const usersInRoleQuery = relation.query();
+ usersInRoleQuery.equalTo('objectId', contact.UserId.objectId);
+ const usersInRole = await usersInRoleQuery.find();
+ if (usersInRole.length > 0) {
+ console.log('User already added to Guest role.');
+ } else {
+ relation.add({ __type: 'Pointer', className: '_User', id: contact.UserId.objectId });
+ await guestRole.save(null, { useMasterKey: true });
+ // console.log('User added to Guest role successfully.');
+ }
+ }
+ } catch (err) {
+ console.log('err in role save', err);
+ }
+ const contactQuery = new Parse.Object('contracts_Contactbook');
+ contactQuery.set('Name', contact.Name);
+ contactQuery.set('Email', contact.Email);
+ if (contact?.Phone) {
+ contactQuery.set('Phone', contact.Phone);
+ }
+ contactQuery.set('CreatedBy', contact.CreatedBy);
+ contactQuery.set('UserId', contact.UserId);
+ contactQuery.set('UserRole', 'contracts_Guest');
+ contactQuery.set('TenantId', contact.TenantId);
+ contactQuery.set('IsDeleted', false);
+ const acl = new Parse.ACL();
+ acl.setReadAccess(contact.CreatedBy.objectId, true);
+ acl.setWriteAccess(contact.CreatedBy.objectId, true);
+ acl.setReadAccess(contact.UserId.objectId, true);
+ acl.setWriteAccess(contact.UserId.objectId, true);
+ contactQuery.setACL(acl);
+ const contactRes = await contactQuery.save();
+ if (contactRes) {
+ return contactRes;
+ }
+};
+
+// `linkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
+// save contact pointer in placeholder, signers and ACL of Document
+export default async function linkContactToDoc(req) {
+ const email = req.params.email;
+ const docId = req.params.docId;
+ const name = req.params.name;
+ const phone = req.params.phone;
+ try {
+ if (docId) {
+ // Execute the query to get the document with the specified 'docId'
+ const docQuery = new Parse.Query('contracts_Document');
+ docQuery.include('ExtUserPtr');
+ const docRes = await docQuery.get(docId, { useMasterKey: true });
+ // Check if the document was found; if not, throw an error indicating the document was not found
+ if (!docRes) {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
+ }
+ const _docRes = JSON.parse(JSON.stringify(docRes));
+ const Placeholders = _docRes?.Placeholders || [];
+ const index = Placeholders?.findIndex(x => x.email && x.email === email);
+ if (index !== -1) {
+ // `signerObjectId` holds the value of `signerObjId` from the `Placeholders` array at the current index.
+ // This value is used to check if `signerObjId` is present or not.
+ const signerObjectId = Placeholders[index]?.signerObjId;
+ if (signerObjectId) {
+ return { contactId: signerObjectId };
+ }
+ // Execute the query to check if a contact already exists in the 'contracts_Contactbook' class
+ const contactCls = new Parse.Query('contracts_Contactbook');
+ contactCls.equalTo('Email', email);
+ contactCls.equalTo('CreatedBy', _docRes.CreatedBy);
+ contactCls.notEqualTo('IsDeleted', true);
+ const existContact = await contactCls.first({ useMasterKey: true });
+ if (existContact) {
+ //update contact in placeholder, signers and update ACl in provide document
+ const updateDoc = new Parse.Object('contracts_Document');
+ updateDoc.id = docId;
+ const signers = _docRes?.Signers || [];
+ signers.push({
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: existContact.id,
+ });
+ updateDoc.set('Signers', signers);
+
+ Placeholders[index] = {
+ ...Placeholders[index],
+ signerObjId: existContact.id,
+ signerPtr: {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: existContact.id,
+ },
+ };
+ updateDoc.set('Placeholders', Placeholders);
+ const Acl = docRes.getACL();
+ Acl.setReadAccess(existContact.get('CreatedBy').id, true);
+ Acl.setWriteAccess(existContact.get('CreatedBy').id, true);
+ updateDoc.setACL(Acl);
+ // const parseData = JSON.parse(JSON.stringify(res));
+ const resDoc = await updateDoc.save(null, { useMasterKey: true });
+ if (resDoc) {
+ return { contactId: existContact.id };
+ }
+ } else {
+ // Execute the query to check if a user already exists in the 'contracts_Users' class
+ const extUserQuery = new Parse.Query('contracts_Users');
+ extUserQuery.equalTo('Email', email);
+ const extUser = await extUserQuery.first({ useMasterKey: true });
+ if (extUser) {
+ const _extUser = JSON.parse(JSON.stringify(extUser));
+ const contact = {
+ UserId: _extUser.UserId,
+ Name: _extUser.Name,
+ Email: email,
+ Phone: _extUser?.Phone ? _extUser.Phone : '',
+ CreatedBy: _docRes.CreatedBy,
+ TenantId: _docRes.ExtUserPtr.TenantId,
+ };
+ // if user present on platform create contact on the basis of extended user details
+ const contactRes = await saveRoleContact(contact);
+ //update contact in placeholder, signers and update ACl in provide document
+ const updateDoc = new Parse.Object('contracts_Document');
+ updateDoc.id = docId;
+ const signers = _docRes?.Signers || [];
+ signers.push({
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: contactRes.id,
+ });
+ updateDoc.set('Signers', signers);
+
+ Placeholders[index] = {
+ ...Placeholders[index],
+ signerObjId: contactRes.id,
+ signerPtr: {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: contactRes.id,
+ },
+ };
+ updateDoc.set('Placeholders', Placeholders);
+ const Acl = docRes.getACL();
+ Acl.setReadAccess(_extUser.UserId.objectId, true);
+ Acl.setWriteAccess(_extUser.UserId.objectId, true);
+ updateDoc.setACL(Acl);
+ // const parseData = JSON.parse(JSON.stringify(res));
+ const resDoc = await updateDoc.save(null, { useMasterKey: true });
+ if (resDoc) {
+ return { contactId: contactRes.id };
+ }
+ } else if (name) {
+ try {
+ // Execute the query to check if a user already exists in the '_User' class
+ const userQuery = new Parse.Query(Parse.User);
+ userQuery.equalTo('email', email);
+ const userRes = await userQuery.first({ useMasterKey: true });
+ if (userRes) {
+ const contact = {
+ UserId: { __type: 'Pointer', className: '_User', objectId: userRes.id },
+ Name: name,
+ Email: email,
+ Phone: phone,
+ CreatedBy: _docRes.CreatedBy,
+ TenantId: _docRes.ExtUserPtr.TenantId,
+ };
+ // Create new contract on the basis provided contact details by user and userId from _User class
+ const contactRes = await saveRoleContact(contact);
+ //update contact in placeholder, signers and update ACl in provide document
+ const updateDoc = new Parse.Object('contracts_Document');
+ updateDoc.id = docId;
+ const signers = _docRes?.Signers || [];
+ signers.push({
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: contactRes.id,
+ });
+ updateDoc.set('Signers', signers);
+
+ Placeholders[index] = {
+ ...Placeholders[index],
+ signerObjId: contactRes.id,
+ signerPtr: {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: contactRes.id,
+ },
+ };
+ updateDoc.set('Placeholders', Placeholders);
+ const Acl = docRes.getACL();
+ Acl.setReadAccess(userRes.id, true);
+ Acl.setWriteAccess(userRes.id, true);
+ updateDoc.setACL(Acl);
+ // const parseData = JSON.parse(JSON.stringify(res));
+ const resDoc = await updateDoc.save(null, { useMasterKey: true });
+ if (resDoc) {
+ return { contactId: contactRes.id };
+ }
+ } else {
+ // create new user in _User class on the basis of details provide by user
+ const _users = Parse.Object.extend('User');
+ const _user = new _users();
+ _user.set('name', name);
+ _user.set('username', email);
+ _user.set('email', email);
+ if (phone) {
+ _user.set('phone', phone);
+ _user.set('password', phone);
+ } else {
+ _user.set('password', email);
+ }
+ const newUserRes = await _user.save();
+ const contact = {
+ UserId: { __type: 'Pointer', className: '_User', objectId: newUserRes.id },
+ Name: name,
+ Email: email,
+ Phone: phone,
+ CreatedBy: _docRes.CreatedBy,
+ TenantId: _docRes.ExtUserPtr.TenantId,
+ };
+ // Create new contract on the basis provided contact details by user and userId from _User class
+ const contactRes = await saveRoleContact(contact);
+ //update contact in placeholder, signers and update ACl in provide document
+ const updateDoc = new Parse.Object('contracts_Document');
+ updateDoc.id = docId;
+ const signers = _docRes?.Signers || [];
+ signers.push({
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: contactRes.id,
+ });
+ updateDoc.set('Signers', signers);
+
+ Placeholders[index] = {
+ ...Placeholders[index],
+ signerObjId: contactRes.id,
+ signerPtr: {
+ __type: 'Pointer',
+ className: 'contracts_Contactbook',
+ objectId: contactRes.id,
+ },
+ };
+ updateDoc.set('Placeholders', Placeholders);
+ const Acl = docRes.getACL();
+ Acl.setReadAccess(newUserRes.id, true);
+ Acl.setWriteAccess(newUserRes.id, true);
+ updateDoc.setACL(Acl);
+ // const parseData = JSON.parse(JSON.stringify(res));
+ const resDoc = await updateDoc.save(null, { useMasterKey: true });
+ if (resDoc) {
+ return { contactId: contactRes.id };
+ }
+ }
+ } catch (err) {
+ console.log('Err', err);
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
+ }
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'unauthorized');
+ }
+ } else {
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
+ }
+ } catch (err) {
+ console.log('err in linkcontacttodoc', err);
+ throw err;
+ }
+}
diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js
index f639ec9ed..b94d2e82d 100644
--- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js
+++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js
@@ -324,6 +324,7 @@ export default function reportJson(id, userId) {
'Signers.Name',
'Signers.Email',
'Signers.Phone',
+ 'Placeholders',
],
};
default: