mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-23 16:12:34 +02:00
v2.12.0
feat: create duplicate template functionality feat: add support of csv and xlsx for bulk contacts import feat: add info text for forms and dashboard button feat: implement functionality to delete a PDF page while editing the document feat: show completed documents in which signers included but not owner in completed reports feat: add delete folder button in opensign drive feat: introduce Bcc email support for sending completed documents feat: allow merging multiple pdf while drafting document and template feat: add 'My Initials' tab for auto-signing in request-sign flow feat: add support for redirect URL to navigate after document completion feat: introduce privacy policy and digital signature terms before signing documents. feat: add feature to allow adding new pages to existing document feat: add save signature, initials, stamp functionality in sign pad for logged in user feat: add preferences menu feat: add save custom email template, notifyonsignature, set timezone, allow signature types in preferences feat: secure local url feat: implement Italian language translation feat: implement German language translation feat: update menu name from report to documents and shift contactbook in main menu feat: provide edit contact functionality fix: unable to delete folder when all its documents are deleted fix: fields.push is not function fix: document loading issue in opensign drive fix: adjust the guest signature flow to display the document in full screen, eliminating any blank space which is displayed below the place holder in mobile view fix: resolve issue of instance of pdfdict or pdfstream but got undefined build(deps): update dependencies refactor: change note text from add contact form
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
The OpenSign Enterprise license (the “Enterprise License”)
|
||||
Copyright (c) 2020-2024 Qik Innovations Private Limited.
|
||||
|
||||
With regard to the OpenSign Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the OpenSign Subscription Terms of Service(the “Enterprise Terms”), or other
|
||||
agreement governing the use of the Software, as agreed by you and OpenSign,
|
||||
and otherwise have a valid OpenSign Enterprise license for the
|
||||
correct number of user seats. Subject to the foregoing sentence, you are free to
|
||||
modify this Software and publish patches to the Software. You agree that OpenSign
|
||||
and/or its licensors (as applicable) retain all right, title and interest in and
|
||||
to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid OpenSign Enterprise license for the correct
|
||||
number of user seats. Notwithstanding the foregoing, you may copy and modify
|
||||
the Software for development and testing purposes, without requiring a
|
||||
subscription. You agree that OpenSign and/or its licensors (as applicable) retain
|
||||
all right, title and interest in and to all such modifications. You are not
|
||||
granted any other rights beyond what is expressly stated herein. Subject to the
|
||||
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the OpenSign Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
@@ -1,192 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
|
||||
// `replaceMailVaribles` is used to replace variables from mail with there actual values
|
||||
function replaceMailVaribles(subject, body, variables) {
|
||||
let replacedSubject = subject;
|
||||
let replacedBody = body;
|
||||
|
||||
for (const variable in variables) {
|
||||
const regex = new RegExp(`{{${variable}}}`, 'g');
|
||||
if (subject) {
|
||||
replacedSubject = replacedSubject.replace(regex, variables[variable]);
|
||||
}
|
||||
if (body) {
|
||||
replacedBody = replacedBody.replace(regex, variables[variable]);
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
subject: replacedSubject,
|
||||
body: replacedBody,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// `sendmail` is used to signing reminder mail to signer
|
||||
async function sendMail(doc, signer) {
|
||||
const subject = `{{sender_name}} has requested you to sign "{{document_title}}"`;
|
||||
const body = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign <b>"{{document_title}}"</b>.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p>{{signing_url}}</p><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team OpenSign™</p><br></body> </html>`;
|
||||
const url = `${cloudServerUrl}/functions/sendmailv3`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
};
|
||||
|
||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||
const encodeBase64 = btoa(`${doc.objectId}/${signer.Email}/${signer.objectId}`);
|
||||
const expireDate = doc?.ExpiryDate?.iso;
|
||||
const newDate = new Date(expireDate);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
const signPdf = `${baseUrl.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || '',
|
||||
receiver_name: signer.Name,
|
||||
receiver_email: signer.Email,
|
||||
receiver_phone: signer?.Phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: doc?.ExtUserPtr?.Company || '',
|
||||
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`,
|
||||
};
|
||||
const mail = replaceMailVaribles(subject, body, variables);
|
||||
|
||||
let params = {
|
||||
mailProvider: doc?.ExtUserPtr?.active_mail_adapter,
|
||||
extUserId: doc?.ExtUserPtr?.objectId,
|
||||
recipient: signer.Email,
|
||||
subject: mail.subject,
|
||||
from: doc?.ExtUserPtr?.Email,
|
||||
html: mail.body,
|
||||
};
|
||||
try {
|
||||
// The axios request is used to send a signing reminder email.
|
||||
const res = await axios.post(url, params, { headers: headers });
|
||||
// console.log('res ', res.data.result);
|
||||
if (res.data.result.status === 'success') {
|
||||
return { status: 'success' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in mail of sendreminder api', err);
|
||||
return { status: 'error' };
|
||||
}
|
||||
}
|
||||
export default async function autoReminder(request, response) {
|
||||
// The query below is used to find documents where the reminder date is less than or equal to the current date, and which have existing signers and a signed URL.
|
||||
try {
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.limit(2000);
|
||||
docQuery.lessThanOrEqualTo('NextReminderDate', new Date());
|
||||
docQuery.equalTo('AutomaticReminders', true);
|
||||
docQuery.exists('NextReminderDate');
|
||||
docQuery.exists('Signers');
|
||||
docQuery.exists('SignedUrl');
|
||||
docQuery.descending('createdAt');
|
||||
docQuery.include('Signers,AuditTrail.UserPtr,ExtUserPtr,ExtUserPtr.TenantId');
|
||||
docQuery.notEqualTo('IsCompleted', true);
|
||||
docQuery.notEqualTo('IsDeclined', true);
|
||||
docQuery.notEqualTo('IsArchive', true);
|
||||
docQuery.greaterThanOrEqualTo('ExpiryDate', new Date());
|
||||
|
||||
const docsArr = await docQuery.find({ useMasterKey: true });
|
||||
|
||||
if (docsArr && docsArr.length > 0) {
|
||||
const _docsArr = JSON.parse(JSON.stringify(docsArr));
|
||||
let mailCount = 0;
|
||||
let docCount = 0;
|
||||
for (const doc of _docsArr) {
|
||||
// The reminderDate variable is used to calculate the next reminder date.
|
||||
const RemindOnceInEvery = doc?.RemindOnceInEvery || 5;
|
||||
const ReminderDate = new Date();
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
// The sendInOrder variable is used to determine whether to send emails in order or not.
|
||||
const SendInOrder = doc?.SendinOrder || false;
|
||||
if (SendInOrder) {
|
||||
// The auditTrail variable is used to get the count of how many users have already signed the document.
|
||||
const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed');
|
||||
const count = auditTrail?.length || 0;
|
||||
const signer = doc?.Signers?.[count];
|
||||
if (signer) {
|
||||
docCount += 1;
|
||||
const mailRes = await sendMail(doc, signer);
|
||||
if (mailRes && mailRes.status === 'success') {
|
||||
mailCount += 1;
|
||||
}
|
||||
try {
|
||||
// The code below is used to update the next reminder date of the document based on the "remind once every X days" setting.
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = doc.objectId;
|
||||
updateDoc.set('NextReminderDate', ReminderDate);
|
||||
const updateRes = await updateDoc.save(null, { useMasterKey: true });
|
||||
// console.log('updateRes ', updateRes);
|
||||
} catch (err) {
|
||||
console.log('err in update document', err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The AuditTrail variable is used to check if there is any user who has already signed the document.
|
||||
const auditTrail = doc?.AuditTrail?.filter(x => x.Activity === 'Signed');
|
||||
if (auditTrail?.length > 0) {
|
||||
// The signers variable is used to get the signers who haven't signed the document.
|
||||
const signers = doc?.Signers.filter(signer => {
|
||||
const signedUser = auditTrail?.find(y => y.UserPtr.objectId === signer.objectId);
|
||||
if (!signedUser) {
|
||||
return signer;
|
||||
}
|
||||
});
|
||||
if (signers?.length > 0) {
|
||||
docCount += 1;
|
||||
// The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet.
|
||||
for (const signer of signers) {
|
||||
const mailRes = await sendMail(doc, signer);
|
||||
if (mailRes && mailRes.status === 'success') {
|
||||
mailCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The for...of loop below is used to send a signing reminder to every signer who hasn't signed the document yet.
|
||||
const signers = doc?.Signers;
|
||||
if (signers?.length > 0) {
|
||||
docCount += 1;
|
||||
for (const signer of signers) {
|
||||
const mailRes = await sendMail(doc, signer);
|
||||
if (mailRes && mailRes.status === 'success') {
|
||||
mailCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The code below is used to update the next reminder date of the document based on the "remind once every X days" setting.
|
||||
try {
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = doc.objectId;
|
||||
updateDoc.set('NextReminderDate', ReminderDate);
|
||||
const updateRes = await updateDoc.save(null, { useMasterKey: true });
|
||||
// console.log('updateRes ', updateRes);
|
||||
} catch (err) {
|
||||
console.log('err in sendmail', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (docCount > 0) {
|
||||
response.json({ status: 'success', document_count: docCount, mail_count: mailCount });
|
||||
} else {
|
||||
response.json({ status: 'no record found' });
|
||||
}
|
||||
} else {
|
||||
response.json({ status: 'no record found' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
const code = err?.code || 400;
|
||||
const message = err?.message || 'Somehting went wrong!';
|
||||
response.status(code).json({ error: message });
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,8 @@
|
||||
//--npm modules
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import dotenv from 'dotenv';
|
||||
import uploadFile from './uploadFile.js';
|
||||
import saveSubscription from './saveSubscription.js';
|
||||
import saveInvoice from './saveInvoice.js';
|
||||
import savePayments from './savePayments.js';
|
||||
import gooogleauth from './googleauth.js';
|
||||
import autoReminder from './autoReminder.js';
|
||||
import validateSmtp from './validateSmtp.js';
|
||||
|
||||
export const app = express();
|
||||
|
||||
dotenv.config();
|
||||
@@ -18,9 +12,3 @@ app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||
|
||||
app.post('/file_upload', uploadFile);
|
||||
|
||||
app.post('/savesubscription', saveSubscription);
|
||||
app.post('/saveinvoice', saveInvoice);
|
||||
app.post('/savepayment', savePayments);
|
||||
app.post('/googleauth', gooogleauth);
|
||||
app.post('/sendreminder', autoReminder);
|
||||
app.post('/validatesmtp', validateSmtp);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
const appId = process.env.APP_ID;
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
export default async function gooogleauth(request, response) {
|
||||
const code = request.body.code;
|
||||
const baseUrl = new URL(process.env.SERVER_URL);
|
||||
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
||||
const redirectUri =
|
||||
baseUrl?.hostname === 'localhost'
|
||||
? 'http://localhost:3000'
|
||||
: 'https://console.opensignlabs.com'; // Should match the redirect URI used in the authorization request
|
||||
const tokenEndpoint = 'https://oauth2.googleapis.com/token';
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('code', code);
|
||||
params.append('client_id', clientId);
|
||||
params.append('client_secret', clientSecret);
|
||||
params.append('redirect_uri', redirectUri);
|
||||
params.append('grant_type', 'authorization_code');
|
||||
|
||||
const res = await axios.post(tokenEndpoint, params);
|
||||
// console.log('oauthres ', res.data);
|
||||
const refresh_token = res.data.refresh_token;
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
|
||||
if (extUser) {
|
||||
const extUserCls = new Parse.Object('contracts_Users');
|
||||
extUserCls.id = extUser.id;
|
||||
extUserCls.set('google_refresh_token', refresh_token);
|
||||
extUserCls.set('active_mail_adapter', 'google');
|
||||
const updateExtUser = await extUserCls.save(null, { useMasterKey: true });
|
||||
// console.log('updateExtUser ', updateExtUser);
|
||||
}
|
||||
return response.status(200).json({ status: 'success' });
|
||||
} else {
|
||||
return response.status(404).json({ message: 'user not found!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in google auth', err);
|
||||
if (err?.response?.data?.error) {
|
||||
return response.status(404).json({ message: err.response.data.error });
|
||||
} else {
|
||||
return response.status(404).json({ message: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
export default async function saveInvoice(request, response) {
|
||||
const InvoiceId = request.body.data.invoice.invoice_id;
|
||||
const body = request.body;
|
||||
const Email = request.body.data.invoice.email;
|
||||
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('Email', Email);
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const invoiceCls = new Parse.Query('contracts_Invoices');
|
||||
invoiceCls.equalTo('InvoiceId', InvoiceId);
|
||||
const invoice = await invoiceCls.first({ useMasterKey: true });
|
||||
if (invoice) {
|
||||
const updateInvoice = new Parse.Object('contracts_Invoices');
|
||||
updateInvoice.id = invoice.id;
|
||||
updateInvoice.set('InvoiceDetails', body);
|
||||
await updateInvoice.save(null, { useMasterKey: true });
|
||||
return response.status(200).json({ status: 'update invoice!' });
|
||||
} else {
|
||||
const createInvoice = new Parse.Object('contracts_Invoices');
|
||||
createInvoice.set('InvoiceId', InvoiceId);
|
||||
createInvoice.set('InvoiceDetails', body);
|
||||
createInvoice.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
createInvoice.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser.get('UserId').id,
|
||||
});
|
||||
if (extUser?.get('TenantId')?.id) {
|
||||
createInvoice.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
}
|
||||
await createInvoice.save(null, { useMasterKey: true });
|
||||
return response.status(200).json({ status: 'create invoice!' });
|
||||
}
|
||||
} else {
|
||||
return response.status(404).json({ status: 'user not found!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in save invoice', err);
|
||||
return response.status(400).json({ status: 'error:' + err.message });
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
export default async function savePayments(request, response) {
|
||||
const PaymentId = request.body.data.payment.payment_id;
|
||||
const body = request.body;
|
||||
const Email = request.body.data.payment.email;
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('Email', Email);
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const paymentCls = new Parse.Query('contracts_Payments');
|
||||
paymentCls.equalTo('PaymentId', PaymentId);
|
||||
const payment = await paymentCls.first({ useMasterKey: true });
|
||||
if (payment) {
|
||||
const updatePayment = new Parse.Object('contracts_Payments');
|
||||
updatePayment.id = payment.id;
|
||||
updatePayment.set('PaymentDetails', body);
|
||||
await updatePayment.save(null, { useMasterKey: true });
|
||||
return response.status(200).json({ status: 'update Payment!' });
|
||||
} else {
|
||||
const createPayment = new Parse.Object('contracts_Payments');
|
||||
createPayment.set('PaymentId', PaymentId);
|
||||
createPayment.set('PaymentDetails', body);
|
||||
createPayment.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
createPayment.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser.get('UserId').id,
|
||||
});
|
||||
if (extUser?.get('TenantId')?.id) {
|
||||
createPayment.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
}
|
||||
await createPayment.save(null, { useMasterKey: true });
|
||||
return response.status(200).json({ status: 'create payments!' });
|
||||
}
|
||||
} else {
|
||||
return response.status(404).json({ status: 'user not found!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in save payment', err);
|
||||
return response.status(400).json({ status: 'error:' + err.message });
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
import { planCredits } from '../../Utils.js';
|
||||
|
||||
export default async function saveSubscription(request, response) {
|
||||
const SubscriptionId = request.body?.data?.subscription?.subscription_id;
|
||||
const body = request.body;
|
||||
const Email = request.body.data?.subscription?.customer?.email;
|
||||
const Next_billing_date = request.body?.data?.subscription?.next_billing_at;
|
||||
const planCode = request.body?.data?.subscription?.plan?.plan_code;
|
||||
const addons = request.body?.data?.subscription?.addons || [];
|
||||
const event = request.body?.data?.event_type || '';
|
||||
const credits = planCredits?.[planCode] || 0;
|
||||
const isTeamPlan = planCode?.includes('team');
|
||||
let newAddons = 0;
|
||||
if (addons?.length > 0) {
|
||||
let allowedUsersMonthly = 0;
|
||||
let allowedUsersYearly = 0;
|
||||
addons?.forEach(item => {
|
||||
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||
allowedUsersYearly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-users') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
}
|
||||
});
|
||||
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||
newAddons = allowedUsersMonthly + allowedUsersYearly + 1;
|
||||
}
|
||||
} else {
|
||||
if (planCode === 'teams-yearly' || planCode === 'teams-monthly' || planCode === 'team-weekly') {
|
||||
newAddons = 1;
|
||||
}
|
||||
}
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('Email', Email);
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const subcriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||
subcriptionCls.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
const subscription = await subcriptionCls.first({ useMasterKey: true });
|
||||
if (subscription) {
|
||||
const _resSub = JSON.parse(JSON.stringify(subscription));
|
||||
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
updateSubscription.id = subscription.id;
|
||||
updateSubscription.set('SubscriptionId', SubscriptionId);
|
||||
updateSubscription.set('SubscriptionDetails', body);
|
||||
if (Next_billing_date) {
|
||||
updateSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||
} else {
|
||||
updateSubscription.unset('Next_billing_date');
|
||||
}
|
||||
updateSubscription.set('PlanCode', planCode);
|
||||
if (newAddons > 0) {
|
||||
updateSubscription.set('AllowedUsers', parseInt(newAddons));
|
||||
}
|
||||
let existAddon = 0;
|
||||
let allowedUsersMonthly = 0;
|
||||
let allowedUsersYearly = 0;
|
||||
_resSub.SubscriptionDetails?.data?.subscription?.addons?.forEach(item => {
|
||||
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||
allowedUsersYearly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-users') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
}
|
||||
});
|
||||
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||
existAddon = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user
|
||||
} else {
|
||||
if (
|
||||
planCode === 'teams-yearly' ||
|
||||
planCode === 'teams-monthly' ||
|
||||
planCode === 'team-weekly'
|
||||
) {
|
||||
existAddon = 1; // 1 is Admin user
|
||||
}
|
||||
}
|
||||
const isSameAsPrevPlan = subscription?.get('PlanCode') === planCode;
|
||||
if (isSameAsPrevPlan) {
|
||||
const planCredits = subscription?.get('PlanCredits');
|
||||
const existAllowedCredits = subscription?.get('AllowedCredits') || 0;
|
||||
if (planCredits) {
|
||||
const oldAddons = existAddon;
|
||||
const substractedAddon = newAddons - oldAddons;
|
||||
if (isTeamPlan && substractedAddon > 0) {
|
||||
const newCredits = existAllowedCredits + substractedAddon * planCredits;
|
||||
updateSubscription.set('AllowedCredits', newCredits);
|
||||
if (event === 'subscription_created') {
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
} else if (isTeamPlan) {
|
||||
const existCredits = existAddon * planCredits;
|
||||
updateSubscription.set('AllowedCredits', existCredits);
|
||||
if (event === 'subscription_created') {
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
} else {
|
||||
updateSubscription.set('AllowedCredits', planCredits);
|
||||
if (event === 'subscription_created') {
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (credits > 0) {
|
||||
if (isTeamPlan) {
|
||||
const newCredits = newAddons * credits;
|
||||
updateSubscription.set('AllowedCredits', newCredits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
} else {
|
||||
updateSubscription.set('AllowedCredits', credits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (credits > 0) {
|
||||
if (isTeamPlan) {
|
||||
const newCredits = newAddons * credits;
|
||||
updateSubscription.set('AllowedCredits', newCredits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
} else {
|
||||
updateSubscription.set('AllowedCredits', credits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
}
|
||||
await updateSubscription.save(null, { useMasterKey: true });
|
||||
return response.status(200).json({ status: 'update subscription!' });
|
||||
} else {
|
||||
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
createSubscription.set('SubscriptionId', SubscriptionId);
|
||||
createSubscription.set('SubscriptionDetails', body);
|
||||
createSubscription.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
createSubscription.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser.get('UserId').id,
|
||||
});
|
||||
createSubscription.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
if (Next_billing_date) {
|
||||
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||
} else {
|
||||
createSubscription.unset('Next_billing_date');
|
||||
}
|
||||
createSubscription.set('PlanCode', planCode);
|
||||
if (newAddons > 0) {
|
||||
createSubscription.set('AllowedUsers', parseInt(newAddons));
|
||||
}
|
||||
if (credits > 0) {
|
||||
if (isTeamPlan) {
|
||||
const totalCredits = parseInt(newAddons) * credits;
|
||||
createSubscription.set('AllowedCredits', totalCredits);
|
||||
createSubscription.set('PlanCredits', credits);
|
||||
} else {
|
||||
createSubscription.set('AllowedCredits', credits);
|
||||
createSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
await createSubscription.save(null, { useMasterKey: true });
|
||||
return response.status(200).json({ status: 'create subscription!' });
|
||||
}
|
||||
} else {
|
||||
return response.status(404).json({ status: 'user not found!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in save subscription', err);
|
||||
return response.status(400).json({ status: 'error:' + err.message });
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
//--npm modules
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
export const app = express();
|
||||
import dotenv from 'dotenv';
|
||||
import getUser from './routes/getUser.js';
|
||||
import getDocumentList from './routes/getDocumentList.js';
|
||||
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 getTemplate from './routes/getTemplate.js';
|
||||
import deletedTemplate from './routes/deleteTemplate.js';
|
||||
import getTemplatetList from './routes/getTemplateList.js';
|
||||
import updateTemplate from './routes/updateTemplate.js';
|
||||
import createContact from './routes/createContact.js';
|
||||
import multer from 'multer';
|
||||
import updateDocument from './routes/updateDocument.js';
|
||||
import deleteDocument from './routes/deleteDocument.js';
|
||||
import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js';
|
||||
import saveWebhook from './routes/saveWebhook.js';
|
||||
import deleteWebhook from './routes/deleteWebhook.js';
|
||||
import getWebhook from './routes/getWebhook.js';
|
||||
import createDocumentwithCoordinate from './routes/createDocumentwithCoordinate.js';
|
||||
import createTemplatewithCoordinate from './routes/createTemplatewithCoordinate.js';
|
||||
import resendMail from './routes/resendMail.js';
|
||||
import getFolder from './routes/getFolder.js';
|
||||
import createFolder from './routes/createFolder.js';
|
||||
import updateFolder from './routes/updateFolder.js';
|
||||
import getFolderList from './routes/getFolderList.js';
|
||||
import deleteFolder from './routes/deleteFolder.js';
|
||||
dotenv.config();
|
||||
const storage = multer.memoryStorage();
|
||||
const upload = multer({ storage: storage });
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json({ limit: '50mb' }));
|
||||
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||
|
||||
// get user details whose api token used
|
||||
app.get('/getuser', getUser);
|
||||
|
||||
// get contact on the basis of id
|
||||
app.post('/createcontact', createContact);
|
||||
|
||||
// get contact on the basis of id
|
||||
app.get('/contact/:contact_id', getContact);
|
||||
|
||||
// soft delete contact
|
||||
app.delete('/contact/:contact_id', deleteContact);
|
||||
|
||||
// get list of contacts
|
||||
app.get('/contactlist', getContactList);
|
||||
|
||||
// create Document
|
||||
app.post('/createdocumentwithbinary', upload.array('file', 1), createDocumentwithCoordinate);
|
||||
|
||||
// create Document with co-ordinate
|
||||
app.post('/createdocument', createDocumentwithCoordinate);
|
||||
|
||||
// create Document with templateId
|
||||
app.post('/createdocument/:template_id', createDocumentWithTemplate);
|
||||
|
||||
// get Document on the basis of id
|
||||
app.get('/document/:document_id', getDocument);
|
||||
|
||||
// get document on the basis of id
|
||||
app.put('/document/:document_id', updateDocument);
|
||||
|
||||
// get document on the basis of id
|
||||
app.delete('/document/:document_id', deleteDocument);
|
||||
|
||||
// get all types of documents on the basis of doctype
|
||||
app.get('/documentlist/:doctype', getDocumentList);
|
||||
|
||||
// create Template with co-ordinate
|
||||
app.post('/createtemplate', createTemplatewithCoordinate);
|
||||
|
||||
// create Template with binary
|
||||
app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplatewithCoordinate);
|
||||
|
||||
// get template on the basis of id
|
||||
app.get('/template/:template_id', getTemplate);
|
||||
|
||||
// get template on the basis of id
|
||||
app.put('/template/:template_id', updateTemplate);
|
||||
|
||||
// get template on the basis of id
|
||||
app.delete('/template/:template_id', deletedTemplate);
|
||||
|
||||
// get all types of documents on the basis of doctype
|
||||
app.get('/templatelist', getTemplatetList);
|
||||
|
||||
// set and update webhook
|
||||
app.get('/webhook', getWebhook);
|
||||
|
||||
// set and update webhook
|
||||
app.post('/webhook', saveWebhook);
|
||||
|
||||
// set and update webhook
|
||||
app.delete('/webhook', deleteWebhook);
|
||||
|
||||
// resend mail
|
||||
app.post('/resendmail', resendMail);
|
||||
|
||||
// create folder
|
||||
app.post('/createfolder', createFolder);
|
||||
|
||||
// update folder
|
||||
app.put('/folder/:folder_id', updateFolder);
|
||||
|
||||
// get folder list
|
||||
app.delete('/folder/:folder_id', deleteFolder);
|
||||
|
||||
// get folder
|
||||
app.get('/folder/:folder_id', getFolder);
|
||||
|
||||
// get folder list
|
||||
app.get('/folderlist', getFolderList);
|
||||
@@ -1,435 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, customAPIurl, replaceMailVaribles } from '../../../../Utils.js';
|
||||
|
||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
||||
if (WebhookUrl) {
|
||||
const params = { event: 'created', ...doc };
|
||||
await axios
|
||||
.post(WebhookUrl, params, { headers: { 'Content-Type': 'application/json' } })
|
||||
.then(res => {
|
||||
try {
|
||||
// console.log('res ', res);
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err);
|
||||
}
|
||||
});
|
||||
// console.log('res ', res.data);
|
||||
}
|
||||
}
|
||||
export default async function createDocumentWithTemplate(request, response) {
|
||||
const signers = request.body.signers;
|
||||
const folderId = request.body.folderId;
|
||||
const templateId = request.params.template_id;
|
||||
const protocol = customAPIurl();
|
||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||
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 || true;
|
||||
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
|
||||
|
||||
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 extUsers = new Parse.Query('contracts_Users');
|
||||
extUsers.equalTo('UserId', userPtr);
|
||||
const extUser = await extUsers.first({ useMasterKey: true });
|
||||
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
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 (totalcredits > 0) {
|
||||
const templateQuery = new Parse.Query('contracts_Template');
|
||||
templateQuery.include('ExtUserPtr');
|
||||
templateQuery.include('ExtUserPtr.TenantId');
|
||||
const templateRes = await templateQuery.get(templateId, { useMasterKey: true });
|
||||
if (templateRes) {
|
||||
const template = JSON.parse(JSON.stringify(templateRes));
|
||||
if (template?.Placeholders?.length > 0) {
|
||||
const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId);
|
||||
const isValid =
|
||||
signers.length >= emptyplaceholder.length &&
|
||||
signers.length <= template?.Placeholders?.length;
|
||||
const placeholder =
|
||||
signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder;
|
||||
const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role));
|
||||
// console.log('isValid ', isValid);
|
||||
if (isValid && updateSigners) {
|
||||
//Check if every item's placeholders contain at least one placeholder with type 'signature'.
|
||||
let isSignature = template?.Placeholders?.every(item =>
|
||||
item?.placeHolder.some(x => x?.pos.some(data => data?.type === 'signature'))
|
||||
);
|
||||
if (!isSignature) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||
}
|
||||
const folderPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
};
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', template.Name);
|
||||
if (template?.Note) {
|
||||
object.set('Note', template.Note);
|
||||
}
|
||||
if (template?.Description) {
|
||||
object.set('Description', template.Description);
|
||||
}
|
||||
object.set('IsSendMail', send_email);
|
||||
if (sendInOrder) {
|
||||
object.set('SendinOrder', sendInOrder);
|
||||
} else if (template?.SendinOrder && template?.SendinOrder) {
|
||||
object.set('SendinOrder', template?.SendinOrder);
|
||||
}
|
||||
let templateSigner = template?.Signers ? template?.Signers : [];
|
||||
let contact = [];
|
||||
if (signers && signers.length > 0) {
|
||||
let parseSigners = [...signers];
|
||||
let createContactUrl = protocol + '/v1/createcontact';
|
||||
|
||||
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 },
|
||||
});
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: res.data?.objectId,
|
||||
};
|
||||
const newObj = { ...obj, contactPtr: contactPtr };
|
||||
contact.push(newObj);
|
||||
} catch (err) {
|
||||
// console.log('err ', err);
|
||||
if (err?.response?.data?.objectId) {
|
||||
const contactPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: err.response.data?.objectId,
|
||||
};
|
||||
const newObj = { ...obj, contactPtr: contactPtr };
|
||||
contact.push(newObj);
|
||||
} else {
|
||||
console.log('err ', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
const contactPtrs = contact.map(x => x.contactPtr);
|
||||
object.set('Signers', [...templateSigner, ...contactPtrs]);
|
||||
|
||||
let updatedPlaceholder = template?.Placeholders?.map(x => {
|
||||
let matchingSigner = contact.find(y => x.Role && x.Role === y.role);
|
||||
|
||||
if (matchingSigner) {
|
||||
return {
|
||||
...x,
|
||||
signerObjId: matchingSigner?.contactPtr?.objectId,
|
||||
signerPtr: matchingSigner?.contactPtr,
|
||||
};
|
||||
} else {
|
||||
return { ...x };
|
||||
}
|
||||
});
|
||||
object.set('Placeholders', updatedPlaceholder);
|
||||
} else {
|
||||
object.set('Signers', templateSigner);
|
||||
}
|
||||
object.set('URL', template.URL);
|
||||
object.set('SignedUrl', template.URL);
|
||||
object.set('SentToOthers', true);
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
const enableOTP = request.body?.enableOTP;
|
||||
const IsEnableOTP =
|
||||
enableOTP !== undefined ? enableOTP : template?.IsEnableOTP || false;
|
||||
const enableTour = request.body?.enableTour;
|
||||
const isTourEnabled =
|
||||
enableTour !== undefined ? enableTour : template?.IsTourEnabled || false;
|
||||
object.set('IsTourEnabled', isTourEnabled);
|
||||
object.set('IsEnableOTP', IsEnableOTP);
|
||||
object.set('CreatedBy', template.CreatedBy);
|
||||
object.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: template.ExtUserPtr.objectId,
|
||||
});
|
||||
if (folderId) {
|
||||
object.set('Folder', folderPtr);
|
||||
}
|
||||
if (template?.FileAdapterId) {
|
||||
object.set('FileAdapterId', template?.FileAdapterId);
|
||||
}
|
||||
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 });
|
||||
|
||||
const newDate = new Date();
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
let sender = template.ExtUserPtr.Email;
|
||||
let sendMail;
|
||||
if (send_email === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
let contactMail = contact;
|
||||
if (sendInOrder) {
|
||||
contactMail = contact.slice();
|
||||
contactMail.splice(1);
|
||||
}
|
||||
for (let i = 0; i < contactMail.length; i++) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
const objectId = contactMail[i].contactPtr.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
//encode this url value `${res.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = template.ExtUserPtr.Company
|
||||
? template.ExtUserPtr.Company
|
||||
: '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
|
||||
imgPng +
|
||||
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
template.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
template.Name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> 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™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: template.Name,
|
||||
sender_name: template.ExtUserPtr.Name,
|
||||
sender_mail: template.ExtUserPtr.Email,
|
||||
sender_phone: template.ExtUserPtr?.Phone || '',
|
||||
receiver_name: contactMail[i].name,
|
||||
receiver_email: contactMail[i].email,
|
||||
receiver_phone: contactMail[i]?.phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||
body: email_html,
|
||||
};
|
||||
}
|
||||
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
let params = {
|
||||
recipient: contactMail[i].email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: template.ExtUserPtr.objectId,
|
||||
mailProvider: template?.ExtUserPtr?.active_mail_adapter || '',
|
||||
};
|
||||
sendMail = await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
try {
|
||||
const doc = {
|
||||
objectId: res.id,
|
||||
file: template?.URL,
|
||||
name: template?.Name,
|
||||
note: template?.Note || '',
|
||||
description: template?.Description || '',
|
||||
signers: contact?.map(x => ({
|
||||
name: x.name,
|
||||
email: x.email,
|
||||
phone: x?.phone || '',
|
||||
})),
|
||||
createdAt: res.createdAt,
|
||||
};
|
||||
if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) {
|
||||
sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err', err);
|
||||
}
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
if (allowedCredits > 0) {
|
||||
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
// console.log("resSubcription ", resSubcription)
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
signurl: contact.map(x => ({
|
||||
email: x.email,
|
||||
url: `${baseUrl.origin}/login/${btoa(
|
||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||
)}`,
|
||||
})),
|
||||
message: 'Document sent successfully!',
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide signers properly!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please setup template properly!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document_with_templateid',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Invalid template id!' });
|
||||
}
|
||||
} else {
|
||||
return response
|
||||
.status(429)
|
||||
.json({ error: 'Quota reached, Please buy credits and try again later.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(400).json({
|
||||
error: 'Please purchase or renew your subscription.',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
if (err.code === 101) {
|
||||
return response.status(404).json({ error: 'Invalid template id!' });
|
||||
}
|
||||
return response.status(400).json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
export default async function createContact(request, response) {
|
||||
const name = request.body.name;
|
||||
const phone = request.body?.phone;
|
||||
const email = request.body.email;
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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,
|
||||
};
|
||||
|
||||
try {
|
||||
const contactbook = new Parse.Query('contracts_Contactbook');
|
||||
contactbook.equalTo('Email', email);
|
||||
contactbook.equalTo('CreatedBy', userPtr);
|
||||
contactbook.notEqualTo('IsDeleted', true);
|
||||
const userExists = await contactbook.first({ useMasterKey: true });
|
||||
|
||||
if (userExists) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_contact',
|
||||
properties: { response_code: 401 },
|
||||
});
|
||||
}
|
||||
return response
|
||||
.status(401)
|
||||
.json({ error: 'Contact already exists!', objectId: userExists.id });
|
||||
} else {
|
||||
try {
|
||||
const Tenant = new Parse.Query('partners_Tenant');
|
||||
Tenant.equalTo('UserId', userPtr);
|
||||
const tenantRes = await Tenant.first({ useMasterKey: true });
|
||||
|
||||
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 (tenantRes && tenantRes.id) {
|
||||
contactQuery.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantRes.id,
|
||||
});
|
||||
}
|
||||
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 = userPtr;
|
||||
contactQuery.set('CreatedBy', currentUser);
|
||||
contactQuery.set('UserId', user);
|
||||
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(userPtr.objectId, true);
|
||||
acl.setWriteAccess(userPtr.objectId, true);
|
||||
acl.setReadAccess(user.id, true);
|
||||
acl.setWriteAccess(user.id, true);
|
||||
contactQuery.setACL(acl);
|
||||
|
||||
const contactRes = await contactQuery.save();
|
||||
const parseRes = JSON.parse(JSON.stringify(contactRes));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_contact',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: parseRes.objectId,
|
||||
name: parseRes.Name,
|
||||
email: parseRes.Email,
|
||||
phone: parseRes?.Phone || '',
|
||||
createdAt: parseRes.createdAt,
|
||||
updatedAt: parseRes.updatedAt,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in', err);
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run('getUserId', params);
|
||||
contactQuery.set('CreatedBy', userPtr);
|
||||
contactQuery.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userRes.id,
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(userPtr.objectId, true);
|
||||
acl.setWriteAccess(userPtr.objectId, true);
|
||||
acl.setReadAccess(userRes.id, true);
|
||||
acl.setWriteAccess(userRes.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
const contactRes = await contactQuery.save();
|
||||
if (contactRes) {
|
||||
const parseRes = JSON.parse(JSON.stringify(contactRes));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_contact',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: parseRes.objectId,
|
||||
name: parseRes.Name,
|
||||
email: parseRes.Email,
|
||||
phone: parseRes?.Phone || '',
|
||||
createdAt: parseRes.createdAt,
|
||||
updatedAt: parseRes.updatedAt,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (err.code === 137) {
|
||||
return response.status(401).json({ error: 'Contact already exists!' });
|
||||
}
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
if (err.code === 137) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_contact',
|
||||
properties: { response_code: 401 },
|
||||
});
|
||||
}
|
||||
return response.status(401).json({ error: 'Contact already exists!' });
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_contact',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_contact',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,454 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import {
|
||||
color,
|
||||
customAPIurl,
|
||||
replaceMailVaribles,
|
||||
saveFileUsage,
|
||||
formatWidgetOptions,
|
||||
sanitizeFileName,
|
||||
cloudServerUrl,
|
||||
} from '../../../../Utils.js';
|
||||
import uploadFileToS3 from '../../../parsefunction/uploadFiletoS3.js';
|
||||
|
||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
||||
if (WebhookUrl) {
|
||||
const params = { event: 'created', ...doc };
|
||||
|
||||
await axios
|
||||
.post(WebhookUrl, params, { headers: { 'Content-Type': 'application/json' } })
|
||||
.then(res => {
|
||||
try {
|
||||
// console.log('res ', res);
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err?.message);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err?.message);
|
||||
}
|
||||
});
|
||||
// console.log('res ', res.data);
|
||||
}
|
||||
}
|
||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||
export default async function createDocumentwithCoordinate(request, response) {
|
||||
const name = request.body.title;
|
||||
const note = request.body.note;
|
||||
const description = request.body.description;
|
||||
const send_email = request.body.send_email;
|
||||
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 email_subject = request.body.email_subject;
|
||||
const email_body = request.body.email_body;
|
||||
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;
|
||||
// console.log('fileData ', fileData);
|
||||
const protocol = customAPIurl();
|
||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
|
||||
try {
|
||||
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 extUsers = new Parse.Query('contracts_Users');
|
||||
extUsers.equalTo('UserId', userPtr);
|
||||
extUsers.include('TenantId');
|
||||
const extUser = await extUsers.first({ useMasterKey: true });
|
||||
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
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 (totalcredits > 0) {
|
||||
if (signers && signers.length > 0) {
|
||||
// Check if at least one signature exists among all items in the signers array
|
||||
let isSignExist = signers.every(item =>
|
||||
item.widgets.some(data => data?.type === 'signature')
|
||||
);
|
||||
if (!isSignExist) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||
}
|
||||
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_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('SignedUrl', fileUrl);
|
||||
object.set('SentToOthers', true);
|
||||
object.set('CreatedBy', userPtr);
|
||||
object.set('ExtUserPtr', extUserPtr);
|
||||
if (TimeToCompleteDays) {
|
||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||
}
|
||||
object.set('IsEnableOTP', IsEnableOTP);
|
||||
object.set('IsTourEnabled', isTourEnabled);
|
||||
object.set('IsSendMail', send_email);
|
||||
if (parseExtUser?.TenantId?.ActiveFileAdapter) {
|
||||
object.set('FileAdapterId', parseExtUser?.TenantId?.ActiveFileAdapter);
|
||||
}
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
object.set(
|
||||
'Signers',
|
||||
contact?.map(x => x.contactPtr)
|
||||
);
|
||||
let updatePlaceholders = contact.map(signer => {
|
||||
const placeHolder = [];
|
||||
|
||||
for (const widget of signer.widgets) {
|
||||
const pageNumber = widget.page;
|
||||
const options = formatWidgetOptions(widget.type, widget.options);
|
||||
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
||||
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] });
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
signerObjId: signer?.contactPtr?.objectId,
|
||||
signerPtr: signer?.contactPtr,
|
||||
Role: signer.role,
|
||||
Id: randomId(),
|
||||
blockColor: color[signer?.index],
|
||||
placeHolder,
|
||||
};
|
||||
});
|
||||
object.set('Placeholders', updatePlaceholders);
|
||||
}
|
||||
if (folderId) {
|
||||
object.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
});
|
||||
}
|
||||
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 });
|
||||
const doc = {
|
||||
objectId: res.id,
|
||||
file: fileUrl,
|
||||
name: name,
|
||||
note: note || '',
|
||||
description: description || '',
|
||||
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x?.phone || '' })),
|
||||
createdAt: res.createdAt,
|
||||
};
|
||||
if (parseExtUser && parseExtUser.Webhook) {
|
||||
sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId);
|
||||
}
|
||||
const newDate = new Date();
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
let sender = parseExtUser.Email;
|
||||
if (send_email === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
let contactMail = contact;
|
||||
if (sendInOrder) {
|
||||
contactMail = contact.slice();
|
||||
contactMail.splice(1);
|
||||
}
|
||||
for (let i = 0; i < contactMail.length; i++) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
const objectId = contactMail[i].contactPtr.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
//encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
parseExtUser.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> 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™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: name,
|
||||
sender_name: parseExtUser.Name,
|
||||
sender_mail: parseExtUser.Email,
|
||||
sender_phone: parseExtUser?.Phone || '',
|
||||
receiver_name: contactMail[i].name,
|
||||
receiver_email: contactMail[i].email,
|
||||
receiver_phone: contactMail[i]?.phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||
body: email_html,
|
||||
};
|
||||
}
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
|
||||
let params = {
|
||||
recipient: contactMail[i].email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: extUser.id,
|
||||
mailProvider: parseExtUser?.active_mail_adapter || '',
|
||||
};
|
||||
|
||||
await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = resSub.id;
|
||||
if (allowedCredits > 0) {
|
||||
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||
// console.log('resSubcription ', resSubcription);
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
signurl: contact.map(x => ({
|
||||
email: x.email,
|
||||
url: `${baseUrl.origin}/login/${btoa(
|
||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||
)}`,
|
||||
})),
|
||||
message: 'Document sent successfully!',
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_document',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide signers!' });
|
||||
}
|
||||
} else {
|
||||
return response
|
||||
.status(429)
|
||||
.json({ error: 'Quota reached, Please buy credits and try again later.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(400).json({
|
||||
error: 'Please purchase or renew your subscription.',
|
||||
});
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
export default async function createFolder(request, response) {
|
||||
const apiToken = request.headers['x-api-token'];
|
||||
const folderName = request.body.folderName;
|
||||
const parentFolderId = request.body.parentFolderId;
|
||||
if (!apiToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('token', apiToken);
|
||||
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 userQuery = new Parse.Query('contracts_Users');
|
||||
userQuery.equalTo('UserId', userPtr);
|
||||
const extUser = await userQuery.first({ useMasterKey: true });
|
||||
|
||||
const folderCls = new Parse.Object('contracts_Document');
|
||||
folderCls.set('Name', folderName);
|
||||
folderCls.set('CreatedBy', userPtr);
|
||||
folderCls.set('Type', 'Folder');
|
||||
folderCls.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
if (parentFolderId) {
|
||||
folderCls.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: parentFolderId,
|
||||
});
|
||||
}
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(parseUser.userId.objectId, true); // Allow read access to the userPtr
|
||||
acl.setWriteAccess(parseUser.userId.objectId, true); // Allow write access to the userPtr
|
||||
|
||||
// Set the ACL to the document
|
||||
folderCls.setACL(acl);
|
||||
|
||||
const _resFolder = await folderCls.save(null, { useMasterKey: true });
|
||||
if (_resFolder) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_folder',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
const parseRes = JSON.parse(JSON.stringify(_resFolder));
|
||||
return response.json({
|
||||
objectId: parseRes.objectId,
|
||||
folderName: parseRes.Name,
|
||||
parentFolderId: parseRes?.Folder?.objectId || '',
|
||||
createdAt: parseRes.createdAt,
|
||||
updatedAt: parseRes.updatedAt,
|
||||
});
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import {
|
||||
color,
|
||||
customAPIurl,
|
||||
saveFileUsage,
|
||||
formatWidgetOptions,
|
||||
sanitizeFileName,
|
||||
} from '../../../../Utils.js';
|
||||
import uploadFileToS3 from '../../../parsefunction/uploadFiletoS3.js';
|
||||
|
||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||
export default async function createTemplatewithCoordinate(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;
|
||||
|
||||
// console.log('fileData ', fileData);
|
||||
const protocol = customAPIurl();
|
||||
|
||||
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,
|
||||
};
|
||||
if (signers && signers.length > 0) {
|
||||
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);
|
||||
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 = contact.map((signer, index) => {
|
||||
const placeHolder = [];
|
||||
|
||||
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],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
signerObjId: signer?.contactPtr?.objectId,
|
||||
signerPtr: signer?.contactPtr,
|
||||
Role: signer.role,
|
||||
Id: randomId(),
|
||||
blockColor: color[signer?.index],
|
||||
placeHolder,
|
||||
};
|
||||
});
|
||||
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_create_template',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: res.id,
|
||||
message: 'Template created successfully!',
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_create_template',
|
||||
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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
export default async function deleteContact(request, response) {
|
||||
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 Contactbook = new Parse.Query('contracts_Contactbook');
|
||||
Contactbook.equalTo('objectId', request.params.contact_id);
|
||||
Contactbook.equalTo('CreatedBy', userPtr);
|
||||
const res = await Contactbook.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const isDeleted = res.get('IsDeleted');
|
||||
if (isDeleted && isDeleted) {
|
||||
return response.status(404).json({ error: 'Contact not found!' });
|
||||
} else {
|
||||
const Contactbook = Parse.Object.extend('contracts_Contactbook');
|
||||
const deleteQuery = new Contactbook();
|
||||
deleteQuery.id = request.params.contact_id;
|
||||
deleteQuery.set('IsDeleted', true);
|
||||
const deleteRes = await deleteQuery.save(null, { useMasterKey: true });
|
||||
if (deleteRes) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_contact',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: request.params.contact_id,
|
||||
deletedAt: deleteRes.get('updatedAt'),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_contact',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Contact not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
export default async function deleteDocument(request, response) {
|
||||
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 Document = new Parse.Query('contracts_Document');
|
||||
Document.equalTo('objectId', request.params.document_id);
|
||||
Document.equalTo('CreatedBy', userPtr);
|
||||
Document.include('ExtUserPtr.TenantId');
|
||||
const res = await Document.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const isArchive = res.get('IsArchive');
|
||||
if (isArchive && isArchive) {
|
||||
return response.status(404).json({ error: 'Document not found!' });
|
||||
} else {
|
||||
const Document = Parse.Object.extend('contracts_Document');
|
||||
const deleteQuery = new Document();
|
||||
deleteQuery.id = request.params.document_id;
|
||||
deleteQuery.set('IsArchive', true);
|
||||
const deleteRes = await deleteQuery.save(null, { useMasterKey: true });
|
||||
if (deleteRes) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_document',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: request.params.document_id,
|
||||
deletedAt: deleteRes.get('updatedAt'),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_document',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Document not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
export default async function deleteFolder(request, response) {
|
||||
const apiToken = request.headers['x-api-token'];
|
||||
const folderId = request.params.folder_id;
|
||||
if (!apiToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('token', apiToken);
|
||||
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 obj = new Parse.Query('contracts_Document');
|
||||
obj.equalTo('objectId', folderId);
|
||||
obj.equalTo('IsArchive', true);
|
||||
obj.equalTo('CreatedBy', userPtr);
|
||||
obj.include('ExtUserPtr.TenantId');
|
||||
const isFolderDeleted = await obj.first({ useMasterKey: true });
|
||||
if (!isFolderDeleted) {
|
||||
const folder = new Parse.Query('contracts_Document');
|
||||
folder.equalTo('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: folderId,
|
||||
});
|
||||
|
||||
folder.notEqualTo('IsArchive', true);
|
||||
folder.equalTo('CreatedBy', userPtr);
|
||||
folder.equalTo('Type', 'Folder');
|
||||
folder.include('ExtUserPtr.TenantId');
|
||||
const isSubItems = await folder.first({ useMasterKey: true });
|
||||
// console.log('isSubItems ', isSubItems);
|
||||
if (isSubItems) {
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'folder is not empty, contains document or folder.' });
|
||||
} else {
|
||||
const deleteFolder = new Parse.Object('contracts_Document');
|
||||
deleteFolder.id = folderId;
|
||||
deleteFolder.set('IsArchive', true);
|
||||
const deleteRes = await deleteFolder.save(null, { useMasterKey: true });
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_folder',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ objectId: deleteRes.id, deletedAt: deleteRes.updatedAt });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_folder',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'folder not found.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err is delete folder API', err);
|
||||
return response.status(400).json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
export default async function deletedTemplate(request, response) {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 template = new Parse.Query('contracts_Template');
|
||||
template.equalTo('objectId', request.params.template_id);
|
||||
template.equalTo('CreatedBy', userPtr);
|
||||
template.include('ExtUserPtr.TenantId');
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const isArchive = res.get('IsArchive');
|
||||
if (isArchive && isArchive) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_template',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Template not found!' });
|
||||
} else {
|
||||
const template = Parse.Object.extend('contracts_Template');
|
||||
const deleteQuery = new template();
|
||||
deleteQuery.id = request.params.template_id;
|
||||
deleteQuery.set('IsArchive', true);
|
||||
const deleteRes = await deleteQuery.save(null, { useMasterKey: true });
|
||||
if (deleteRes) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_template',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: request.params.template_id,
|
||||
deletedAt: deleteRes.get('updatedAt'),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_template',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Template not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
export default async function deleteWebhook(request, response) {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 query = new Parse.Query('contracts_Users');
|
||||
query.equalTo('UserId', userPtr);
|
||||
const user = await query.first({ useMasterKey: true });
|
||||
if (user) {
|
||||
const updateQuery = new Parse.Object('contracts_Users');
|
||||
updateQuery.id = user.id;
|
||||
updateQuery.unset('Webhook');
|
||||
const res = await updateQuery.save(null, { useMasterKey: true });
|
||||
if (res) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_webhook',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
result: 'Webhook deleted successfully!',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_delete_webhook',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'User not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
export default async function getContact(request, response) {
|
||||
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 Contactbook = new Parse.Query('contracts_Contactbook');
|
||||
Contactbook.equalTo('objectId', request.params.contact_id);
|
||||
Contactbook.equalTo('CreatedBy', userPtr);
|
||||
Contactbook.notEqualTo('IsDeleted', true);
|
||||
Contactbook.select('Name,Email,Phone');
|
||||
|
||||
const res = await Contactbook.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const parseRes = JSON.parse(JSON.stringify(res));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_contact',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: parseRes.objectId,
|
||||
name: parseRes.Name,
|
||||
email: parseRes.Email,
|
||||
phone: parseRes?.Phone || '',
|
||||
createdAt: parseRes.createdAt,
|
||||
updatedAt: parseRes.updatedAt,
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_contact',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Contact not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
export default async function getContactList(request, response) {
|
||||
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 limit = request?.query?.limit ? parseInt(request.query.limit) : 100;
|
||||
const skip = request?.query?.skip ? parseInt(request.query.skip) : 0;
|
||||
const Contactbook = new Parse.Query('contracts_Contactbook');
|
||||
Contactbook.equalTo('CreatedBy', userPtr);
|
||||
Contactbook.notEqualTo('IsDeleted', true);
|
||||
Contactbook.limit(limit);
|
||||
Contactbook.skip(skip);
|
||||
Contactbook.descending('createdAt');
|
||||
const res = await Contactbook.find({ useMasterKey: true });
|
||||
if (res && res.length > 0) {
|
||||
const parseRes = JSON.parse(JSON.stringify(res));
|
||||
const contactlist = parseRes.map(x => ({
|
||||
objectId: x.objectId,
|
||||
name: x.Name,
|
||||
email: x.Email,
|
||||
phone: x?.Phone || '',
|
||||
createdAt: x.createdAt,
|
||||
updatedAt: x.updatedAt,
|
||||
}));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_contact_list',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ result: contactlist });
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_contact_list',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ result: [] });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
export default async function getDocument(request, response) {
|
||||
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 Document = new Parse.Query('contracts_Document');
|
||||
Document.equalTo('objectId', request.params.document_id);
|
||||
Document.equalTo('CreatedBy', userPtr);
|
||||
Document.notEqualTo('IsArchive', true);
|
||||
Document.include('Signers');
|
||||
Document.include('Folder');
|
||||
Document.include('ExtUserPtr');
|
||||
Document.include('Placeholders.signerPtr');
|
||||
Document.include('ExtUserPtr.TenantId');
|
||||
const res = await Document.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const document = JSON.parse(JSON.stringify(res));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_document',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: document.objectId,
|
||||
title: document.Name,
|
||||
note: document.Note || '',
|
||||
folder: { objectId: document?.Folder?.objectId, name: document?.Folder?.Name } || '',
|
||||
file: document?.SignedUrl || document.URL,
|
||||
certificate: document?.CertificateUrl || '',
|
||||
owner: document?.ExtUserPtr?.Name,
|
||||
signers:
|
||||
document?.Placeholders?.map(y => ({
|
||||
role: y.Role,
|
||||
name: y?.signerPtr?.Name || '',
|
||||
email: y?.signerPtr?.Email || '',
|
||||
phone: y?.signerPtr?.Phone || '',
|
||||
widgets: y.placeHolder?.flatMap(x =>
|
||||
x?.pos.map(w => ({
|
||||
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
|
||||
x: w.xPosition,
|
||||
y: w.yPosition,
|
||||
w: w?.Width || 150,
|
||||
h: w?.Height || 60,
|
||||
page: x?.pageNumber,
|
||||
}))
|
||||
),
|
||||
})) ||
|
||||
document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
|
||||
[],
|
||||
sendInOrder: document?.SendinOrder || false,
|
||||
enableOTP: document?.IsEnableOTP || false,
|
||||
createdAt: document.createdAt,
|
||||
updatedAt: document.updatedAt,
|
||||
enableTour: document?.IsTourEnabled || false,
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_document',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Document not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import reportJson from '../../../parsefunction/reportsJson.js';
|
||||
import dotenv from 'dotenv';
|
||||
import { cloudServerUrl } from '../../../../Utils.js';
|
||||
dotenv.config();
|
||||
|
||||
export default async function getDocumentList(request, response) {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
const appId = process.env.APP_ID;
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 docType = request.params.doctype;
|
||||
const limit = request?.query?.limit ? request.query.limit : 100;
|
||||
const skip = request?.query?.skip ? request.query.skip : 0;
|
||||
let reportId;
|
||||
switch (docType) {
|
||||
case 'draft':
|
||||
reportId = 'ByHuevtCFY';
|
||||
break;
|
||||
case 'signaturerequest':
|
||||
reportId = '4Hhwbp482K';
|
||||
break;
|
||||
case 'inprogress':
|
||||
reportId = '1MwEuxLEkF';
|
||||
break;
|
||||
case 'completed':
|
||||
reportId = 'kQUoW4hUXz';
|
||||
break;
|
||||
case 'expired':
|
||||
reportId = 'zNqBHXHsYH';
|
||||
break;
|
||||
case 'declined':
|
||||
reportId = 'UPr2Fm5WY3';
|
||||
break;
|
||||
default:
|
||||
reportId = '';
|
||||
}
|
||||
const json = reportId && reportJson(reportId, userPtr.objectId);
|
||||
const clsName = 'contracts_Document';
|
||||
if (reportId && json) {
|
||||
const { params, keys } = json;
|
||||
const orderBy = '-updatedAt';
|
||||
const strParams = JSON.stringify(params);
|
||||
const strKeys = keys.join();
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys},Placeholders&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId`;
|
||||
try {
|
||||
const res = await axios.get(url, { headers: headers });
|
||||
if (res.data && res.data.results.length > 0) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: `api_get_document_list_${docType}`,
|
||||
properties: { response_code: 200, doc_type: docType },
|
||||
});
|
||||
}
|
||||
const updateRes = res.data.results.map(x => ({
|
||||
objectId: x.objectId,
|
||||
title: x.Name,
|
||||
note: x.Note || '',
|
||||
folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '',
|
||||
// file: x?.SignedUrl || x.URL,
|
||||
owner: x?.ExtUserPtr?.Name,
|
||||
signers:
|
||||
x?.Placeholders?.map(y => ({
|
||||
role: y.Role,
|
||||
name: y?.signerPtr?.Name || '',
|
||||
email: y?.signerPtr?.Email || '',
|
||||
phone: y?.signerPtr?.Phone || '',
|
||||
widgets: y.placeHolder?.flatMap(x =>
|
||||
x?.pos.map(w => ({
|
||||
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
|
||||
x: w.xPosition,
|
||||
y: w.yPosition,
|
||||
w: w?.Width || 150,
|
||||
h: w?.Height || 60,
|
||||
page: x?.pageNumber,
|
||||
}))
|
||||
),
|
||||
})) ||
|
||||
x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
|
||||
[],
|
||||
sendInOrder: x?.SendinOrder || false,
|
||||
enableOTP: x?.IsEnableOTP || false,
|
||||
createdAt: x.createdAt,
|
||||
updatedAt: x.updatedAt,
|
||||
enableTour: x?.IsTourEnabled || false,
|
||||
}));
|
||||
return response.json({ result: updateRes });
|
||||
} else {
|
||||
return response.json({ result: [] });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getdocument list', err);
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: `api_get_document_list_${docType}`,
|
||||
properties: { response_code: 400, doc_type: docType },
|
||||
});
|
||||
}
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: `api_get_document_list_${docType}`,
|
||||
properties: { response_code: 404, doc_type: docType },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Report not available!' });
|
||||
}
|
||||
}
|
||||
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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
export default async function getFolder(request, response) {
|
||||
const apiToken = request.headers['x-api-token'];
|
||||
const folder_id = request.params.folder_id;
|
||||
if (!apiToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('token', apiToken);
|
||||
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 folderCls = new Parse.Query('contracts_Document');
|
||||
folderCls.equalTo('CreatedBy', userPtr);
|
||||
folderCls.equalTo('objectId', folder_id);
|
||||
folderCls.equalTo('Type', 'Folder');
|
||||
folderCls.notEqualTo('IsArchive', true);
|
||||
folderCls.descending('createdAt');
|
||||
folderCls.include('Folder');
|
||||
folderCls.include('ExtUserPtr.TenantId');
|
||||
const res = await folderCls.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const parseRes = JSON.parse(JSON.stringify(res));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_folder',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: parseRes.objectId,
|
||||
folderName: parseRes.Name,
|
||||
parentFolderId: parseRes?.Folder?.objectId || '',
|
||||
parentFolderName: parseRes?.Folder?.Name || '',
|
||||
createdAt: parseRes.createdAt,
|
||||
updatedAt: parseRes.updatedAt,
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_folder',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'folder not found.' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
export default async function getFolderList(request, response) {
|
||||
const apiToken = request.headers['x-api-token'];
|
||||
const parentFolderId = request.query?.parentFolderId || '';
|
||||
if (!apiToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('token', apiToken);
|
||||
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 limit = request?.query?.limit ? parseInt(request.query.limit) : 100;
|
||||
const skip = request?.query?.skip ? parseInt(request.query.skip) : 0;
|
||||
const folderCls = new Parse.Query('contracts_Document');
|
||||
folderCls.equalTo('CreatedBy', userPtr);
|
||||
folderCls.equalTo('Type', 'Folder');
|
||||
folderCls.notEqualTo('IsArchive', true);
|
||||
folderCls.descending('createdAt');
|
||||
folderCls.include('Folder');
|
||||
if (parentFolderId) {
|
||||
folderCls.equalTo('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: parentFolderId,
|
||||
});
|
||||
} else {
|
||||
folderCls.doesNotExist('Folder');
|
||||
}
|
||||
folderCls.descending('createdAt');
|
||||
folderCls.include('ExtUserPtr.TenantId');
|
||||
folderCls.limit(limit);
|
||||
folderCls.skip(skip);
|
||||
const res = await folderCls.find({ useMasterKey: true });
|
||||
if (res && res.length > 0) {
|
||||
const parseRes = JSON.parse(JSON.stringify(res));
|
||||
const folderlist = parseRes.map(x => ({
|
||||
objectId: x.objectId,
|
||||
folderName: x.Name,
|
||||
parentFolderId: x?.Folder?.objectId || '',
|
||||
parentFolderName: x?.Folder?.Name || '',
|
||||
createdAt: x.createdAt,
|
||||
updatedAt: x.updatedAt,
|
||||
}));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_Folder_list',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ result: folderlist });
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_Folder_list',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ result: [] });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
export default async function getTemplate(request, response) {
|
||||
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 Template = new Parse.Query('contracts_Template');
|
||||
Template.equalTo('objectId', request.params.template_id);
|
||||
Template.equalTo('CreatedBy', userPtr);
|
||||
Template.notEqualTo('IsArchive', true);
|
||||
Template.include('Signers');
|
||||
Template.include('Folder');
|
||||
Template.include('ExtUserPtr');
|
||||
Template.include('Placeholders.signerPtr');
|
||||
Template.include('ExtUserPtr.TenantId');
|
||||
const res = await Template.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const template = JSON.parse(JSON.stringify(res));
|
||||
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_template',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: template.objectId,
|
||||
title: template.Name,
|
||||
note: template.Note || '',
|
||||
folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '',
|
||||
file: template?.SignedUrl || template?.URL,
|
||||
owner: template?.ExtUserPtr?.Name,
|
||||
signers:
|
||||
template?.Placeholders?.map(y => ({
|
||||
role: y.Role,
|
||||
name: y?.signerPtr?.Name || '',
|
||||
email: y?.signerPtr?.Email || '',
|
||||
phone: y?.signerPtr?.Phone || '',
|
||||
widgets: y.placeHolder?.flatMap(x =>
|
||||
x?.pos.map(w => ({
|
||||
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
|
||||
x: w.xPosition,
|
||||
y: w.yPosition,
|
||||
w: w?.Width || 150,
|
||||
h: w?.Height || 60,
|
||||
page: x?.pageNumber,
|
||||
}))
|
||||
),
|
||||
})) || [],
|
||||
sendInOrder: template?.SendinOrder || false,
|
||||
enableOTP: template?.IsEnableOTP || false,
|
||||
createdAt: template.createdAt,
|
||||
updatedAt: template.updatedAt,
|
||||
enableTour: template?.IsTourEnabled || false,
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_template',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Template not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import dotenv from 'dotenv';
|
||||
import { cloudServerUrl } from '../../../../Utils.js';
|
||||
dotenv.config();
|
||||
export default async function getTemplatetList(request, response) {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
const appId = process.env.APP_ID;
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 limit = request?.query?.limit ? request.query.limit : 100;
|
||||
const skip = request?.query?.skip ? request.query.skip : 0;
|
||||
|
||||
const clsName = 'contracts_Template';
|
||||
const params = {
|
||||
Type: { $ne: 'Folder' },
|
||||
CreatedBy: userPtr,
|
||||
IsArchive: { $ne: true },
|
||||
};
|
||||
const keys = [
|
||||
'Name',
|
||||
'Note',
|
||||
'Description',
|
||||
'Folder.Name',
|
||||
'URL',
|
||||
'SignedUrl',
|
||||
'ExtUserPtr.Name',
|
||||
'Signers.Name',
|
||||
'Signers.Email',
|
||||
'Signers.Phone',
|
||||
'Placeholders',
|
||||
];
|
||||
const orderBy = '-updatedAt';
|
||||
const strParams = JSON.stringify(params);
|
||||
const strKeys = keys.join();
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'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,Placeholders.signerPtr,ExtUserPtr.TenantId`;
|
||||
const res = await axios.get(url, { headers: headers });
|
||||
if (res.data && res.data.results.length > 0) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_template_list',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
const updateRes = res.data.results.map(template => ({
|
||||
objectId: template.objectId,
|
||||
title: template.Name,
|
||||
note: template.Note || '',
|
||||
folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '',
|
||||
file: template?.SignedUrl || template.URL,
|
||||
owner: template?.ExtUserPtr?.Name,
|
||||
signers:
|
||||
template?.Placeholders?.map(y => ({
|
||||
role: y.Role,
|
||||
name: y?.signerPtr?.Name || '',
|
||||
email: y?.signerPtr?.Email || '',
|
||||
phone: y?.signerPtr?.Phone || '',
|
||||
widgets: y.placeHolder?.flatMap(x =>
|
||||
x?.pos.map(w => ({
|
||||
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
|
||||
x: w.xPosition,
|
||||
y: w.yPosition,
|
||||
w: w?.Width || 150,
|
||||
h: w?.Height || 60,
|
||||
page: x?.pageNumber,
|
||||
}))
|
||||
),
|
||||
})) || [],
|
||||
sendInOrder: template?.SendinOrder || false,
|
||||
enableOTP: template?.IsEnableOTP || false,
|
||||
createdAt: template.createdAt,
|
||||
updatedAt: template.updatedAt,
|
||||
enableTour: template?.IsTourEnabled || false,
|
||||
}));
|
||||
|
||||
return response.json({ result: updateRes });
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_template_list',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ result: [] });
|
||||
}
|
||||
}
|
||||
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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
export default async function getUser(request, response) {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 query = new Parse.Query('contracts_Users');
|
||||
query.equalTo('UserId', userPtr);
|
||||
query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan');
|
||||
const user = await query.first({ useMasterKey: true });
|
||||
if (user) {
|
||||
const parseRes = JSON.parse(JSON.stringify(user));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_your_account_details',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: parseRes.objectId,
|
||||
name: parseRes.Name,
|
||||
email: parseRes.Email,
|
||||
phone: parseRes?.Phone || '',
|
||||
jobTitle: parseRes.JobTitle,
|
||||
company: parseRes.Company,
|
||||
createdAt: parseRes.createdAt,
|
||||
updatedAt: parseRes.updatedAt,
|
||||
});
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_your_account_details',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'User not found!' });
|
||||
}
|
||||
}
|
||||
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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
export default async function getWebhook(request, response) {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 query = new Parse.Query('contracts_Users');
|
||||
query.equalTo('UserId', userPtr);
|
||||
const user = await query.first({ useMasterKey: true });
|
||||
if (user) {
|
||||
const extUser = JSON.parse(JSON.stringify(user));
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_webhook',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
if (extUser && extUser.Webhook) {
|
||||
return response.json({
|
||||
webhook: extUser.Webhook,
|
||||
});
|
||||
} else {
|
||||
return response.json({});
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_get_webhook',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'User not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, replaceMailVaribles } from '../../../../Utils.js';
|
||||
|
||||
export default async function resendMail(request, response) {
|
||||
try {
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
const docId = request.body.document_id;
|
||||
const userMail = request.body.email;
|
||||
const email_subject = request.body.email_subject;
|
||||
const email_body = request.body.email_body;
|
||||
const baseUrl = new URL(process.env.SERVER_URL);
|
||||
|
||||
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 docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.equalTo('objectId', docId);
|
||||
docQuery.equalTo('CreatedBy', userPtr);
|
||||
docQuery.include('Signers,ExtUserPtr');
|
||||
docQuery.notEqualTo('IsCompleted', true);
|
||||
docQuery.notEqualTo('IsDeclined', true);
|
||||
docQuery.notEqualTo('IsArchive', true);
|
||||
docQuery.greaterThanOrEqualTo('ExpiryDate', new Date());
|
||||
docQuery.exists('SignedUrl');
|
||||
docQuery.include('ExtUserPtr.TenantId');
|
||||
const resDoc = await docQuery.first({ useMasterKey: true });
|
||||
// console.log("resDoc ",resDoc)
|
||||
if (resDoc) {
|
||||
const _resDoc = resDoc.toJSON();
|
||||
const contact = _resDoc.Signers.find(x => x.Email === userMail);
|
||||
const activeMailAdapter = _resDoc?.ExtUserPtr?.active_mail_adapter || '';
|
||||
if (contact) {
|
||||
try {
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
};
|
||||
|
||||
const objectId = contact.objectId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
const title = _resDoc.Name;
|
||||
const receiverMail = contact.Email;
|
||||
//encode this url value `${response.id}/${receiverMail}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${_resDoc.objectId}/${receiverMail}/${objectId}`);
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||
const orgName = _resDoc.ExtUserPtr.Company ? _resDoc.ExtUserPtr.Company : '';
|
||||
const newDate = new Date(_resDoc.ExpiryDate.iso);
|
||||
newDate.setDate(newDate.getDate() + 15);
|
||||
const sender = _resDoc.ExtUserPtr.Email;
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const email_html =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
_resDoc.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
title +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> 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™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||
let replaceVar;
|
||||
const variables = {
|
||||
document_title: title,
|
||||
sender_name: _resDoc.ExtUserPtr.Name,
|
||||
sender_mail: _resDoc.ExtUserPtr.Email,
|
||||
sender_phone: _resDoc.ExtUserPtr?.Phone || '',
|
||||
receiver_name: contact.Name,
|
||||
receiver_email: contact.Email,
|
||||
receiver_phone: contact?.Phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: signPdf,
|
||||
};
|
||||
if (email_subject && email_body) {
|
||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||
} else if (email_subject) {
|
||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||
} else if (email_body) {
|
||||
replaceVar = replaceMailVaribles(
|
||||
`${_resDoc.ExtUserPtr.Name} has requested you to sign "${title}"`,
|
||||
email_body,
|
||||
variables
|
||||
);
|
||||
} else {
|
||||
replaceVar = {
|
||||
subject: `${_resDoc.ExtUserPtr.Name} has requested you to sign "${title}"`,
|
||||
body: email_html,
|
||||
};
|
||||
}
|
||||
const subject = replaceVar.subject;
|
||||
const html = replaceVar.body;
|
||||
|
||||
let params = {
|
||||
recipient: contact.Email,
|
||||
subject: subject,
|
||||
from: sender,
|
||||
html: html,
|
||||
extUserId: _resDoc.ExtUserPtr.objectId,
|
||||
mailProvider: activeMailAdapter,
|
||||
};
|
||||
|
||||
const res = await axios.post(url, params, { headers: headers });
|
||||
if (res.data.result && res.data.result.status === 'success') {
|
||||
return response.json({ result: 'mail sent successfully.' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
return response.status(400).json({ error: error.message });
|
||||
}
|
||||
} else {
|
||||
return response.status(404).json({ error: 'user not found.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(404).json({ error: 'document not found.' });
|
||||
}
|
||||
} else {
|
||||
return response.status(405).json({ error: 'Invalid API Token.' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in resendmail', err);
|
||||
return response.status(400).json({ error: err.message || 'Something went wrong.' });
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
export default async function saveWebhook(request, response) {
|
||||
const Url = request.body.url;
|
||||
const reqToken = request.headers['x-api-token'];
|
||||
if (!reqToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
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 query = new Parse.Query('contracts_Users');
|
||||
query.equalTo('UserId', userPtr);
|
||||
const user = await query.first({ useMasterKey: true });
|
||||
if (user) {
|
||||
const extUser = JSON.parse(JSON.stringify(user));
|
||||
const isUrlExist = extUser?.Webhook && extUser?.Webhook === Url;
|
||||
|
||||
if (!isUrlExist) {
|
||||
try {
|
||||
const updateQuery = new Parse.Object('contracts_Users');
|
||||
updateQuery.id = user.id;
|
||||
updateQuery.set('Webhook', Url);
|
||||
const res = await updateQuery.save(null, { useMasterKey: true });
|
||||
if (res) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_save_webhook',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
result: 'Webhook updated successfully!',
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_save_webhook',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
console.log('Err ', err);
|
||||
return response
|
||||
.status(400)
|
||||
.json({ error: 'Something went wrong, please try again later!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_save_webhook',
|
||||
properties: { response_code: 401 },
|
||||
});
|
||||
}
|
||||
return response.status(401).json({ error: 'Webhook url already exists!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_save_webhook',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'User not found!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
export default async function updateDocument(request, response) {
|
||||
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 allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP', 'enableTour'];
|
||||
const objectKeys = Object.keys(request.body);
|
||||
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
|
||||
const parseUser = JSON.parse(JSON.stringify(token));
|
||||
const userPtr = {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: parseUser.userId.objectId,
|
||||
};
|
||||
if (isValid) {
|
||||
const document = new Parse.Query('contracts_Document');
|
||||
document.equalTo('objectId', request.params.document_id);
|
||||
document.equalTo('CreatedBy', userPtr);
|
||||
document.include('ExtUserPtr.TenantId');
|
||||
const res = await document.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const isArchive = res.get('IsArchive');
|
||||
if (isArchive && isArchive) {
|
||||
return response.status(404).json({ message: 'Document not found!' });
|
||||
} else {
|
||||
const document = Parse.Object.extend('contracts_Document');
|
||||
const updateQuery = new document();
|
||||
updateQuery.id = request.params.document_id;
|
||||
if (request?.body?.name) {
|
||||
updateQuery.set('Name', request?.body?.name);
|
||||
}
|
||||
if (request?.body?.note) {
|
||||
updateQuery.set('Note', request?.body?.note);
|
||||
}
|
||||
if (request?.body?.description) {
|
||||
updateQuery.set('Description', request?.body?.description);
|
||||
}
|
||||
if (request?.body?.folderId) {
|
||||
updateQuery.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: request?.body?.folderId,
|
||||
});
|
||||
}
|
||||
if (request.body?.enableOTP !== undefined) {
|
||||
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
||||
}
|
||||
if (request.body?.enableTour !== undefined) {
|
||||
updateQuery.set('IsTourEnabled', request.body?.enableTour);
|
||||
}
|
||||
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
||||
if (updatedRes) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_document',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: updatedRes.id,
|
||||
updatedAt: updatedRes.get('updatedAt'),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_document',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Document not found!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_document',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide valid field names!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
export default async function updateFolder(request, response) {
|
||||
const apiToken = request.headers['x-api-token'];
|
||||
const folderId = request.params.folder_id;
|
||||
const name = request.body.folderName;
|
||||
const parentFolderId = request.body.parentFolderId;
|
||||
if (!apiToken) {
|
||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||
}
|
||||
try {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('token', apiToken);
|
||||
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 folderCls = new Parse.Query('contracts_Document');
|
||||
folderCls.equalTo('CreatedBy', userPtr);
|
||||
folderCls.equalTo('objectId', folderId);
|
||||
folderCls.equalTo('Type', 'Folder');
|
||||
folderCls.notEqualTo('IsArchive', true);
|
||||
folderCls.include('ExtUserPtr.TenantId');
|
||||
const res = await folderCls.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const updateFolder = new Parse.Object('contracts_Document');
|
||||
updateFolder.id = res.id;
|
||||
updateFolder.set('Name', name);
|
||||
if (parentFolderId) {
|
||||
updateFolder.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: parentFolderId,
|
||||
});
|
||||
}
|
||||
const updateRes = await updateFolder.save(null, { useMasterKey: true });
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_folder',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({ objectId: updateRes.id, updatedAt: updateRes.updatedAt });
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_folder',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'folder not found.' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
export default async function updateTemplate(request, response) {
|
||||
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 allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP', 'enableTour'];
|
||||
const objectKeys = Object.keys(request.body);
|
||||
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
|
||||
const parseUser = JSON.parse(JSON.stringify(token));
|
||||
const userPtr = {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: parseUser.userId.objectId,
|
||||
};
|
||||
if (isValid) {
|
||||
const template = new Parse.Query('contracts_Template');
|
||||
template.equalTo('objectId', request.params.template_id);
|
||||
template.equalTo('CreatedBy', userPtr);
|
||||
template.include('ExtUserPtr.TenantId');
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const isArchive = res.get('IsArchive');
|
||||
if (isArchive && isArchive) {
|
||||
return response.status(404).json({ message: 'Template not found!' });
|
||||
} else {
|
||||
const template = Parse.Object.extend('contracts_Template');
|
||||
const updateQuery = new template();
|
||||
updateQuery.id = request.params.template_id;
|
||||
if (request?.body?.name) {
|
||||
updateQuery.set('Name', request?.body?.name);
|
||||
}
|
||||
if (request?.body?.note) {
|
||||
updateQuery.set('Note', request?.body?.note);
|
||||
}
|
||||
if (request?.body?.description) {
|
||||
updateQuery.set('Description', request?.body?.description);
|
||||
}
|
||||
if (request?.body?.folderId) {
|
||||
updateQuery.set('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Template',
|
||||
objectId: request?.body?.folderId,
|
||||
});
|
||||
}
|
||||
if (request.body?.enableOTP !== undefined) {
|
||||
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
||||
}
|
||||
if (request.body?.enableTour !== undefined) {
|
||||
updateQuery.set('IsTourEnabled', request.body?.enableTour);
|
||||
}
|
||||
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
||||
if (updatedRes) {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_template',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return response.json({
|
||||
objectId: updatedRes.id,
|
||||
updatedAt: updatedRes.get('updatedAt'),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_template',
|
||||
properties: { response_code: 404 },
|
||||
});
|
||||
}
|
||||
return response.status(404).json({ error: 'Template not found!' });
|
||||
}
|
||||
} else {
|
||||
if (request.posthog) {
|
||||
request.posthog?.capture({
|
||||
distinctId: parseUser.userId.email,
|
||||
event: 'api_update_template',
|
||||
properties: { response_code: 400 },
|
||||
});
|
||||
}
|
||||
return response.status(400).json({ error: 'Please provide valid field names!' });
|
||||
}
|
||||
} 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!' });
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import { createTransport } from 'nodemailer';
|
||||
import { appName } from '../../Utils.js';
|
||||
// Online Javascript Editor for free
|
||||
// Write, Edit and Run your Javascript code using JS Online Compiler
|
||||
|
||||
function generateOtpWithSum10() {
|
||||
let otp = [];
|
||||
let sum = 0;
|
||||
|
||||
// First, generate 3 random digits (0-9) and add them to the sum
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let digit = Math.floor(Math.random() * 10);
|
||||
otp.push(digit);
|
||||
sum += digit;
|
||||
}
|
||||
|
||||
// Calculate the last digit to ensure the sum equals 10
|
||||
let lastDigit = 10 - sum;
|
||||
|
||||
// If the last digit is not valid (e.g., greater than 9), regenerate
|
||||
if (lastDigit >= 0 && lastDigit <= 9) {
|
||||
otp.push(lastDigit);
|
||||
} else {
|
||||
return generateOtpWithSum10(); // Recursively generate again
|
||||
}
|
||||
|
||||
return otp.join('');
|
||||
}
|
||||
|
||||
export default async function validateSmtp(request, response) {
|
||||
const host = request.body.host;
|
||||
const port = request.body?.port?.toString();
|
||||
const username = request.body.username;
|
||||
const password = request.body.password;
|
||||
const secure = request.body?.secure;
|
||||
const email = request.body?.email;
|
||||
const otp = generateOtpWithSum10();
|
||||
// console.log('Generated OTP:', otp);
|
||||
|
||||
try {
|
||||
const smtpsecure = secure || port !== '465' ? false : true;
|
||||
const transporterSMTP = createTransport({
|
||||
host: host,
|
||||
port: port,
|
||||
secure: smtpsecure,
|
||||
auth: { user: username, pass: password },
|
||||
});
|
||||
const from = appName;
|
||||
const mailsender = username;
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: email,
|
||||
subject: `Your ${appName} SMTP credentials verification code`,
|
||||
text: 'mail',
|
||||
html:
|
||||
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>SMTP Verification Code</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your verification code is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
|
||||
otp +
|
||||
'</p></div> </div> </div></body></html>',
|
||||
};
|
||||
|
||||
const res = await transporterSMTP.sendMail(messageParams);
|
||||
console.log('custom smtp transporter res: ', res?.response);
|
||||
if (!res.err) {
|
||||
response.status(200).json({ message: 'success' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
const code = err?.responseCode || 400;
|
||||
const message = err?.response || 'failed!';
|
||||
response.status(code).json({ error: message });
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
|
||||
import PDF from './parsefunction/pdf/PDF.js';
|
||||
import sendmailv3 from './parsefunction/sendMailv3.js';
|
||||
import GoogleSign from './parsefunction/GoogleSign.js';
|
||||
import ZohoDetails from './parsefunction/ZohoDetails.js';
|
||||
import usersignup from './parsefunction/usersignup.js';
|
||||
import FacebookSign from './parsefunction/FacebookSign.js';
|
||||
import DocumentAftersave from './parsefunction/DocumentAftersave.js';
|
||||
import ContactbookAftersave from './parsefunction/ContactBookAftersave.js';
|
||||
import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
|
||||
@@ -13,86 +11,53 @@ import getUserDetails from './parsefunction/getUserDetails.js';
|
||||
import getDocument from './parsefunction/getDocument.js';
|
||||
import getDrive from './parsefunction/getDrive.js';
|
||||
import getReport from './parsefunction/getReport.js';
|
||||
import generateApiToken from './parsefunction/generateApiToken.js';
|
||||
import getapitoken from './parsefunction/getapitoken.js';
|
||||
import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
|
||||
import GetTemplate from './parsefunction/GetTemplate.js';
|
||||
import savewebhook from './parsefunction/saveWebhook.js';
|
||||
import callWebhook from './parsefunction/callWebhook.js';
|
||||
import SubscribeFree from './parsefunction/SubscribeFree.js';
|
||||
import DocumentBeforesave from './parsefunction/DocumentBeforesave.js';
|
||||
import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js';
|
||||
import DocumentBeforeFind from './parsefunction/DocumentAfterFind.js';
|
||||
import TemplateAfterFind from './parsefunction/TemplateAfterFind.js';
|
||||
import UserAfterFind from './parsefunction/UserAfterFInd.js';
|
||||
import SignatureAfterFind from './parsefunction/SignatureAfterFind.js';
|
||||
import getInvoices from './parsefunction/getInvoices.js';
|
||||
import getPayments from './parsefunction/getPayments.js';
|
||||
import getSubscriptions from './parsefunction/getSubscriptions.js';
|
||||
import TenantAterFind from './parsefunction/TenantAfterFind.js';
|
||||
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';
|
||||
import CreatePublicTemplate from './parsefunction/CreatePublicTemplate.js';
|
||||
import GetPublicUserName from './parsefunction/GetPublicUserName.js';
|
||||
import GetPublicTemplate from './parsefunction/GetPublicTemplate.js';
|
||||
import ssoSignin from './parsefunction/ssoSignin.js';
|
||||
import isextenduser from './parsefunction/isextenduser.js';
|
||||
import getUserByOrg from './parsefunction/getUserByOrg.js';
|
||||
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
|
||||
import TeamsAftersave from './parsefunction/TeamsAftersave.js';
|
||||
import SubscriptionAftersave from './parsefunction/SubscriptionAftersave.js';
|
||||
import PublicUserLinkContactToDoc from './parsefunction/PublicUserLinkContactToDoc.js';
|
||||
import GetLogoByDomain from './parsefunction/GetLogobyDomain.js';
|
||||
import GetLogoByDomain from './parsefunction/GetLogoByDomain.js';
|
||||
import AddAdmin from './parsefunction/AddAdmin.js';
|
||||
import CheckAdminExist from './parsefunction/CheckAdminExist.js';
|
||||
import UpdateExistUserAsAdmin from './parsefunction/UpdateExistUserAsAdmin.js';
|
||||
import Newsletter from './parsefunction/Newsletter.js';
|
||||
import getOrganizations from './parsefunction/getOrganizations.js';
|
||||
import addOrganization from './parsefunction/addOrganization.js';
|
||||
import updateOrganization from './parsefunction/updateOrganization.js';
|
||||
import getTeams from './parsefunction/getTeams.js';
|
||||
import addTeam from './parsefunction/addTeam.js';
|
||||
import updateTeam from './parsefunction/updateTeam.js';
|
||||
import getOrgAdmins from './parsefunction/getOrgAdmins.js';
|
||||
import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js';
|
||||
import AllowedUsers from './parsefunction/AlllowedUsers.js';
|
||||
import BuyAddonUsers from './parsefunction/BuyAddonUsers.js';
|
||||
import ExtUserAftersave from './parsefunction/ExtUserAftersave.js';
|
||||
import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js';
|
||||
import AllowedCredits from './parsefunction/AllowedCredits.js';
|
||||
import BuyCredits from './parsefunction/BuyCredits.js';
|
||||
import getContact from './parsefunction/getContact.js';
|
||||
import updateContactTour from './parsefunction/updateContactTour.js';
|
||||
import declinedocument from './parsefunction/declinedocument.js';
|
||||
import addcustomsmtp from './parsefunction/addcustomsmtp.js';
|
||||
import deactivateMailAdapter from './parsefunction/deactivateMailAdapter.js';
|
||||
import addFileAdapter from './parsefunction/addFileAdapter.js';
|
||||
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';
|
||||
import updateSignatureType from './parsefunction/updatesignaturetype.js';
|
||||
import updatePreferences from './parsefunction/updatePreferences.js';
|
||||
import createDuplicate from './parsefunction/createDuplicate.js';
|
||||
import createBatchContact from './parsefunction/createBatchContact.js';
|
||||
import generateCertificatebydocId from './parsefunction/generateCertificatebydocId.js';
|
||||
import fileUpload from './parsefunction/fileUpload.js';
|
||||
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
|
||||
import editContact from './parsefunction/editContact.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_Template', TemplateAfterSave);
|
||||
Parse.Cloud.afterSave('contracts_Teams', TeamsAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Subscriptions', SubscriptionAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Users', ExtUserAftersave);
|
||||
|
||||
// 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);
|
||||
@@ -105,16 +70,10 @@ Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind);
|
||||
Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
|
||||
Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
|
||||
|
||||
// This afterDelete function triggers after an object get deleted.
|
||||
Parse.Cloud.afterDelete('contracts_Users', ExtUserAfterdelete);
|
||||
|
||||
// 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('signPdf', PDF);
|
||||
Parse.Cloud.define('sendmailv3', sendmailv3);
|
||||
Parse.Cloud.define('googlesign', GoogleSign);
|
||||
Parse.Cloud.define('zohodetails', ZohoDetails);
|
||||
Parse.Cloud.define('usersignup', usersignup);
|
||||
Parse.Cloud.define('facebooksign', FacebookSign);
|
||||
Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
|
||||
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
|
||||
Parse.Cloud.define('getUserId', getUserId);
|
||||
@@ -122,63 +81,34 @@ Parse.Cloud.define('getUserDetails', getUserDetails);
|
||||
Parse.Cloud.define('getDocument', getDocument);
|
||||
Parse.Cloud.define('getDrive', getDrive);
|
||||
Parse.Cloud.define('getReport', getReport);
|
||||
Parse.Cloud.define('generateapitoken', generateApiToken);
|
||||
Parse.Cloud.define('getapitoken', getapitoken);
|
||||
Parse.Cloud.define('getTemplate', GetTemplate);
|
||||
Parse.Cloud.define('savewebhook', savewebhook);
|
||||
Parse.Cloud.define('callwebhook', callWebhook);
|
||||
Parse.Cloud.define('freesubscription', SubscribeFree);
|
||||
Parse.Cloud.define('getinvoices', getInvoices);
|
||||
Parse.Cloud.define('getpayments', getPayments);
|
||||
Parse.Cloud.define('getsubscriptions', getSubscriptions);
|
||||
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);
|
||||
Parse.Cloud.define('createpublictemplate', CreatePublicTemplate);
|
||||
Parse.Cloud.define('getpublicusername', GetPublicUserName);
|
||||
Parse.Cloud.define('getpublictemplate', GetPublicTemplate);
|
||||
Parse.Cloud.define('ssosign', ssoSignin);
|
||||
Parse.Cloud.define('isextenduser', isextenduser);
|
||||
Parse.Cloud.define('getuserbyorg', getUserByOrg);
|
||||
Parse.Cloud.define('getuserlistbyorg', getUserListByOrg);
|
||||
Parse.Cloud.define('publicuserlinkcontacttodoc', PublicUserLinkContactToDoc);
|
||||
Parse.Cloud.define('getlogobydomain', GetLogoByDomain);
|
||||
Parse.Cloud.define('addadmin', AddAdmin);
|
||||
Parse.Cloud.define('checkadminexist', CheckAdminExist);
|
||||
Parse.Cloud.define('updateuserasadmin', UpdateExistUserAsAdmin);
|
||||
Parse.Cloud.define('newsletter', Newsletter);
|
||||
Parse.Cloud.define('getorganizations', getOrganizations);
|
||||
Parse.Cloud.define('addorganization', addOrganization);
|
||||
Parse.Cloud.define('updateorganization', updateOrganization);
|
||||
Parse.Cloud.define('getteams', getTeams);
|
||||
Parse.Cloud.define('addteam', addTeam);
|
||||
Parse.Cloud.define('updateteam', updateTeam);
|
||||
Parse.Cloud.define('getorgadmins', getOrgAdmins);
|
||||
Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg);
|
||||
Parse.Cloud.define('allowedusers', AllowedUsers);
|
||||
Parse.Cloud.define('buyaddonusers', BuyAddonUsers);
|
||||
Parse.Cloud.define('allowedcredits', AllowedCredits);
|
||||
Parse.Cloud.define('buycredits', BuyCredits);
|
||||
Parse.Cloud.define('getcontact', getContact);
|
||||
Parse.Cloud.define('updatecontacttour', updateContactTour);
|
||||
Parse.Cloud.define('declinedoc', declinedocument);
|
||||
Parse.Cloud.define('addsmtp', addcustomsmtp);
|
||||
Parse.Cloud.define('deactivatemailadapter', deactivateMailAdapter);
|
||||
Parse.Cloud.define('savetofileadapter', saveToFileAdapter);
|
||||
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);
|
||||
Parse.Cloud.define('updatesignaturetype', updateSignatureType);
|
||||
Parse.Cloud.define('updatepreferences', updatePreferences);
|
||||
Parse.Cloud.define('createduplicate', createDuplicate);
|
||||
Parse.Cloud.define('createbatchcontact', createBatchContact);
|
||||
Parse.Cloud.define('generatecertificate', generateCertificatebydocId);
|
||||
Parse.Cloud.define('fileupload', fileUpload);
|
||||
Parse.Cloud.define('getuserlistbyorg', getUserListByOrg);
|
||||
Parse.Cloud.define('editcontact', editContact);
|
||||
|
||||
@@ -5,51 +5,55 @@ const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
async function addTeamAndOrg(extUser) {
|
||||
try {
|
||||
const orgCls = new Parse.Object('contracts_Organizations');
|
||||
orgCls.set('Name', extUser.Company);
|
||||
orgCls.set('IsActive', true);
|
||||
orgCls.set('ExtUserId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser?.objectId,
|
||||
});
|
||||
orgCls.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser?.UserId?.objectId,
|
||||
});
|
||||
orgCls.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser?.TenantId?.objectId,
|
||||
});
|
||||
|
||||
const orgRes = await orgCls.save(null, { useMasterKey: true });
|
||||
const teamCls = new Parse.Object('contracts_Teams');
|
||||
teamCls.set('Name', 'All Users');
|
||||
teamCls.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
teamCls.set('IsActive', true);
|
||||
const teamRes = await teamCls.save(null, { useMasterKey: true });
|
||||
const updateUser = new Parse.Object('contracts_Users');
|
||||
updateUser.id = extUser.objectId;
|
||||
updateUser.set('UserRole', 'contracts_Admin');
|
||||
updateUser.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
updateUser.set('TeamIds', [
|
||||
{
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
const updateUser = await extUserCls.get(extUser.objectId, { useMasterKey: true });
|
||||
if (updateUser && !updateUser?.get('OrganizationId')) {
|
||||
const orgCls = new Parse.Object('contracts_Organizations');
|
||||
orgCls.set('Name', extUser.Company);
|
||||
orgCls.set('IsActive', true);
|
||||
orgCls.set('ExtUserId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Teams',
|
||||
objectId: teamRes.id,
|
||||
},
|
||||
]);
|
||||
const extUserRes = await updateUser.save(null, { useMasterKey: true });
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser?.objectId,
|
||||
});
|
||||
orgCls.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser?.UserId?.objectId,
|
||||
});
|
||||
orgCls.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser?.TenantId?.objectId,
|
||||
});
|
||||
|
||||
const orgRes = await orgCls.save(null, { useMasterKey: true });
|
||||
const teamCls = new Parse.Object('contracts_Teams');
|
||||
teamCls.set('Name', 'All Users');
|
||||
teamCls.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
teamCls.set('IsActive', true);
|
||||
const teamRes = await teamCls.save(null, { useMasterKey: true });
|
||||
// const updateUser = new Parse.Object('contracts_Users');
|
||||
// updateUser.id = extUser.objectId;
|
||||
updateUser.set('UserRole', 'contracts_Admin');
|
||||
updateUser.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
updateUser.set('TeamIds', [
|
||||
{
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Teams',
|
||||
objectId: teamRes.id,
|
||||
},
|
||||
]);
|
||||
const extUserRes = await updateUser.save(null, { useMasterKey: true });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in add team, role, org', err);
|
||||
}
|
||||
@@ -94,7 +98,6 @@ async function saveUser(userDetails) {
|
||||
}
|
||||
export default async function AddAdmin(request) {
|
||||
const userDetails = request.params.userDetails;
|
||||
// const subscription = request.params.subscription;
|
||||
const user = await saveUser(userDetails);
|
||||
|
||||
try {
|
||||
@@ -167,8 +170,10 @@ export default async function AddAdmin(request) {
|
||||
if (userDetails && userDetails.jobTitle) {
|
||||
newObj.set('JobTitle', userDetails.jobTitle);
|
||||
}
|
||||
if (userDetails?.timezone) {
|
||||
newObj.set('Timezone', userDetails?.timezone);
|
||||
}
|
||||
const extRes = await newObj.save(null, { useMasterKey: true });
|
||||
// if (subscription) {
|
||||
const extUser = {
|
||||
objectId: extRes.id,
|
||||
Name: userDetails.name,
|
||||
@@ -181,8 +186,6 @@ export default async function AddAdmin(request) {
|
||||
JobTitle: userDetails.jobTitle,
|
||||
};
|
||||
await addTeamAndOrg(extUser);
|
||||
// await saveSubscription(extRes.id, user.id, tenantRes.id, subscription);
|
||||
// }
|
||||
return { message: 'User sign up', sessionToken: user.sessionToken };
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
export default async function AllowedUsers(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', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
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 count = _resSub?.UsersCount || 0;
|
||||
if (count > 0) {
|
||||
const allowedUser = resSub.get('AllowedUsers') || 0;
|
||||
const remainUsers = allowedUser - count;
|
||||
if (remainUsers > 0) {
|
||||
return remainUsers;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
const alloweduser = resSub.get('AllowedUsers') || 0;
|
||||
return alloweduser;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in allowedusers', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
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: '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 };
|
||||
}
|
||||
} 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.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in allowedCredits', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { planCredits } from '../../Utils.js';
|
||||
export default async function BuyAddonUsers(request) {
|
||||
const users = request.params.users;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
if (users) {
|
||||
try {
|
||||
const extUser = new Parse.Query('contracts_Users');
|
||||
extUser.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
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));
|
||||
// Define the URL
|
||||
const url = 'https://accounts.zoho.in/oauth/v2/token';
|
||||
|
||||
// Convert the data to x-www-form-urlencoded format
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
|
||||
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
|
||||
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
|
||||
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
|
||||
formData.append('grant_type', 'refresh_token');
|
||||
|
||||
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||
// Make the POST request using Axios
|
||||
const res = await axios.post(url, formData, { headers });
|
||||
if (res.data.access_token) {
|
||||
const subscriptionId = _resSub.SubscriptionId;
|
||||
const price = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.price;
|
||||
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
|
||||
const addonsArr = _resSub?.SubscriptionDetails?.data?.subscription?.addons || [];
|
||||
let addon = 0;
|
||||
if (addonsArr?.length > 0) {
|
||||
let allowedUsersMonthly = 0;
|
||||
let allowedUsersYearly = 0;
|
||||
addonsArr?.forEach(item => {
|
||||
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||
allowedUsersYearly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-users') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
}
|
||||
});
|
||||
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||
addon = allowedUsersMonthly + allowedUsersYearly;
|
||||
}
|
||||
}
|
||||
const quantity = parseInt(users) + parseInt(addon);
|
||||
const addoncode = plan_code.includes('yearly')
|
||||
? 'extra-teams-users-yearly'
|
||||
: 'extra-teams-users-monthly';
|
||||
const data = JSON.stringify({
|
||||
plan: { plan_code: plan_code },
|
||||
addons: [
|
||||
{
|
||||
addon_code: addoncode,
|
||||
addon_description: 'Extra users',
|
||||
price: price,
|
||||
quantity: quantity,
|
||||
},
|
||||
],
|
||||
});
|
||||
const updatedSubscription = await axios.put(
|
||||
'https://www.zohoapis.in/billing/v1/subscriptions/' + subscriptionId,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||
},
|
||||
}
|
||||
);
|
||||
const subscriptionInfo = { data: updatedSubscription.data };
|
||||
const allowedUsers = quantity + 1;
|
||||
const existAllowedCredits = _resSub?.AllowedCredits || 0;
|
||||
const credits = resSub?.PlanCredits || planCredits[plan_code];
|
||||
const newAllowedCredits = users * credits;
|
||||
const totalCredits = existAllowedCredits + newAllowedCredits;
|
||||
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||
updateSub.id = resSub.id;
|
||||
updateSub.set('SubscriptionDetails', subscriptionInfo);
|
||||
updateSub.set('AllowedUsers', allowedUsers);
|
||||
updateSub.set('AllowedCredits', totalCredits);
|
||||
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
|
||||
return { status: 'success', addon: allowedUsers };
|
||||
} else {
|
||||
throw new Parse.Error('400', 'Invalid access token.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||
const msg =
|
||||
err?.response?.data?.error ||
|
||||
err?.response?.data ||
|
||||
err?.message ||
|
||||
'Something went wrong.';
|
||||
console.log('err in buyaddon', code, msg);
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import axios from 'axios';
|
||||
export default async function BuyCredits(request) {
|
||||
const credits = request.params.credits;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
if (credits) {
|
||||
try {
|
||||
const extUser = new Parse.Query('contracts_Users');
|
||||
extUser.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
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));
|
||||
// Define the URL
|
||||
const url = 'https://accounts.zoho.in/oauth/v2/token';
|
||||
|
||||
// Convert the data to x-www-form-urlencoded format
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
|
||||
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
|
||||
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
|
||||
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
|
||||
formData.append('grant_type', 'refresh_token');
|
||||
|
||||
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||
|
||||
// Make the POST request using Axios
|
||||
const res = await axios.post(url, formData, { headers });
|
||||
if (res.data.access_token) {
|
||||
const subscriptionId = _resSub.SubscriptionId;
|
||||
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
|
||||
const quantity = parseInt(credits);
|
||||
const addoncode = 'addon-credits';
|
||||
const data = JSON.stringify({
|
||||
plan: { plan_code: plan_code },
|
||||
addons: [
|
||||
{ addon_code: addoncode, addon_description: 'addon credits', quantity: quantity },
|
||||
],
|
||||
});
|
||||
const creditsUrl = `https://www.zohoapis.in/billing/v1/subscriptions/${subscriptionId}/buyonetimeaddon`;
|
||||
const resCredits = await axios.post(creditsUrl, data, {
|
||||
headers: {
|
||||
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||
},
|
||||
});
|
||||
// console.log('resCredits ', resCredits.data);
|
||||
if (resCredits.data) {
|
||||
const existAddonCredits = _resSub?.AddonCredits ? _resSub.AddonCredits : 0;
|
||||
const addonCredits = existAddonCredits + quantity;
|
||||
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||
updateSub.id = resSub.id;
|
||||
updateSub.set('AddonCredits', addonCredits);
|
||||
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
|
||||
// console.log('resupdateSub ', resupdateSub);
|
||||
return { status: 'success', addon: quantity };
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error('400', 'Invalid access token.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||
const msg =
|
||||
err?.response?.data?.error ||
|
||||
err?.response?.data ||
|
||||
err?.message ||
|
||||
'Something went wrong.';
|
||||
console.log('err in Buyaddonusers', code, msg);
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.');
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,66 @@ async function ContactbookAftersave(request) {
|
||||
you can check as follows */
|
||||
if (!request.original) {
|
||||
const user = request.user;
|
||||
|
||||
// Retrieve the current ACL
|
||||
const acl = new Parse.ACL();
|
||||
|
||||
// Ensure the current user has read access
|
||||
if (acl && request?.user) {
|
||||
const object = request.object;
|
||||
acl.setReadAccess(user, true);
|
||||
acl.setWriteAccess(user, true);
|
||||
acl.setReadAccess(object.get('UserId'), true);
|
||||
acl.setWriteAccess(object.get('UserId'), true);
|
||||
const object = request.object;
|
||||
if (object.get('UserId')) {
|
||||
// Retrieve the current ACL
|
||||
const acl = new Parse.ACL();
|
||||
// Ensure the current user has read access
|
||||
if (acl && request?.user) {
|
||||
const object = request.object;
|
||||
acl.setReadAccess(user, true);
|
||||
acl.setWriteAccess(user, true);
|
||||
acl.setReadAccess(object.get('UserId'), true);
|
||||
acl.setWriteAccess(object.get('UserId'), true);
|
||||
|
||||
object.setACL(acl);
|
||||
object.set('IsDeleted', false)
|
||||
// Continue saving the object
|
||||
return object.save(null, { useMasterKey: true });
|
||||
object.setACL(acl);
|
||||
object.set('IsDeleted', false);
|
||||
// Continue saving the object
|
||||
return object.save(null, { useMasterKey: true });
|
||||
}
|
||||
} else {
|
||||
const Name = object.get('Name');
|
||||
const Email = object.get('Email');
|
||||
const Phone = object.get('Phone');
|
||||
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 (Email) {
|
||||
_user.set('phone', Phone);
|
||||
}
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
object.set('UserId', user);
|
||||
const acl = object.getACL() || new Parse.ACL();
|
||||
acl.setReadAccess(user.id, true);
|
||||
acl.setWriteAccess(user.id, true);
|
||||
object.setACL(acl);
|
||||
await object.save(null, { useMasterKey: true });
|
||||
// console.log('res update new user with contac', res);
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log('err ', err);
|
||||
if (err.code === 202) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('email', Email);
|
||||
const userRes = await userQuery.first({ useMasterKey: true });
|
||||
object.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userRes.id,
|
||||
});
|
||||
const acl = object.getACL() || new Parse.ACL();
|
||||
acl.setReadAccess(userRes.id, true);
|
||||
acl.setWriteAccess(userRes.id, true);
|
||||
object.setACL(acl);
|
||||
await object.save(null, { useMasterKey: true });
|
||||
// console.log('res update existing user with contact', res);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('Object being update');
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
export default async function CreatePublicTemplate(request) {
|
||||
const templateid = request.params.templateid;
|
||||
const ispublic = request.params.ispublic;
|
||||
const publicrole = request.params.publicrole;
|
||||
try {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
} else {
|
||||
const userId = request?.user && request?.user?.id;
|
||||
if (templateid) {
|
||||
const updateTemplate = new Parse.Object('contracts_Template');
|
||||
updateTemplate.id = templateid;
|
||||
if (ispublic) {
|
||||
updateTemplate.set('PublicRole', publicrole);
|
||||
}
|
||||
updateTemplate.set('IsPublic', ispublic);
|
||||
const Acl = new Parse.ACL();
|
||||
if (ispublic) {
|
||||
Acl.setPublicReadAccess(true);
|
||||
}
|
||||
Acl.setReadAccess(userId, true);
|
||||
Acl.setWriteAccess(userId, true);
|
||||
updateTemplate.setACL(Acl);
|
||||
const savedObject = await updateTemplate.save(null, { useMasterKey: true });
|
||||
const res = savedObject.toJSON();
|
||||
if (res) {
|
||||
return {
|
||||
status: 'success',
|
||||
};
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err.code || 400;
|
||||
const msg = err.message;
|
||||
const error = new Parse.Error(code, msg);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,53 @@
|
||||
import { useLocal } from '../../Utils.js';
|
||||
import getPresignedUrl from './getSignedUrl.js';
|
||||
import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
|
||||
|
||||
async function DocumentAfterFind(request) {
|
||||
if (request.objects.length === 1) {
|
||||
if (request.objects) {
|
||||
const obj = request.objects[0];
|
||||
const FileAdapterId = obj?.get('FileAdapterId') || '';
|
||||
if (FileAdapterId || useLocal !== 'true') {
|
||||
if (
|
||||
useLocal !== 'true'
|
||||
) {
|
||||
const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
|
||||
const Url = obj?.get('URL') && obj?.get('URL');
|
||||
const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
|
||||
let fileAdapter = {};
|
||||
if (FileAdapterId) {
|
||||
const tenantId = obj?.get('ExtUserPtr')?.get('TenantId');
|
||||
if (tenantId) {
|
||||
const _tenantId = JSON.parse(JSON.stringify(obj?.get('ExtUserPtr')?.get('TenantId')));
|
||||
fileAdapter = _tenantId?.FileAdapters?.find(x => x.id === FileAdapterId) || {};
|
||||
}
|
||||
}
|
||||
if (SignedUrl) {
|
||||
obj.set('SignedUrl', getPresignedUrl(SignedUrl, fileAdapter));
|
||||
obj.set(
|
||||
'SignedUrl',
|
||||
getPresignedUrl(
|
||||
SignedUrl,
|
||||
)
|
||||
);
|
||||
}
|
||||
if (Url) {
|
||||
obj.set('URL', getPresignedUrl(Url, fileAdapter));
|
||||
obj.set(
|
||||
'URL',
|
||||
getPresignedUrl(
|
||||
Url,
|
||||
)
|
||||
);
|
||||
}
|
||||
if (certificateUrl) {
|
||||
obj.set('CertificateUrl', getPresignedUrl(certificateUrl, fileAdapter));
|
||||
obj.set(
|
||||
'CertificateUrl',
|
||||
getPresignedUrl(
|
||||
certificateUrl,
|
||||
)
|
||||
);
|
||||
}
|
||||
return [obj];
|
||||
} else if (useLocal == 'true') {
|
||||
const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
|
||||
const Url = obj?.get('URL') && obj?.get('URL');
|
||||
const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
|
||||
if (SignedUrl) {
|
||||
obj.set('SignedUrl', presignedlocalUrl(SignedUrl));
|
||||
}
|
||||
if (Url) {
|
||||
obj.set('URL', presignedlocalUrl(Url));
|
||||
}
|
||||
if (certificateUrl) {
|
||||
obj.set('CertificateUrl', presignedlocalUrl(certificateUrl));
|
||||
}
|
||||
return [obj];
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
async function ExtUserAfterdelete(request) {
|
||||
try {
|
||||
const extUser = request.object;
|
||||
const tenantId = extUser.get('TenantId')?.id;
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
});
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||
updateSub.id = resSub.id;
|
||||
if (resSub?.get('UsersCount') > 0) {
|
||||
updateSub.decrement('UsersCount', 1);
|
||||
} else {
|
||||
updateSub.decrement('UsersCount', 0);
|
||||
}
|
||||
updateSub.save(null, { useMasterKey: true });
|
||||
} else {
|
||||
const addSub = new Parse.Object('contracts_Subscriptions');
|
||||
addSub.set('UsersCount', 0);
|
||||
addSub.save(null, { useMasterKey: true });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in extuser afterdelete', err);
|
||||
}
|
||||
}
|
||||
|
||||
export default ExtUserAfterdelete;
|
||||
@@ -1,44 +0,0 @@
|
||||
async function ExtUserAftersave(request) {
|
||||
try {
|
||||
if (!request.original) {
|
||||
const extUser = request.object;
|
||||
const tenantId = extUser.get('TenantId')?.id;
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
});
|
||||
const resSub = await subscription.first({ useMasterKey: true });
|
||||
if (resSub) {
|
||||
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||
updateSub.id = resSub.id;
|
||||
updateSub.increment('UsersCount', 1);
|
||||
await updateSub.save(null, { useMasterKey: true });
|
||||
} else {
|
||||
const addSub = new Parse.Object('contracts_Subscriptions');
|
||||
addSub.set('UsersCount', 1);
|
||||
addSub.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
addSub.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser.get('UserId').id,
|
||||
});
|
||||
addSub.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
await addSub.save(null, { useMasterKey: true });
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in extuser aftersave', err);
|
||||
}
|
||||
}
|
||||
|
||||
export default ExtUserAftersave;
|
||||
@@ -1,93 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
|
||||
/**
|
||||
* FacebookSign is function which is used to sign up/sign in with google
|
||||
* @param Id It is google Id
|
||||
* @param AccessToken It is facebook Access Token
|
||||
* @param Email It is user's email with user sign in/sign up
|
||||
* @param Phone It is user's Phone number
|
||||
* @param Name It is user's Name
|
||||
* @returns if success {email, message, sessiontoken} else on reject {message}
|
||||
*/
|
||||
|
||||
export default async function FacebookSign(request) {
|
||||
const userGoogleId = request.params.Id;
|
||||
const userAccessToken = request.params.AccessToken;
|
||||
const userEmail = request.params.Email;
|
||||
const phone = request.params?.Phone || '';
|
||||
const name = request.params.Name;
|
||||
const authData = {
|
||||
facebook: { id: userGoogleId, access_token: userAccessToken },
|
||||
};
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('email', userEmail);
|
||||
const res = await userQuery.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
try {
|
||||
const SignIn = await axios.put(
|
||||
serverUrl + '/users/' + res.id,
|
||||
{ authData: authData },
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Master-key': masterKEY,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (SignIn.data) {
|
||||
// console.log("google Sign in", SignIn);
|
||||
const sessiontoken = SignIn.data.sessionToken;
|
||||
console.log('Google sessiontoken', sessiontoken);
|
||||
return {
|
||||
email: userEmail,
|
||||
message: 'User Sign In',
|
||||
sessiontoken: sessiontoken,
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in user google sign in', err);
|
||||
return { message: 'Internal server error' };
|
||||
}
|
||||
} else {
|
||||
// console.log("in sign up condition");
|
||||
try {
|
||||
const SignUp = await axios.post(
|
||||
serverUrl + '/users',
|
||||
{
|
||||
authData: authData,
|
||||
username: userEmail,
|
||||
email: userEmail,
|
||||
phone: phone,
|
||||
name: name,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Revocable-Session': '1',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// console.log("SignUp", SignUp);
|
||||
|
||||
if (SignUp.data) {
|
||||
const sessiontoken = SignUp.data.sessionToken;
|
||||
const payload = {
|
||||
email: userEmail,
|
||||
message: 'User Sign Up',
|
||||
sessiontoken: sessiontoken,
|
||||
};
|
||||
return payload;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in user google sign up', err);
|
||||
return { message: 'Internal server err' };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
async function GetPublicTemplate(request) {
|
||||
try {
|
||||
const username = request.params.username;
|
||||
if (username) {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('UserName', username);
|
||||
const userRes = await extUserQuery.first({ useMasterKey: true });
|
||||
const userId = userRes.get('UserId').id;
|
||||
|
||||
//get _user details
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(userId, { useMasterKey: true });
|
||||
if (userId) {
|
||||
const templatQuery = new Parse.Query('contracts_Template');
|
||||
templatQuery.equalTo('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
templatQuery.descending('updatedAt');
|
||||
templatQuery.equalTo('IsPublic', true);
|
||||
templatQuery.notEqualTo('IsArchive', true);
|
||||
templatQuery.include('ExtUserPtr.TenantId');
|
||||
const getTemplate = await templatQuery.find({ useMasterKey: true });
|
||||
const extcls = new Parse.Query('contracts_Users');
|
||||
extcls.equalTo('Email', user.get('email'));
|
||||
const res = await extcls.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const _res = JSON.parse(JSON.stringify(res));
|
||||
return {
|
||||
template: getTemplate,
|
||||
user: user,
|
||||
extend_User: { Tagline: _res?.Tagline || '', SearchIndex: _res?.SearchIndex || '' },
|
||||
};
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User does not exist');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err.code || 400;
|
||||
const msg = err.message;
|
||||
const error = new Parse.Error(code, msg);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
export default GetPublicTemplate;
|
||||
@@ -1,23 +0,0 @@
|
||||
async function GetPublicUserName(request) {
|
||||
try {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
} else {
|
||||
const username = request.params.username;
|
||||
if (username) {
|
||||
const userQuery = new Parse.Query('contracts_Users');
|
||||
userQuery.equalTo('UserName', username);
|
||||
const res = await userQuery.first({ useMasterKey: true });
|
||||
return res;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err.code || 400;
|
||||
const msg = err.message;
|
||||
const error = new Parse.Error(code, msg);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
export default GetPublicUserName;
|
||||
@@ -1,45 +1,17 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import {
|
||||
cloudServerUrl,
|
||||
} from '../../Utils.js';
|
||||
|
||||
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) {
|
||||
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) {
|
||||
if (sessiontoken) {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
@@ -56,6 +28,7 @@ export default async function GetTemplate(request) {
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
template.include('ExtUserPtr.TenantId');
|
||||
template.include('Bcc');
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', userEmail);
|
||||
extUserQuery.include('TeamIds');
|
||||
@@ -83,6 +56,7 @@ export default async function GetTemplate(request) {
|
||||
template.include('CreatedBy');
|
||||
template.include('ExtUserPtr.TenantId');
|
||||
template.include('Placeholders.signerPtr');
|
||||
template.include('Bcc');
|
||||
}
|
||||
}
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
@@ -109,6 +83,7 @@ export default async function GetTemplate(request) {
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
template.include('ExtUserPtr.TenantId');
|
||||
template.include('Bcc');
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
// console.log("res ", res)
|
||||
if (res) {
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
|
||||
/**
|
||||
* GoogleSign is function which is used to sign up/sign in with google
|
||||
* @param Id It is google Id
|
||||
* @param TokenId It is google token Id
|
||||
* @param Gmail It is user's gmail with user sign in/sign up
|
||||
* @param Phone It is user's Phone number
|
||||
* @param Name It is user's Name
|
||||
* @returns if success {email, message, sessiontoken} else on reject {message}
|
||||
*/
|
||||
|
||||
export default async function GoogleSign(request) {
|
||||
const userGoogleId = request.params.Id;
|
||||
const userTokenId = request.params.TokenId;
|
||||
const userEmail = request.params.Gmail;
|
||||
const phone = request.params?.Phone || '';
|
||||
const name = request.params.Name;
|
||||
const extUserId = request.params?.extUserId || '';
|
||||
const authData = { google: { id: userGoogleId, id_token: userTokenId } };
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('email', userEmail);
|
||||
const res = await userQuery.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
if (extUserId) {
|
||||
const userQuery = new Parse.Query('contracts_Users');
|
||||
const resExtUser = await userQuery.get(extUserId, { useMasterKey: true });
|
||||
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||
try {
|
||||
const SignIn = await axios.put(
|
||||
serverUrl + '/users/' + res.id,
|
||||
{ authData: authData },
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Master-key': masterKEY,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (SignIn.data) {
|
||||
// console.log("google Sign in", SignIn);
|
||||
const sessiontoken = SignIn.data.sessionToken;
|
||||
return {
|
||||
email: userEmail,
|
||||
phone: _resExtUser?.Phone || '',
|
||||
company: _resExtUser?.Company,
|
||||
message: 'User Sign In',
|
||||
sessiontoken: sessiontoken,
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in user google sign in', err);
|
||||
return { message: 'Internal server error' };
|
||||
}
|
||||
} else {
|
||||
return { message: 'Internal server err' };
|
||||
}
|
||||
} else {
|
||||
// console.log("in sign up condition");
|
||||
try {
|
||||
const SignUp = await axios.post(
|
||||
serverUrl + '/users',
|
||||
{
|
||||
authData: authData,
|
||||
username: userEmail,
|
||||
email: userEmail,
|
||||
phone: phone,
|
||||
name: name,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Revocable-Session': '1',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// console.log("SignUp", SignUp);
|
||||
|
||||
if (SignUp.data) {
|
||||
const sessiontoken = SignUp.data.sessionToken;
|
||||
const payload = {
|
||||
email: userEmail,
|
||||
message: 'User Sign Up',
|
||||
sessiontoken: sessiontoken,
|
||||
};
|
||||
return payload;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in user google sign up', err);
|
||||
return { message: 'Internal server err' };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ export default async function Newsletter(request) {
|
||||
const email = request.params.email;
|
||||
const domain = request.params.domain;
|
||||
try {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': 'legadranaxn',
|
||||
};
|
||||
const envAppId = process.env.REACT_APP_APPID || 'legadranaxn';
|
||||
const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': envAppId };
|
||||
const envProdServer = process.env.REACT_APP_SERVERURL || 'https://app.opensignlabs.com/api/app';
|
||||
const newsletter = await axios.post(
|
||||
'https://app.opensignlabs.com/api/app/classes/Newsletter',
|
||||
`${envProdServer}/classes/Newsletter`,
|
||||
{ Name: name, Email: email, Domain: domain },
|
||||
{ headers: headers }
|
||||
);
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
import { replaceMailVaribles } from '../../Utils.js';
|
||||
|
||||
// `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');
|
||||
if (contact?.TenantId) {
|
||||
contactQuery.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: 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;
|
||||
}
|
||||
};
|
||||
|
||||
// `createDocumentFromTemplate` is used to create document from template
|
||||
const createDocumentFromTemplate = async (template, existContact, index) => {
|
||||
try {
|
||||
if (template) {
|
||||
//update contact in placeholder, signers and update ACl in provide document
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', template?.Name);
|
||||
object.set('Description', template?.Description);
|
||||
object.set('Note', template?.Note);
|
||||
object.set('TimeToCompleteDays', template?.TimeToCompleteDays || 15);
|
||||
object.set('SendinOrder', template?.SendinOrder || false);
|
||||
object.set('AutomaticReminders', template?.AutomaticReminders || false);
|
||||
object.set('RemindOnceInEvery', template?.RemindOnceInEvery || 5);
|
||||
object.set('URL', template?.URL);
|
||||
object.set('CreatedBy', template?.CreatedBy);
|
||||
object.set('ExtUserPtr', template?.ExtUserPtr);
|
||||
object.set('OriginIp', template?.OriginIp || '');
|
||||
object.set('IsEnableOTP', template?.IsEnableOTP || false);
|
||||
object.set('IsTourEnabled', template?.IsTourEnabled || false);
|
||||
object.set('FileAdapterId', template?.FileAdapterId || '');
|
||||
if (template?.SignatureType?.length > 0) {
|
||||
object.set('SignatureType', template?.SignatureType);
|
||||
}
|
||||
if (template?.NotifyOnSignatures) {
|
||||
object.set('NotifyOnSignatures', template?.NotifyOnSignatures);
|
||||
}
|
||||
let signers = template?.Signers || [];
|
||||
const signerobj = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: existContact.id,
|
||||
};
|
||||
signers = [...signers.slice(0, index), signerobj, ...signers.slice(index)];
|
||||
object.set('Signers', signers);
|
||||
object.set('SignedUrl', template.URL || template.SignedUrl);
|
||||
const Placeholders = template?.Placeholders || [];
|
||||
Placeholders[index] = {
|
||||
...Placeholders[index],
|
||||
signerObjId: existContact.id,
|
||||
signerPtr: {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: existContact.id,
|
||||
},
|
||||
};
|
||||
object.set('Placeholders', Placeholders);
|
||||
object.set('SendMail', true);
|
||||
const resDoc = await object.save(null, { useMasterKey: true });
|
||||
return resDoc;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in create document from template', err);
|
||||
}
|
||||
};
|
||||
|
||||
//`sendMailToAllSigners` is used to send email to all signers at a time if send-in-order false
|
||||
const sendMailToAllSigners = async docId => {
|
||||
try {
|
||||
//get document details that recenlty created from public template
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.include('ExtUserPtr,ExtUserPtr.TenantId');
|
||||
docQuery.include('Signers');
|
||||
const docRes = await docQuery.get(docId, { useMasterKey: true });
|
||||
const Doc = JSON.parse(JSON.stringify(docRes));
|
||||
const templateOwnerUserId = Doc?.CreatedBy?.objectId;
|
||||
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
|
||||
tenantCreditsQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: templateOwnerUserId,
|
||||
});
|
||||
const res = await tenantCreditsQuery.first();
|
||||
if (res) {
|
||||
const existUserId = Doc?.ExtUserPtr?.objectId;
|
||||
try {
|
||||
const getSubscriptionDetails = await Parse.Cloud.run('getsubscriptions', {
|
||||
extUserId: existUserId,
|
||||
ispublic: true,
|
||||
});
|
||||
if (getSubscriptionDetails) {
|
||||
const tenantRes = JSON.parse(JSON.stringify(res));
|
||||
const extUserDetails = Doc?.ExtUserPtr;
|
||||
const signerMail = Doc?.Signers;
|
||||
const requestBody = tenantRes?.RequestBody;
|
||||
const requestSubject = tenantRes?.RequestSubject;
|
||||
const subscription_json = JSON.parse(JSON.stringify(getSubscriptionDetails));
|
||||
const billingDate =
|
||||
subscription_json?.result?.Next_billing_date &&
|
||||
subscription_json?.result?.Next_billing_date?.iso;
|
||||
const isSubscribed = billingDate ? new Date(billingDate) > new Date() : false;
|
||||
for (let i = 0; i < signerMail.length; i++) {
|
||||
try {
|
||||
const senderEmail = Doc?.ExtUserPtr?.Email;
|
||||
const senderPhone = Doc?.ExtUserPtr?.Phone;
|
||||
const expireDate = Doc?.ExpiryDate?.iso || 15;
|
||||
const newDate = new Date(expireDate);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||
const objectId = signerMail[i].objectId;
|
||||
const hostPublicUrl = 'https://app.opensignlabs.com';
|
||||
|
||||
//encode this url value `${Doc.objectId}/${signerMail[i].Email}/${objectId}` to base64 using `btoa` function
|
||||
const encodeBase64 = btoa(`${Doc?.objectId}/${signerMail[i].Email}/${objectId}`);
|
||||
let signPdf = `${hostPublicUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl = 'https://www.opensignlabs.com/';
|
||||
const orgName = Doc?.ExtUserPtr?.Company || '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const senderName = `${Doc?.ExtUserPtr.Name}`;
|
||||
const documentName = `${Doc?.Name}`;
|
||||
let replaceVar;
|
||||
if (isSubscribed && requestBody && requestSubject) {
|
||||
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
||||
htmlReqBody =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||
replacedRequestBody +
|
||||
'</body> </html>';
|
||||
|
||||
const variables = {
|
||||
document_title: documentName,
|
||||
sender_name: senderName,
|
||||
sender_mail: senderEmail,
|
||||
sender_phone: senderPhone || '',
|
||||
receiver_name: signerMail[i].Name,
|
||||
receiver_email: signerMail[i].Email,
|
||||
receiver_phone: signerMail[i]?.Phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`,
|
||||
};
|
||||
replaceVar = replaceMailVaribles(requestSubject, htmlReqBody, variables);
|
||||
}
|
||||
let params = {
|
||||
mailProvider: extUserDetails?.activeMailAdapter,
|
||||
extUserId: existUserId,
|
||||
recipient: signerMail[i].Email,
|
||||
subject:
|
||||
replaceVar?.subject ||
|
||||
`${senderName} has requested you to sign "${documentName}"`,
|
||||
from: senderEmail,
|
||||
html:
|
||||
replaceVar?.body ||
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
Doc?.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
Doc?.Name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
senderEmail +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||
senderEmail +
|
||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= ' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>',
|
||||
};
|
||||
|
||||
await Parse.Cloud.run('sendmailv3', params);
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error in get partners_Tenant class details', err);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error in sendMailToAllSigners function', err);
|
||||
}
|
||||
};
|
||||
|
||||
const deductcount = async _resSub => {
|
||||
try {
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = _resSub.objectId;
|
||||
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||
const addonCredits = _resSub?.AddonCredits || 0;
|
||||
if (allowedCredits > 0) {
|
||||
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
await subscriptionCls.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('Err in deductcount in PublicUserLinkContacttoDoc cloud function', err);
|
||||
}
|
||||
};
|
||||
|
||||
// `PublicUserLinkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
|
||||
// create new document from template and save contact pointer in placeholder, signers and ACL of Document
|
||||
export default async function PublicUserLinkContactToDoc(req) {
|
||||
const email = req.params.email;
|
||||
const templateid = req.params.templateid;
|
||||
const signatureType = req.params.signatureType;
|
||||
const name = req.params.name;
|
||||
const phone = req.params.phone;
|
||||
const role = req.params.role;
|
||||
try {
|
||||
if (templateid) {
|
||||
// Execute the query to get the template with the specified 'templateid'
|
||||
const docQuery = new Parse.Query('contracts_Template');
|
||||
docQuery.include('ExtUserPtr');
|
||||
docQuery.include('ExtUserPtr.TenantId');
|
||||
const tempRes = await docQuery.get(templateid, { useMasterKey: true });
|
||||
// Check if the template was found; if not, throw an error indicating the template was not found
|
||||
if (!tempRes) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
||||
}
|
||||
const _tempRes = JSON.parse(JSON.stringify(tempRes));
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: _tempRes?.ExtUserPtr?.TenantId?.objectId,
|
||||
});
|
||||
subscription.include('ExtUserPtr');
|
||||
const date = new Date();
|
||||
subscription.greaterThanOrEqualTo('Next_billing_date', 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 (totalcredits > 0) {
|
||||
const Placeholders = _tempRes?.Placeholders || [];
|
||||
let index;
|
||||
if (role) {
|
||||
index = Placeholders?.findIndex(x => x.Role && x.Role === role);
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, '');
|
||||
}
|
||||
if (index !== -1) {
|
||||
// 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', _tempRes.CreatedBy);
|
||||
contactCls.notEqualTo('IsDeleted', true);
|
||||
const existContact = await contactCls.first({ useMasterKey: true });
|
||||
if (existContact) {
|
||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||
const _template_json = template_json;
|
||||
_template_json.SignatureType =
|
||||
signatureType?.length > 0 ? signatureType : _template_json?.SignatureType;
|
||||
//update contact in placeholder, signers and update ACl in provide document
|
||||
const docRes = await createDocumentFromTemplate(_template_json, existContact, index);
|
||||
if (docRes) {
|
||||
await deductcount(_resSub);
|
||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||
if (!template_json?.SendinOrder) {
|
||||
await sendMailToAllSigners(docRes.id);
|
||||
}
|
||||
return { contactId: existContact.id, docId: docRes.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: _tempRes.CreatedBy,
|
||||
TenantId: _tempRes.ExtUserPtr?.TenantId?.objectId,
|
||||
};
|
||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||
const _template_json = template_json;
|
||||
_template_json.SignatureType =
|
||||
signatureType?.length > 0 ? signatureType : _template_json?.SignatureType;
|
||||
// if user present on platform create contact on the basis of extended user details
|
||||
const contactRes = await saveRoleContact(contact);
|
||||
const docRes = await createDocumentFromTemplate(_template_json, contactRes, index);
|
||||
if (docRes) {
|
||||
await deductcount(_resSub);
|
||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||
if (!template_json?.SendinOrder) {
|
||||
await sendMailToAllSigners(docRes.id);
|
||||
}
|
||||
return { contactId: contactRes.id, docId: docRes.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: _tempRes.CreatedBy,
|
||||
TenantId: _tempRes.ExtUserPtr?.TenantId?.objectId,
|
||||
};
|
||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||
const _template_json = template_json;
|
||||
_template_json.SignatureType =
|
||||
signatureType?.length > 0 ? signatureType : _template_json?.SignatureType;
|
||||
// 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 docRes = await createDocumentFromTemplate(
|
||||
_template_json,
|
||||
contactRes,
|
||||
index
|
||||
);
|
||||
if (docRes) {
|
||||
await deductcount(_resSub);
|
||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||
if (!template_json?.SendinOrder) {
|
||||
await sendMailToAllSigners(docRes.id);
|
||||
}
|
||||
return { contactId: contactRes.id, docId: docRes.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);
|
||||
_user.set('password', email);
|
||||
if (phone) {
|
||||
_user.set('phone', phone);
|
||||
}
|
||||
const newUserRes = await _user.save();
|
||||
const contact = {
|
||||
UserId: { __type: 'Pointer', className: '_User', objectId: newUserRes.id },
|
||||
Name: name,
|
||||
Email: email,
|
||||
Phone: phone,
|
||||
CreatedBy: _tempRes.CreatedBy,
|
||||
TenantId: _tempRes.ExtUserPtr?.TenantId?.objectId,
|
||||
};
|
||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||
const _template_json = template_json;
|
||||
_template_json.SignatureType =
|
||||
signatureType?.length > 0 ? signatureType : _template_json?.SignatureType;
|
||||
// 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 docRes = await createDocumentFromTemplate(
|
||||
_template_json,
|
||||
contactRes,
|
||||
index
|
||||
);
|
||||
if (docRes) {
|
||||
await deductcount(_resSub);
|
||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||
if (!template_json?.SendinOrder) {
|
||||
await sendMailToAllSigners(docRes.id);
|
||||
}
|
||||
return { contactId: contactRes.id, docId: docRes.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.OBJECT_NOT_FOUND,
|
||||
'Please provide required parameters!'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.REQUEST_LIMIT_EXCEEDED, 'Insufficient Credit');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Plan expired');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in publicuserlinkcontacttodoc', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useLocal } from '../../Utils.js';
|
||||
import getPresignedUrl from './getSignedUrl.js';
|
||||
import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
|
||||
|
||||
async function SignatureAfterFind(request) {
|
||||
if (useLocal !== 'true') {
|
||||
@@ -17,6 +17,21 @@ async function SignatureAfterFind(request) {
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
} else if (useLocal == 'true') {
|
||||
if (request.objects.length === 1) {
|
||||
if (request.objects) {
|
||||
const obj = request.objects[0];
|
||||
const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
|
||||
const Initials = obj?.get('Initials') && obj?.get('Initials');
|
||||
if (ImageURL) {
|
||||
obj.set('ImageURL', presignedlocalUrl(ImageURL));
|
||||
}
|
||||
if (Initials) {
|
||||
obj.set('Initials', presignedlocalUrl(Initials));
|
||||
}
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default SignatureAfterFind;
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
export default async function SubscribeFree(request) {
|
||||
const userId = request.params.userId;
|
||||
const userPtr = { __type: 'Pointer', className: '_User', objectId: userId };
|
||||
try {
|
||||
const extQuery = new Parse.Query('contracts_Users');
|
||||
extQuery.equalTo('UserId', userPtr);
|
||||
const extUser = await extQuery.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||
subscriptionCls.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
subscriptionCls.descending('createdAt');
|
||||
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||
if (subcripitions) {
|
||||
if (subcripitions?.get('PlanCode') === 'freeplan') {
|
||||
return { status: 'success', result: 'already subscribed!' };
|
||||
} else if (subcripitions?.get('Next_billing_date') < new Date()) {
|
||||
try {
|
||||
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
updateSubscription.id = subcripitions.id;
|
||||
updateSubscription.set('PlanCode', 'freeplan');
|
||||
updateSubscription.set('AllowedCredits', 0);
|
||||
updateSubscription.set('PlanCredits', 0);
|
||||
await updateSubscription.save(null, { useMasterKey: true });
|
||||
return { status: 'success', result: 'subscribed!' };
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
} else if (subcripitions?.get('Next_billing_date') > new Date()) {
|
||||
return { status: 'success', result: 'already subscribed!' };
|
||||
} else {
|
||||
try {
|
||||
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
updateSubscription.id = subcripitions.id;
|
||||
updateSubscription.set('PlanCode', 'freeplan');
|
||||
updateSubscription.set('AllowedCredits', 0);
|
||||
updateSubscription.set('PlanCredits', 0);
|
||||
await updateSubscription.save(null, { useMasterKey: true });
|
||||
return { status: 'success', result: 'subscribed!' };
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
createSubscription.set('PlanCode', 'freeplan');
|
||||
createSubscription.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
createSubscription.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser.get('UserId').id,
|
||||
});
|
||||
if (extUser?.get('TenantId')) {
|
||||
createSubscription.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
}
|
||||
createSubscription.set('AllowedCredits', 0);
|
||||
createSubscription.set('PlanCredits', 0);
|
||||
await createSubscription.save(null, { useMasterKey: true });
|
||||
return { status: 'success', result: 'subscribed!' };
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'User not found!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
async function addTeamAndOrg(extUser) {
|
||||
try {
|
||||
const orgCls = new Parse.Object('contracts_Organizations');
|
||||
orgCls.set('Name', extUser.Company);
|
||||
orgCls.set('IsActive', true);
|
||||
orgCls.set('ExtUserId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser?.objectId,
|
||||
});
|
||||
orgCls.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser?.UserId?.objectId,
|
||||
});
|
||||
orgCls.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser?.TenantId?.objectId,
|
||||
});
|
||||
|
||||
const orgRes = await orgCls.save(null, { useMasterKey: true });
|
||||
const teamCls = new Parse.Object('contracts_Teams');
|
||||
teamCls.set('Name', 'All Users');
|
||||
teamCls.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
teamCls.set('IsActive', true);
|
||||
const teamRes = await teamCls.save(null, { useMasterKey: true });
|
||||
const updateUser = new Parse.Object('contracts_Users');
|
||||
updateUser.id = extUser.objectId;
|
||||
updateUser.set('UserRole', 'contracts_Admin');
|
||||
updateUser.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
updateUser.set('TeamIds', [
|
||||
{
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Teams',
|
||||
objectId: teamRes.id,
|
||||
},
|
||||
]);
|
||||
const extUserRes = await updateUser.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err in add team, role, org', err);
|
||||
}
|
||||
}
|
||||
|
||||
export default async function SubscriptionAftersave(request) {
|
||||
const oldObj = request.original;
|
||||
if (!oldObj) {
|
||||
try {
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.include('CreatedBy');
|
||||
const res = await subscription.get(request.object.id, { useMasterKey: true });
|
||||
const _res = JSON.parse(JSON.stringify(res));
|
||||
const user = _res.CreatedBy?.email;
|
||||
if (user) {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', user);
|
||||
const extUserRes = await extUserQuery.first({ useMasterKey: true });
|
||||
if (extUserRes) {
|
||||
const extUser = JSON.parse(JSON.stringify(extUserRes));
|
||||
if (!extUser?.OrganizationId) {
|
||||
await addTeamAndOrg(extUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in subscriptionaftersave', err);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||
subscription.include('CreatedBy');
|
||||
const res = await subscription.get(request.object.id, { useMasterKey: true });
|
||||
const _res = JSON.parse(JSON.stringify(res));
|
||||
const user = _res.CreatedBy?.email;
|
||||
if (user) {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', user);
|
||||
const extUserRes = await extUserQuery.first({ useMasterKey: true });
|
||||
if (extUserRes) {
|
||||
const extUser = JSON.parse(JSON.stringify(extUserRes));
|
||||
if (!extUser?.OrganizationId) {
|
||||
await addTeamAndOrg(extUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in subscriptionaftersave', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,53 @@
|
||||
import { useLocal } from '../../Utils.js';
|
||||
import getPresignedUrl from './getSignedUrl.js';
|
||||
import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
|
||||
|
||||
async function TemplateAfterFind(request) {
|
||||
if (request.objects.length === 1) {
|
||||
if (request.objects) {
|
||||
const obj = request.objects[0];
|
||||
const FileAdapterId = obj?.get('FileAdapterId') || '';
|
||||
if (FileAdapterId || useLocal !== 'true') {
|
||||
if (
|
||||
useLocal !== 'true'
|
||||
) {
|
||||
const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
|
||||
const Url = obj?.get('URL') && obj?.get('URL');
|
||||
const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
|
||||
let fileAdapter = {};
|
||||
if (FileAdapterId) {
|
||||
const tenantId = obj?.get('ExtUserPtr')?.get('TenantId');
|
||||
if (tenantId) {
|
||||
const _tenantId = JSON.parse(JSON.stringify(obj?.get('ExtUserPtr')?.get('TenantId')));
|
||||
fileAdapter = _tenantId?.FileAdapters?.find(x => x.id === FileAdapterId) || {};
|
||||
}
|
||||
}
|
||||
if (SignedUrl) {
|
||||
obj.set('SignedUrl', getPresignedUrl(SignedUrl, fileAdapter));
|
||||
obj.set(
|
||||
'SignedUrl',
|
||||
getPresignedUrl(
|
||||
SignedUrl,
|
||||
)
|
||||
);
|
||||
}
|
||||
if (Url) {
|
||||
obj.set('URL', getPresignedUrl(Url, fileAdapter));
|
||||
obj.set(
|
||||
'URL',
|
||||
getPresignedUrl(
|
||||
Url,
|
||||
)
|
||||
);
|
||||
}
|
||||
if (certificateUrl) {
|
||||
obj.set('CertificateUrl', getPresignedUrl(certificateUrl, fileAdapter));
|
||||
obj.set(
|
||||
'CertificateUrl',
|
||||
getPresignedUrl(
|
||||
certificateUrl,
|
||||
)
|
||||
);
|
||||
}
|
||||
return [obj];
|
||||
} else if (useLocal == 'true') {
|
||||
const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
|
||||
const Url = obj?.get('URL') && obj?.get('URL');
|
||||
const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
|
||||
if (SignedUrl) {
|
||||
obj.set('SignedUrl', presignedlocalUrl(SignedUrl));
|
||||
}
|
||||
if (Url) {
|
||||
obj.set('URL', presignedlocalUrl(Url));
|
||||
}
|
||||
if (certificateUrl) {
|
||||
obj.set('CertificateUrl', presignedlocalUrl(certificateUrl));
|
||||
}
|
||||
return [obj];
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@ export default async function TemplateAfterSave(request) {
|
||||
const signers = request.object.get('Signers');
|
||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
||||
const ip = request?.headers?.['x-real-ip'] || '';
|
||||
const originIp = request?.object?.get('OriginIp') || '';
|
||||
if (AutoReminder) {
|
||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
||||
const ReminderDate = new Date(request?.object?.get('createdAt'));
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
request.object.set('NextReminderDate', ReminderDate);
|
||||
}
|
||||
request.object.set('OriginIp', ip);
|
||||
if (!originIp) {
|
||||
request.object.set('OriginIp', ip);
|
||||
}
|
||||
await request.object.save(null, { useMasterKey: true });
|
||||
if (signers && signers.length > 0) {
|
||||
await updateAclDoc(request.object.id);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useLocal } from '../../Utils.js';
|
||||
import getPresignedUrl from './getSignedUrl.js';
|
||||
import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
|
||||
|
||||
async function TenantAterFind(request) {
|
||||
if (useLocal !== 'true') {
|
||||
@@ -13,6 +13,17 @@ async function TenantAterFind(request) {
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
} else if (useLocal == 'true') {
|
||||
if (request.objects.length === 1) {
|
||||
if (request.objects) {
|
||||
const obj = request.objects[0];
|
||||
const Logo = obj?.get('Logo') && obj?.get('Logo');
|
||||
if (Logo) {
|
||||
obj.set('Logo', presignedlocalUrl(Logo));
|
||||
}
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default TenantAterFind;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useLocal } from '../../Utils.js';
|
||||
import getPresignedUrl from './getSignedUrl.js';
|
||||
import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
|
||||
|
||||
async function UserAfterFind(request) {
|
||||
if (useLocal !== 'true') {
|
||||
@@ -13,6 +13,17 @@ async function UserAfterFind(request) {
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
} else if (useLocal == 'true') {
|
||||
if (request.objects.length === 1) {
|
||||
if (request.objects) {
|
||||
const obj = request.objects[0];
|
||||
const ProfilePic = obj?.get('ProfilePic') && obj?.get('ProfilePic');
|
||||
if (ProfilePic) {
|
||||
obj.set('ProfilePic', presignedlocalUrl(ProfilePic));
|
||||
}
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default UserAfterFind;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
* ZohoDetails function
|
||||
* @param hostedpagesId Id must be in String
|
||||
* @returns response {phone, name, email, nextBillingDate, company, plan, customer_id, subscription_id}
|
||||
*/
|
||||
|
||||
export default async function ZohoDetails(request) {
|
||||
// Define the URL
|
||||
const url = 'https://accounts.zoho.in/oauth/v2/token';
|
||||
|
||||
// Convert the data to x-www-form-urlencoded format
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
|
||||
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
|
||||
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
|
||||
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
|
||||
formData.append('grant_type', 'refresh_token');
|
||||
|
||||
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||
// Make the POST request using Axios
|
||||
const res = await axios.post(url, formData, { headers });
|
||||
// console.log("Access Token:", res.data);
|
||||
if (res.data.access_token) {
|
||||
const hostedpages = request.params.hostedpagesId;
|
||||
const userData = await axios.get(
|
||||
'https://www.zohoapis.in/billing/v1/hostedpages/' + hostedpages,
|
||||
{
|
||||
headers: {
|
||||
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const first_name = userData.data.data.subscription.contactpersons[0].first_name || '';
|
||||
const last_name = userData.data.data.subscription.contactpersons[0].last_name || '';
|
||||
const company_name =
|
||||
(userData.data.data.subscription.customer &&
|
||||
userData.data.data.subscription.customer.company_name) ||
|
||||
'';
|
||||
const jobTitle =
|
||||
(userData.data.data.subscription.customer &&
|
||||
userData.data.data.subscription.customer.cd_job_title) ||
|
||||
'';
|
||||
const resData = {
|
||||
phone: userData.data.data.subscription.contactpersons[0]?.mobile || '',
|
||||
name: first_name + ' ' + last_name,
|
||||
email: userData.data.data.subscription.contactpersons[0].email,
|
||||
nextBillingDate: userData.data.data.subscription.next_billing_at,
|
||||
company: company_name,
|
||||
plan: userData.data.data.subscription.plan,
|
||||
customer_id: userData.data.data.subscription.customer_id,
|
||||
subscription_id: userData.data.data.subscription.subscription_id,
|
||||
jobTitle: jobTitle,
|
||||
subscription: userData.data,
|
||||
};
|
||||
return resData;
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
// `generateId` is used to unique Id for fileAdapter
|
||||
function generateId(length) {
|
||||
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// `getExtUser` get ext user details
|
||||
async function getExtUser(request) {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', request.user);
|
||||
extUserCls.include('TenantId');
|
||||
return await extUserCls.first({ useMasterKey: true });
|
||||
}
|
||||
|
||||
// `saveTenant` save file adapter details in tenant class
|
||||
async function saveTenant(tenantId, fileAdapters, activeAdapter) {
|
||||
const tenantCls = new Parse.Object('partners_Tenant');
|
||||
tenantCls.id = tenantId;
|
||||
if (fileAdapters?.length > 0) {
|
||||
tenantCls.set('FileAdapters', fileAdapters);
|
||||
}
|
||||
if (activeAdapter) {
|
||||
tenantCls.set('ActiveFileAdapter', activeAdapter);
|
||||
} else {
|
||||
tenantCls.unset('ActiveFileAdapter');
|
||||
}
|
||||
return await tenantCls.save(null, { useMasterKey: true });
|
||||
}
|
||||
|
||||
// `updateTenantSchema` is used add FileAdapter in protected fields
|
||||
async function updateTenantSchema() {
|
||||
const tenantSchema = new Parse.Schema('partners_Tenant');
|
||||
const currentSchema = await tenantSchema.get();
|
||||
let clp = currentSchema.classLevelPermissions;
|
||||
// Public permission ("*")
|
||||
const role = '*';
|
||||
if (!clp.protectedFields || Object.keys(clp.protectedFields).length === 0) {
|
||||
// Initialize protectedFields if it doesn't exist
|
||||
clp.protectedFields = { [role]: [] };
|
||||
}
|
||||
// save FileAdapters field is in protectedFields if not exists
|
||||
if (!clp.protectedFields[role]?.includes('FileAdapters')) {
|
||||
clp.protectedFields[role].push('FileAdapters');
|
||||
// Update the class schema with the modified CLP
|
||||
tenantSchema.setCLP(clp);
|
||||
await tenantSchema.update();
|
||||
}
|
||||
}
|
||||
|
||||
export default async function addFileAdapter(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
const fileAdapterName = request.params.fileAdapterName;
|
||||
const bucketName = request.params.bucketName;
|
||||
const region = request.params.region;
|
||||
const endpoint = request.params.endpoint;
|
||||
const baseUrl = request.params.baseUrl;
|
||||
const accessKeyId = request.params.accessKeyId;
|
||||
const secretAccessKey = request.params.secretAccessKey;
|
||||
const adapter = request.params.fileAdapter;
|
||||
|
||||
if (fileAdapterName && accessKeyId && secretAccessKey && adapter) {
|
||||
try {
|
||||
const extUser = await getExtUser(request);
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
const tenantId = extUser?.get('TenantId')?.id;
|
||||
// assign existing file adapters or empty array
|
||||
let fileAdapters = _extUser?.TenantId?.FileAdapters || [];
|
||||
const uniqueId = generateId(10);
|
||||
let id = extUser?.get('TenantId')?.id + '_' + uniqueId;
|
||||
const index = fileAdapters?.findIndex(x => x.fileAdapterName === fileAdapterName);
|
||||
if (index !== -1) {
|
||||
// If an object with the same fileAdapterName exists, update it
|
||||
if (bucketName || region || endpoint || baseUrl) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'Cannot update bucketName, region, endpoint, baseUrl.'
|
||||
);
|
||||
} else {
|
||||
const adapterConfig = { accessKeyId: accessKeyId, secretAccessKey: secretAccessKey };
|
||||
fileAdapters[index] = { ...fileAdapters[index], ...adapterConfig };
|
||||
id = fileAdapters[index].id;
|
||||
}
|
||||
} else {
|
||||
if (bucketName && region && endpoint && baseUrl) {
|
||||
// If the object with the given fileAdapterName doesn't exist, add a new one
|
||||
fileAdapters.push({
|
||||
id: id,
|
||||
fileAdapterName: fileAdapterName,
|
||||
fileAdapter: adapter,
|
||||
bucketName: bucketName,
|
||||
region: region,
|
||||
endpoint: endpoint,
|
||||
baseUrl: baseUrl,
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: secretAccessKey,
|
||||
});
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.');
|
||||
}
|
||||
}
|
||||
const updateTenant = await saveTenant(tenantId, fileAdapters, id);
|
||||
await updateTenantSchema();
|
||||
const ActiveFileAdapter = adapter === 'opensign' ? 'opensign' : id;
|
||||
return { ActiveFileAdapter: ActiveFileAdapter, updateAt: updateTenant.updatedAt };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in add custom file adapter', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else if (adapter === 'opensign') {
|
||||
try {
|
||||
const extUser = await getExtUser(request);
|
||||
if (extUser) {
|
||||
const tenantId = extUser?.get('TenantId')?.id;
|
||||
const updateTenant = await saveTenant(tenantId);
|
||||
await updateTenantSchema();
|
||||
return { ActiveFileAdapter: 'opensign', updateAt: updateTenant.updatedAt };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in add custom file adapter', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.');
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
export default async function addOrganization(request) {
|
||||
const name = request.params.name;
|
||||
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
extUserQuery.notEqualTo('IsDisabled', true);
|
||||
const resExt = await extUserQuery.first({ useMasterKey: true });
|
||||
if (!resExt) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
const _resExt = JSON.parse(JSON.stringify(resExt));
|
||||
|
||||
const orgQuery = new Parse.Query('contracts_Organizations');
|
||||
orgQuery.equalTo('Name', name);
|
||||
orgQuery.equalTo('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
const resOrg = await orgQuery.first({ useMasterKey: true });
|
||||
if (resOrg) {
|
||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Organization already exists.');
|
||||
} else {
|
||||
const newOrg = new Parse.Object('contracts_Organizations');
|
||||
newOrg.set('Name', name);
|
||||
newOrg.set('IsActive', true);
|
||||
newOrg.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
newOrg.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: _resExt.TenantId.objectId,
|
||||
});
|
||||
newOrg.set('ExtUserId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: resExt.id,
|
||||
});
|
||||
const newResOrg = await newOrg.save(null, { useMasterKey: true });
|
||||
const teamCls = new Parse.Object('contracts_Teams');
|
||||
teamCls.set('Name', 'All Users');
|
||||
teamCls.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: newResOrg.id,
|
||||
});
|
||||
teamCls.set('IsActive', true);
|
||||
await teamCls.save(null, { useMasterKey: true });
|
||||
if (newResOrg) {
|
||||
return newResOrg;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in addorganization', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// `updateTenantSchema` is used add FileAdapter in protected fields
|
||||
async function updateTenantSchema() {
|
||||
const tenantSchema = new Parse.Schema('partners_Tenant');
|
||||
const currentSchema = await tenantSchema.get();
|
||||
let clp = currentSchema.classLevelPermissions;
|
||||
// Public permission ("*")
|
||||
const role = '*';
|
||||
if (!clp.protectedFields || Object.keys(clp.protectedFields).length === 0) {
|
||||
// Initialize protectedFields if it doesn't exist
|
||||
clp.protectedFields = { [role]: [] };
|
||||
}
|
||||
// save PfxFile field is in protectedFields if not exists
|
||||
if (!clp.protectedFields[role]?.includes('PfxFile')) {
|
||||
clp.protectedFields[role].push('PfxFile');
|
||||
// Update the class schema with the modified CLP
|
||||
tenantSchema.setCLP(clp);
|
||||
await tenantSchema.update();
|
||||
}
|
||||
}
|
||||
|
||||
export default async function addPfxFile(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
const pfxBase64 = request.params.pfxBase64;
|
||||
const title = request.params.title;
|
||||
const password = request.params.password;
|
||||
const provider = request.params.provider;
|
||||
if (provider === 'opensign' || (pfxBase64 && password)) {
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', request.user);
|
||||
extUserCls.include('TenantId');
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const tenantCls = new Parse.Object('partners_Tenant');
|
||||
tenantCls.id = extUser?.get('TenantId')?.id;
|
||||
if (provider === 'opensign') {
|
||||
tenantCls.unset('PfxFile');
|
||||
} else {
|
||||
tenantCls.set('PfxFile', { title: title, password: password, base64: pfxBase64 });
|
||||
}
|
||||
const updateTenant = await tenantCls.save(null, { useMasterKey: true });
|
||||
await updateTenantSchema();
|
||||
return { updateAt: updateTenant.updatedAt };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in add custom file adapter', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.');
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
export default async function addTeam(request) {
|
||||
const Name = request.params.Name;
|
||||
const ParentId = request.params.ParentId;
|
||||
const Ancestors = request.params.Ancestors;
|
||||
const ParentPtr = { __type: 'Pointer', className: 'contracts_Teams', objectId: ParentId };
|
||||
if (Name) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
extUserQuery.notEqualTo('IsDisabled', true);
|
||||
const resExt = await extUserQuery.first({ useMasterKey: true });
|
||||
const extUser = JSON.parse(JSON.stringify(resExt));
|
||||
if (!extUser) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
const teamCls = new Parse.Query('contracts_Teams');
|
||||
teamCls.equalTo('Name', Name);
|
||||
teamCls.equalTo('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: extUser.OrganizationId.objectId,
|
||||
});
|
||||
if (ParentId) {
|
||||
teamCls.equalTo('ParentId', ParentPtr);
|
||||
}
|
||||
const teamRes = await teamCls.first({ useMasterKey: true });
|
||||
if (teamRes) {
|
||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Team already exists.');
|
||||
} else {
|
||||
const newteam = new Parse.Object('contracts_Teams');
|
||||
newteam.set('Name', Name);
|
||||
newteam.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: extUser.OrganizationId.objectId,
|
||||
});
|
||||
if (ParentId) {
|
||||
newteam.set('ParentId', ParentPtr);
|
||||
}
|
||||
if (Ancestors && Ancestors.length > 0) {
|
||||
newteam.set('Ancestors', Ancestors);
|
||||
}
|
||||
newteam.set('IsActive', true);
|
||||
const newTeamRes = await newteam.save(null, { useMasterKey: true });
|
||||
return newTeamRes;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getOrganizations', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters');
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
export default async function addcustomsmtp(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
const host = request.params.host;
|
||||
const port = request.params.port;
|
||||
const username = request.params.username;
|
||||
const password = request.params.password;
|
||||
if (host && port && username && password) {
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', request.user);
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const extUserCls = new Parse.Object('contracts_Users');
|
||||
extUserCls.id = extUser.id;
|
||||
extUserCls.set('SmtpConfig', { host, port, username, password });
|
||||
extUserCls.set('active_mail_adapter', 'smtp');
|
||||
const updateExtUser = await extUserCls.save(null, { useMasterKey: true });
|
||||
// console.log('updateExtUser ', updateExtUser);
|
||||
return updateExtUser.updatedAt;
|
||||
}
|
||||
return extUser;
|
||||
} catch (err) {
|
||||
console.log('Err in add custom smtp', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide all parameters.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
const appId = process.env.APP_ID;
|
||||
const masterkey = process.env.MASTER_KEY;
|
||||
export default async function createBatchContact(req) {
|
||||
if (!req?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
if (!req.params?.contacts) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameter.');
|
||||
}
|
||||
const contactData = JSON.parse(req.params.contacts);
|
||||
if (contactData?.length > 0) {
|
||||
try {
|
||||
const requests = contactData.map(x => {
|
||||
return {
|
||||
method: 'POST',
|
||||
path: '/app/classes/contracts_Contactbook',
|
||||
body: {
|
||||
UserRole: 'contracts_Guest',
|
||||
TenantId: { __type: 'Pointer', className: 'partners_Tenant', objectId: x.TenantId },
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: req.user.id },
|
||||
Name: x.Name,
|
||||
Email: x.Email,
|
||||
IsDeleted: false,
|
||||
IsImported: true,
|
||||
...(x?.Phone ? { Phone: `${x?.Phone}` } : {}),
|
||||
ACL: { [req.user.id]: { read: true, write: true } },
|
||||
},
|
||||
};
|
||||
});
|
||||
const parseConfig = {
|
||||
baseURL: cloudServerUrl,
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': masterkey,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
const response = await axios.post('batch', { requests: requests }, parseConfig);
|
||||
// Handle the batch query response
|
||||
// console.info('createbatchcontact ', response.data);
|
||||
const successCount = response?.data?.filter(item => item.success).length;
|
||||
const failedCount = requests.length - successCount;
|
||||
console.log(
|
||||
`createbatchcontact query response: success: ${successCount}, failed: ${failedCount}`
|
||||
);
|
||||
return { success: successCount, failed: failedCount };
|
||||
} catch (err) {
|
||||
console.log('err while create batch contact', err);
|
||||
throw new Parse.Error(400, 'Something went wrong, please try again later');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_CONTENT_LENGTH, 'Please provide parameter');
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,15 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import {
|
||||
cloudServerUrl,
|
||||
replaceMailVaribles,
|
||||
} from '../../Utils.js';
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
const licenseKey = process.env.LICENSE_KEY;
|
||||
async function deductcount(docsCount, extUserId, subscription) {
|
||||
async function deductcount(
|
||||
docsCount,
|
||||
extUserId,
|
||||
) {
|
||||
try {
|
||||
if (licenseKey) {
|
||||
const allowedCredits = subscription?.AllowedCredits || 0;
|
||||
const addonCredits = subscription?.AddonCredits || 0;
|
||||
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||
subscriptionCls.id = subscription.objectId;
|
||||
if (docsCount <= allowedCredits) {
|
||||
const updateAllowedcredits = allowedCredits - docsCount;
|
||||
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||
} else {
|
||||
const remaingCount = docsCount - allowedCredits;
|
||||
const updateAddonCredits = addonCredits - remaingCount;
|
||||
subscriptionCls.set('AllowedCredits', 0);
|
||||
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||
}
|
||||
await subscriptionCls.save(null, { useMasterKey: true });
|
||||
}
|
||||
const extCls = new Parse.Object('contracts_Users');
|
||||
extCls.id = extUserId;
|
||||
extCls.increment('DocumentCount', docsCount);
|
||||
@@ -55,11 +43,7 @@ async function sendMail(document) {
|
||||
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 headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': appId };
|
||||
const objectId = signerMail[i]?.signerObjId;
|
||||
const hostUrl = baseUrl.origin;
|
||||
let encodeBase64;
|
||||
@@ -74,35 +58,67 @@ async function sendMail(document) {
|
||||
const openSignUrl = 'https://www.opensignlabs.com/';
|
||||
const orgName = document.ExtUserPtr.Company ? document.ExtUserPtr.Company : '';
|
||||
const themeBGcolor = '#47a3ad';
|
||||
const senderObj = document?.ExtUserPtr;
|
||||
const mailBody = document?.ExtUserPtr?.TenantId?.RequestBody || '';
|
||||
const mailSubject = document?.ExtUserPtr?.TenantId?.RequestSubject || '';
|
||||
let replaceVar;
|
||||
if (mailBody && mailSubject) {
|
||||
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
||||
const htmlReqBody =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||
replacedRequestBody +
|
||||
'</body></html>';
|
||||
const variables = {
|
||||
document_title: document?.Name,
|
||||
sender_name:
|
||||
senderObj?.Name,
|
||||
sender_mail:
|
||||
senderObj?.Email,
|
||||
sender_phone: senderObj?.Phone || '',
|
||||
receiver_name: existSigner?.Name || '',
|
||||
receiver_email: existSigner?.Email || signerMail[i].email,
|
||||
receiver_phone: existSigner?.Phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: orgName,
|
||||
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`,
|
||||
};
|
||||
replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables);
|
||||
}
|
||||
|
||||
let params = {
|
||||
mailProvider: document?.ExtUserPtr?.active_mail_adapter || '',
|
||||
extUserId: document.ExtUserPtr.objectId,
|
||||
recipient: objectId ? existSigner?.Email : signerMail[i].email,
|
||||
subject: `${document.ExtUserPtr.Name} has requested you to sign "${document.Name}"`,
|
||||
mailProvider: document?.ExtUserPtr?.active_mail_adapter || '',
|
||||
from: sender,
|
||||
html:
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
|
||||
imgPng +
|
||||
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||
document.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
document.Name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a target=_blank href=" +
|
||||
signPdf +
|
||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> 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™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p> </div></div></body> </html>',
|
||||
subject: replaceVar?.subject
|
||||
? replaceVar?.subject
|
||||
: `${document.ExtUserPtr.Name} has requested you to sign "${document.Name}"`,
|
||||
from:
|
||||
sender,
|
||||
replyto:
|
||||
sender ||
|
||||
'',
|
||||
html: replaceVar?.body
|
||||
? replaceVar?.body
|
||||
: "<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px;'><div style='box-shadow:rgba(0, 0, 0, 0.1) 0px 4px 12px;background:white;padding-bottom:20px;'><div style='padding:10px 10px 0 10px'><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding:20px;width:170px;height:40px;' /></div><div style='padding:2px;font-family:system-ui;background-color:" +
|
||||
themeBGcolor +
|
||||
";'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px;' > Digital Signature Request</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px;margin-bottom:10px;'> " +
|
||||
document.ExtUserPtr.Name +
|
||||
' has requested you to review and sign <strong> ' +
|
||||
document.Name +
|
||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display:flex;flex-direction:row;justify-content:space-around;'><table><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
sender +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td><td></td><td style='color:#626363;font-weight:bold'> " +
|
||||
orgName +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
localExpireDate +
|
||||
"</td></tr><tr><td></td><td></td></tr></table></div><div style='margin-left:70px;'><a target=_blank href=" +
|
||||
signPdf +
|
||||
"><button style='padding:12px 12px 12px 12px;background-color:#d46b0f;color:white;border:0px;box-shadow:rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a></div><div style='display:flex;justify-content:center;margin-top:10px;'></div></div></div><div><p> 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™ <a href=' +
|
||||
openSignUrl +
|
||||
' target=_blank>here</a>.</p></div></div></body></html>',
|
||||
};
|
||||
const sendMail = await axios.post(url, params, { headers: headers });
|
||||
// if (sendMail.data.result.status === 'success') {
|
||||
@@ -113,75 +129,13 @@ async function sendMail(document) {
|
||||
}
|
||||
}
|
||||
}
|
||||
async function callwebhookevent(document) {
|
||||
const Signers = document.Signers;
|
||||
const allSigner = document?.Placeholders?.map(item => {
|
||||
if (item.signerObjId) {
|
||||
const signer = Signers?.find(e => item?.signerPtr?.objectId === e?.objectId);
|
||||
if (signer) {
|
||||
return {
|
||||
role: item?.Role || '',
|
||||
name: signer?.Name || '',
|
||||
email: signer?.Email || '',
|
||||
phone: signer?.Phone || '',
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return { role: item?.Role || '', name: '', email: item?.email || '', phone: '' };
|
||||
}
|
||||
});
|
||||
const params = {
|
||||
event: 'created',
|
||||
body: {
|
||||
objectId: document?.objectId,
|
||||
file: document?.SignedUrl || document?.URL,
|
||||
name: document?.Name,
|
||||
note: document?.Note || '',
|
||||
description: document?.Description || '',
|
||||
signers: allSigner,
|
||||
createdBy: document?.ExtUserPtr.Email,
|
||||
createdAt: document?.createdAt,
|
||||
},
|
||||
};
|
||||
try {
|
||||
await axios
|
||||
.post(document?.ExtUserPtr?.Webhook, params, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
.then(res => {
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: document.CreatedBy.objectId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err?.message);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: document.CreatedBy.objectId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err?.message);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('Err ', err?.message);
|
||||
}
|
||||
}
|
||||
async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
async function batchQuery(
|
||||
userId,
|
||||
Documents,
|
||||
Ip,
|
||||
parseConfig,
|
||||
type
|
||||
) {
|
||||
const extCls = new Parse.Query('contracts_Users');
|
||||
extCls.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
@@ -202,10 +156,14 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
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 };
|
||||
if (x?.CreatedBy?.objectId) {
|
||||
const obj = { [x.CreatedBy.objectId]: { read: true, write: true } };
|
||||
Acl = { ...Acl, ...obj };
|
||||
}
|
||||
});
|
||||
}
|
||||
const mailBody = x?.ExtUserPtr?.TenantId?.RequestBody || '';
|
||||
const mailSubject = x?.ExtUserPtr?.TenantId?.RequestSubject || '';
|
||||
return {
|
||||
method: 'POST',
|
||||
path: '/app/classes/contracts_Document',
|
||||
@@ -231,8 +189,9 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
objectId: y.signerPtr.objectId,
|
||||
},
|
||||
signerObjId: y.signerObjId,
|
||||
email: y?.signerPtr?.Email || y?.email || '',
|
||||
}
|
||||
: { ...y, signerPtr: {}, signerObjId: '' }
|
||||
: { ...y, signerPtr: {}, signerObjId: '', email: y.email || '' }
|
||||
),
|
||||
SignedUrl: x.URL || x.SignedUrl,
|
||||
SentToOthers: true,
|
||||
@@ -250,55 +209,17 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
DocSentAt: { __type: 'Date', iso: isoDate },
|
||||
IsEnableOTP: x?.IsEnableOTP || false,
|
||||
IsTourEnabled: x?.IsTourEnabled || false,
|
||||
FileAdapterId: x?.FileAdapterId || '',
|
||||
AllowModifications: x?.AllowModifications || false,
|
||||
...(x?.SignatureType ? { SignatureType: x?.SignatureType } : {}),
|
||||
...(x?.NotifyOnSignatures ? { NotifyOnSignatures: x?.NotifyOnSignatures } : {}),
|
||||
...(x?.Bcc?.length > 0 ? { Bcc: x?.Bcc } : {}),
|
||||
...(x?.RedirectUrl ? { RedirectUrl: x?.RedirectUrl } : {}),
|
||||
...(mailBody ? { RequestBody: mailBody } : {}),
|
||||
...(mailSubject ? { RequestSubject: mailSubject } : {}),
|
||||
},
|
||||
};
|
||||
});
|
||||
// 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
|
||||
}
|
||||
callwebhookevent(Documents[0]);
|
||||
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);
|
||||
@@ -313,10 +234,8 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
};
|
||||
deductcount(response.data.length, resExt.id);
|
||||
sendMail(updateDocuments); //sessionToken
|
||||
callwebhookevent(Documents[0]);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const code = error?.response?.data?.code || error?.response?.status || error?.code || 400;
|
||||
@@ -335,7 +254,7 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
export default async function createBatchDocs(request) {
|
||||
const strDocuments = request.params.Documents;
|
||||
const sessionToken = request.headers?.sessiontoken;
|
||||
const jwttoken = request.headers?.jwttoken;
|
||||
const type = request.headers?.type || 'quicksend';
|
||||
const Documents = JSON.parse(strDocuments);
|
||||
const Ip = request?.headers?.['x-real-ip'] || '';
|
||||
const parseConfig = {
|
||||
@@ -348,31 +267,9 @@ export default async function createBatchDocs(request) {
|
||||
};
|
||||
try {
|
||||
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 {
|
||||
return await batchQuery(request.user.id, Documents, Ip, parseConfig, '', type);
|
||||
}
|
||||
else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
export default async function createDuplicate(request) {
|
||||
const templateId = request.params.templateId;
|
||||
|
||||
if (!request.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
|
||||
if (templateId) {
|
||||
try {
|
||||
const templateQuery = new Parse.Query('contracts_Template');
|
||||
templateQuery.equalTo('objectId', templateId);
|
||||
templateQuery.equalTo('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
templateQuery.notEqualTo('IsArchive', true);
|
||||
const templateRes = await templateQuery.first({ useMasterKey: true });
|
||||
if (templateRes?.id) {
|
||||
const _templateRes = JSON.parse(JSON.stringify(templateRes));
|
||||
const newTemplate = new Parse.Object('contracts_Template');
|
||||
|
||||
let signers = [];
|
||||
if (_templateRes.Signers?.length > 0) {
|
||||
_templateRes.Signers?.forEach(x => {
|
||||
if (x.objectId) {
|
||||
const obj = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: x.objectId,
|
||||
};
|
||||
signers.push(obj);
|
||||
}
|
||||
});
|
||||
}
|
||||
newTemplate.set('Name', _templateRes.Name);
|
||||
newTemplate.set('URL', _templateRes.URL);
|
||||
newTemplate.set('SignedUrl', _templateRes.SignedUrl);
|
||||
newTemplate.set('SentToOthers', _templateRes?.SentToOthers || false);
|
||||
newTemplate.set('SendinOrder', _templateRes?.SendinOrder || false);
|
||||
newTemplate.set('AutomaticReminders', _templateRes?.AutomaticReminders || false);
|
||||
newTemplate.set('RemindOnceInEvery', _templateRes?.RemindOnceInEvery || 5);
|
||||
newTemplate.set('IsEnableOTP', _templateRes?.IsEnableOTP || false);
|
||||
newTemplate.set('AllowModifications', _templateRes?.AllowModifications || false);
|
||||
newTemplate.set('Signers', signers);
|
||||
newTemplate.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: _templateRes.ExtUserPtr.objectId,
|
||||
});
|
||||
newTemplate.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: _templateRes.CreatedBy.objectId,
|
||||
});
|
||||
if (_templateRes?.Note) {
|
||||
newTemplate.set('Note', _templateRes?.Note);
|
||||
}
|
||||
if (_templateRes?.Description) {
|
||||
newTemplate.set('Description', _templateRes?.Description);
|
||||
}
|
||||
if (_templateRes?.Placeholders?.length > 0) {
|
||||
newTemplate.set('Placeholders', _templateRes.Placeholders);
|
||||
}
|
||||
if (_templateRes?.SignatureType?.length > 0) {
|
||||
newTemplate.set('SignatureType', _templateRes?.SignatureType);
|
||||
}
|
||||
if (_templateRes?.NotifyOnSignatures !== undefined) {
|
||||
newTemplate.set('NotifyOnSignatures', _templateRes.NotifyOnSignatures);
|
||||
}
|
||||
if (_templateRes?.SharedWith?.length > 0) {
|
||||
newTemplate.set('SharedWith', _templateRes.SharedWith);
|
||||
}
|
||||
if (_templateRes?.IsPublic) {
|
||||
newTemplate.set('IsPublic', _templateRes?.IsPublic);
|
||||
}
|
||||
if (_templateRes?.PublicRole?.length > 0) {
|
||||
newTemplate.set('PublicRole', _templateRes?.PublicRole);
|
||||
}
|
||||
if (_templateRes?.IsTourEnabled) {
|
||||
newTemplate.set('IsTourEnabled', _templateRes?.IsTourEnabled);
|
||||
}
|
||||
if (_templateRes?.Bcc?.length) {
|
||||
newTemplate.set('Bcc', _templateRes?.Bcc);
|
||||
}
|
||||
const OriginIp = _templateRes?.OriginIp || request?.headers?.['x-real-ip'] || '';
|
||||
|
||||
if (OriginIp) {
|
||||
newTemplate.set('OriginIp', OriginIp);
|
||||
}
|
||||
if (_templateRes?.RedirectUrl) {
|
||||
newTemplate.set('RedirectUrl', _templateRes?.RedirectUrl);
|
||||
}
|
||||
const acl = templateRes.getACL();
|
||||
if (acl) {
|
||||
newTemplate.setACL(acl);
|
||||
}
|
||||
const newTemplateRes = await newTemplate.save(null, { useMasterKey: true });
|
||||
const _newTemplateRes = JSON.parse(JSON.stringify(newTemplateRes));
|
||||
return _newTemplateRes;
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'You cannot create duplicate of this template.'
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err while creating duplicate', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
export default async function deactivateMailAdapter(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', request.user);
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const extUserCls = new Parse.Object('contracts_Users');
|
||||
extUserCls.id = extUser.id;
|
||||
extUserCls.unset('active_mail_adapter');
|
||||
const updateExtUser = await extUserCls.save(null, { useMasterKey: true });
|
||||
// console.log('updateExtUser ', updateExtUser);
|
||||
return updateExtUser.updatedAt;
|
||||
}
|
||||
return extUser;
|
||||
} catch (err) {
|
||||
console.log('Err in add custom smtp', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
export default async function editContact(request) {
|
||||
const { contactId, name, email, phone, tenantId } = request.params;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
const createdBy = { __type: 'Pointer', className: '_User', objectId: request.user.id };
|
||||
try {
|
||||
const contact = new Parse.Object('contracts_Contactbook');
|
||||
contact.id = contactId;
|
||||
contact.set('IsDeleted', true);
|
||||
const contactRes = await contact.save(null, {
|
||||
sessionToken: request?.user.getSessionToken(),
|
||||
});
|
||||
if (contactRes) {
|
||||
const query = new Parse.Query('contracts_Contactbook');
|
||||
query.equalTo('CreatedBy', createdBy);
|
||||
query.notEqualTo('IsDeleted', true);
|
||||
query.equalTo('Email', email);
|
||||
const isContactExist = await query.first({ useMasterKey: true });
|
||||
if (isContactExist) {
|
||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
|
||||
}
|
||||
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');
|
||||
contactQuery.set('IsDeleted', false);
|
||||
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', createdBy);
|
||||
contactQuery.set('UserId', user);
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(user.id, true);
|
||||
acl.setWriteAccess(user.id, true);
|
||||
acl.setReadAccess(createdBy.objectId, true);
|
||||
acl.setWriteAccess(createdBy.objectId, 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', createdBy);
|
||||
contactQuery.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userRes.id,
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(userRes.id, true);
|
||||
acl.setWriteAccess(userRes.id, true);
|
||||
acl.setReadAccess(createdBy.objectId, true);
|
||||
acl.setWriteAccess(createdBy.objectId, true);
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.save();
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
return parseData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(400, 'Something went wrong.');
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { getSignedLocalUrl } from './getSignedUrl.js';
|
||||
|
||||
export default async function fileUpload(request) {
|
||||
const url = request.params.url;
|
||||
|
||||
try {
|
||||
const urlwithjwt = getSignedLocalUrl(url, 200);
|
||||
return { url: urlwithjwt };
|
||||
} catch (err) {
|
||||
console.log('Err ', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { generateApiKey } from 'generate-api-key';
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
export default async function generateApiToken(request) {
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const token = await tokenQuery.first({ useMasterKey: true });
|
||||
if (token !== undefined) {
|
||||
// return exsiting Token
|
||||
console.log('Regenerate API Token');
|
||||
const AppToken = Parse.Object.extend('appToken');
|
||||
const updateToken = new AppToken();
|
||||
updateToken.id = token.id;
|
||||
const newToken = generateApiKey({ method: 'base62', prefix: 'opensign' });
|
||||
updateToken.set('token', newToken);
|
||||
const updatedRes = await updateToken.save(null, { useMasterKey: true });
|
||||
return updatedRes;
|
||||
} else {
|
||||
// Create New Token
|
||||
console.log('New API Token Generation');
|
||||
const appToken = Parse.Object.extend('appToken');
|
||||
const appTokenQuery = new appToken();
|
||||
const token = generateApiKey({ method: 'base62', prefix: 'opensign' });
|
||||
appTokenQuery.set('token', token);
|
||||
appTokenQuery.set('userId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const newRes = await appTokenQuery.save(null, { useMasterKey: true });
|
||||
return newRes;
|
||||
}
|
||||
} else {
|
||||
return 'User not found!';
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { SignPdf } from '@signpdf/signpdf';
|
||||
import { P12Signer } from '@signpdf/signer-p12';
|
||||
import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib';
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
import Parse from 'parse/node.js';
|
||||
import fs from 'node:fs';
|
||||
import dotenv from 'dotenv';
|
||||
import GenerateCertificate from './pdf/GenerateCertificate.js';
|
||||
import { getSecureUrl } from '../../Utils.js';
|
||||
dotenv.config();
|
||||
const eSignName = 'opensign';
|
||||
const eSigncontact = 'hello@opensignlabs.com';
|
||||
|
||||
// `uploadFile` is used to create url in from pdfFile
|
||||
async function uploadFile(
|
||||
pdfName,
|
||||
filepath,
|
||||
) {
|
||||
try {
|
||||
const filedata = fs.readFileSync(filepath);
|
||||
let fileUrl;
|
||||
const file = new Parse.File(pdfName, [...filedata], 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
const fileRes = getSecureUrl(file.url());
|
||||
fileUrl = fileRes.url;
|
||||
return { imageUrl: fileUrl };
|
||||
} catch (err) {
|
||||
console.log('Err ', err);
|
||||
// `unlinkCertificate` is used to remove exported signed pdf file from exports folder
|
||||
unlinkCertificate(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
async function unlinkCertificate(path) {
|
||||
if (fs.existsSync(path)) {
|
||||
try {
|
||||
fs.unlinkSync(path);
|
||||
} catch (err) {
|
||||
console.log('Err in unlink certificate generatecertificatebydocid', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default async function generateCertificatebydocId(req) {
|
||||
const docId = req.params.docId;
|
||||
// const userId = req.headers.userid;
|
||||
|
||||
if (!docId) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'please provide parameter.');
|
||||
}
|
||||
// `P12Buffer` used to create buffer from p12 certificate
|
||||
const pfxFile = process.env.PFX_BASE64;
|
||||
// const P12Buffer = fs.readFileSync();
|
||||
const P12Buffer = Buffer.from(pfxFile, 'base64');
|
||||
const certificatePath = `./exports/certificate_${docId}.pdf`;
|
||||
try {
|
||||
const getDocument = new Parse.Query('contracts_Document');
|
||||
getDocument.include('ExtUserPtr,Signers,AuditTrail.UserPtr,Placeholders,ExtUserPtr.TenantId');
|
||||
const docRes = await getDocument.get(docId, { useMasterKey: true });
|
||||
|
||||
if (docRes && docRes?.get('IsCompleted') && !docRes?.get('CertificateUrl')) {
|
||||
const _docRes = JSON.parse(JSON.stringify(docRes));
|
||||
const filteredaudit = _docRes?.AuditTrail?.filter(x => x?.UserPtr?.objectId);
|
||||
// Create a reversed copy of the array and find the last object with 'signedOn'
|
||||
const lastObj = [...filteredaudit].reverse().find(obj => obj.hasOwnProperty('SignedOn'));
|
||||
const completedAt = lastObj.SignedOn;
|
||||
const doc = { ..._docRes, completedAt: completedAt };
|
||||
const certificate = await GenerateCertificate(doc);
|
||||
const certificatePdf = await PDFDocument.load(certificate);
|
||||
const p12 = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null });
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign in certificate
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: certificatePdf,
|
||||
reason: 'Digitally signed by OpenSign.',
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await certificatePdf.save();
|
||||
const CertificateBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
//`new signPDF` create new instance of CertificateBuffer and p12Buffer
|
||||
const certificateOBJ = new SignPdf();
|
||||
// `signedCertificate` is used to sign certificate digitally
|
||||
const signedCertificate = await certificateOBJ.sign(CertificateBuffer, p12);
|
||||
|
||||
//below is used to save signed certificate in exports folder
|
||||
fs.writeFileSync(certificatePath, signedCertificate);
|
||||
const file = await uploadFile(
|
||||
'certificate.pdf',
|
||||
certificatePath,
|
||||
);
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = doc.objectId;
|
||||
updateDoc.set('CertificateUrl', file.imageUrl);
|
||||
const updateDocRes = await updateDoc.save(null, { useMasterKey: true });
|
||||
unlinkCertificate(certificatePath);
|
||||
return { CertificateUrl: file.imageUrl };
|
||||
} else {
|
||||
return { CertificateUrl: '' };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching or processing document:', error);
|
||||
const code = error?.code || 400;
|
||||
const message = error?.message || 'Something went wrong.';
|
||||
unlinkCertificate(certificatePath);
|
||||
throw new Parse.Error(code, message);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
export default async function getAllUserTeamByOrg(request) {
|
||||
const OrgId = request.params.orgId;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const teamCls = new Parse.Query('contracts_Teams');
|
||||
teamCls.equalTo('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: OrgId,
|
||||
});
|
||||
teamCls.equalTo('IsActive', true);
|
||||
const teamRes = await teamCls.first({ useMasterKey: true });
|
||||
if (teamRes) {
|
||||
return teamRes;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Team not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getOrganizations', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import {
|
||||
cloudServerUrl,
|
||||
} from '../../Utils.js';
|
||||
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) {
|
||||
@@ -48,38 +47,8 @@ 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 {
|
||||
}
|
||||
else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,25 +16,29 @@ export default async function getDrive(request) {
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
let url;
|
||||
if (docId) {
|
||||
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,ExtUserPtr.TenantId,Signers,Folder&order=-updatedAt&skip=${skip}&limit=${limit}`;
|
||||
} else {
|
||||
url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,ExtUserPtr.TenantId,Signers&order=-updatedAt&skip=${skip}&limit=${limit}`;
|
||||
}
|
||||
try {
|
||||
const res = await axios.get(url, {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-key': process.env.MASTER_KEY,
|
||||
},
|
||||
});
|
||||
// console.log('res.data.results ', res.data.results);
|
||||
if (res.data && res.data.results) {
|
||||
return res.data.results;
|
||||
const query = new Parse.Query('contracts_Document');
|
||||
if (docId) {
|
||||
query.equalTo('Folder', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Document',
|
||||
objectId: docId,
|
||||
});
|
||||
query.include('Folder');
|
||||
} else {
|
||||
return [];
|
||||
query.doesNotExist('Folder', true);
|
||||
}
|
||||
query.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
query.include('ExtUserPtr');
|
||||
query.include('ExtUserPtr.TenantId');
|
||||
query.include('Signers');
|
||||
query.notEqualTo('IsArchive', true);
|
||||
query.descending('updatedAt');
|
||||
query.skip(skip);
|
||||
query.limit(limit);
|
||||
query.exclude('AuditTrail');
|
||||
const res = await query.find({ useMasterKey: true });
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
return { error: "You don't have access to drive" };
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
export default async function getFileAdapter(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', request.user);
|
||||
extUserCls.include('TenantId');
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
const FileAdapters =
|
||||
_extUser?.TenantId?.FileAdapters?.length > 0 ? _extUser?.TenantId?.FileAdapters : [];
|
||||
const ActiveFileAdapter = _extUser?.TenantId?.ActiveFileAdapter || 'opensign';
|
||||
return { ActiveFileAdapter: ActiveFileAdapter, FileAdapters: FileAdapters };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in add custom file adapter', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
export default async function getInvoices(request) {
|
||||
const limit = request.params.limit || 100;
|
||||
const skip = request.params.skip || 0;
|
||||
const extUserId = request.params.extUserId;
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
if (!extUserId) {
|
||||
return { status: 'error', result: 'Please provide parameter!' };
|
||||
}
|
||||
const invoiceCls = new Parse.Query('contracts_Invoices');
|
||||
invoiceCls.equalTo('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUserId,
|
||||
});
|
||||
invoiceCls.limit(limit);
|
||||
invoiceCls.skip(skip);
|
||||
invoiceCls.descending('createdAt');
|
||||
const invoices = await invoiceCls.find({ useMasterKey: true });
|
||||
if (invoices?.length > 0) {
|
||||
const _invoices = JSON.parse(JSON.stringify(invoices));
|
||||
return { status: 'success', result: _invoices };
|
||||
} else {
|
||||
return { status: 'success', result: [] };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid session token!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in get invoices', err.message);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
export default async function getOrgAdmins(req) {
|
||||
if (!req?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
} else {
|
||||
try {
|
||||
const extUser = new Parse.Query('contracts_Users');
|
||||
extUser.equalTo('UserRole', 'contracts_OrgAdmin');
|
||||
extUser.equalTo('CreatedBy', req?.user);
|
||||
extUser.notEqualTo('UserId', req?.user);
|
||||
extUser.include('TeamIds,OrganizationId');
|
||||
extUser.descending('createdAt');
|
||||
const userRes = await extUser.find({ useMasterKey: true });
|
||||
if (userRes.length > 0) {
|
||||
const _userRes = JSON.parse(JSON.stringify(userRes));
|
||||
return _userRes;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getOrgAdmins', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
export default async function getOrganizations(request) {
|
||||
const limit = request.params.limit || 200;
|
||||
const skip = request.params.skip || 0;
|
||||
const extUserId = request.params.extUserId;
|
||||
const activeOrgs = request.params.active;
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const orgQuery = new Parse.Query('contracts_Organizations');
|
||||
orgQuery.equalTo('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
orgQuery.equalTo('ExtUserId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUserId,
|
||||
});
|
||||
if (activeOrgs) {
|
||||
orgQuery.equalTo('IsActive', true);
|
||||
}
|
||||
orgQuery.exclude('ExtUserId');
|
||||
orgQuery.limit(limit);
|
||||
orgQuery.skip(skip);
|
||||
const resOrg = await orgQuery.find({ useMasterKey: true });
|
||||
if (resOrg && resOrg.length > 0) {
|
||||
return resOrg;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getOrganizations', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
export default async function getPayments(request) {
|
||||
const limit = request.params.limit || 100;
|
||||
const skip = request.params.skip || 0;
|
||||
const extUserId = request.params.extUserId;
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (userId) {
|
||||
const paymentsCls = new Parse.Query('contracts_Payments');
|
||||
paymentsCls.equalTo('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_User',
|
||||
objectId: extUserId,
|
||||
});
|
||||
paymentsCls.limit(limit);
|
||||
paymentsCls.skip(skip);
|
||||
paymentsCls.descending('createdAt');
|
||||
const payments = await paymentsCls.find({ useMasterKey: true });
|
||||
if (payments?.length > 0) {
|
||||
const _payments = JSON.parse(JSON.stringify(payments));
|
||||
return { status: 'success', result: _payments };
|
||||
} else {
|
||||
return { status: 'success', result: [] };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid session token!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in get Payments', err.message);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
export default async function getPfxFile(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', request.user);
|
||||
extUserCls.include('TenantId');
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
const title = _extUser?.TenantId?.PfxFile?.title || '';
|
||||
const pfxBase64 = _extUser?.TenantId?.PfxFile?.base64 || '';
|
||||
const password = _extUser?.TenantId?.PfxFile?.password || '';
|
||||
return { title: title, password: password, base64: pfxBase64 };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in add custom file adapter', err);
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,47 @@
|
||||
import AWS from 'aws-sdk';
|
||||
import { useLocal } from '../../Utils.js';
|
||||
export default function getPresignedUrl(url, adapter) {
|
||||
const credentials = {
|
||||
accessKeyId: adapter?.accessKeyId || process.env.DO_ACCESS_KEY_ID,
|
||||
secretAccessKey: adapter?.secretAccessKey || process.env.DO_SECRET_ACCESS_KEY,
|
||||
};
|
||||
AWS.config.update({ credentials: credentials, region: adapter?.region || process.env.DO_REGION });
|
||||
const spacesEndpoint = adapter?.endpoint || new AWS.Endpoint(process.env.DO_ENDPOINT);
|
||||
import jwt from 'jsonwebtoken';
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
const s3 = new AWS.S3({ endpoint: spacesEndpoint, signatureVersion: "v4" });
|
||||
export default function getPresignedUrl(
|
||||
url,
|
||||
) {
|
||||
if (url?.includes('files')) {
|
||||
return presignedlocalUrl(url);
|
||||
} else {
|
||||
const credentials = {
|
||||
accessKeyId:
|
||||
process.env.DO_ACCESS_KEY_ID,
|
||||
secretAccessKey:
|
||||
process.env.DO_SECRET_ACCESS_KEY,
|
||||
};
|
||||
AWS.config.update({
|
||||
credentials: credentials,
|
||||
region:
|
||||
process.env.DO_REGION,
|
||||
});
|
||||
const spacesEndpoint =
|
||||
new AWS.Endpoint(process.env.DO_ENDPOINT);
|
||||
|
||||
// Create a new URL object
|
||||
const parsedUrl = new URL(url);
|
||||
// Get the pathname of the URL
|
||||
const pathname = parsedUrl.pathname;
|
||||
// Extract the filename from the pathname
|
||||
const filename = pathname.substring(pathname.lastIndexOf('/') + 1);
|
||||
const s3 = new AWS.S3({ endpoint: spacesEndpoint, signatureVersion: 'v4' });
|
||||
|
||||
// presignedGETURL return presignedUrl with expires time
|
||||
const presignedGETURL = s3.getSignedUrl('getObject', {
|
||||
Bucket: adapter?.bucketName || process.env.DO_SPACE,
|
||||
Key: filename, //filename
|
||||
Expires: 160, //time to expire in seconds
|
||||
});
|
||||
return presignedGETURL;
|
||||
// Create a new URL object
|
||||
const parsedUrl = new URL(url);
|
||||
// Get the pathname of the URL
|
||||
const pathname = parsedUrl.pathname;
|
||||
// Extract the filename from the pathname
|
||||
const filename = pathname.substring(pathname.lastIndexOf('/') + 1);
|
||||
|
||||
// presignedGETURL return presignedUrl with expires time
|
||||
const presignedGETURL = s3.getSignedUrl('getObject', {
|
||||
Bucket:
|
||||
process.env.DO_SPACE,
|
||||
Key: filename, //filename
|
||||
Expires: 160, //time to expire in seconds
|
||||
});
|
||||
return presignedGETURL;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSignedUrl(request) {
|
||||
@@ -31,10 +49,13 @@ export async function getSignedUrl(request) {
|
||||
const docId = request.params.docId || '';
|
||||
const templateId = request.params.templateId || '';
|
||||
const url = request.params.url;
|
||||
const fileAdapterId = request.params.fileAdapterId || '';
|
||||
if (docId || templateId) {
|
||||
try {
|
||||
if (fileAdapterId || useLocal !== 'true') {
|
||||
if (url?.includes('files')) {
|
||||
return presignedlocalUrl(url);
|
||||
} else if (
|
||||
useLocal !== 'true'
|
||||
) {
|
||||
const query = new Parse.Query(docId ? 'contracts_Document' : 'contracts_Template');
|
||||
query.equalTo('objectId', docId ? docId : templateId);
|
||||
query.include('ExtUserPtr.TenantId');
|
||||
@@ -49,26 +70,15 @@ export async function getSignedUrl(request) {
|
||||
'User is not authenticated.'
|
||||
);
|
||||
} else {
|
||||
let adapterConfig = {};
|
||||
if (fileAdapterId) {
|
||||
// `adapterConfig` is used to get file in user's fileAdapter
|
||||
adapterConfig =
|
||||
_resDoc?.ExtUserPtr?.TenantId?.FileAdapters?.find(
|
||||
x => x.id === fileAdapterId
|
||||
) || {};
|
||||
}
|
||||
const presignedUrl = getPresignedUrl(url, adapterConfig);
|
||||
const presignedUrl = getPresignedUrl(
|
||||
url,
|
||||
);
|
||||
return presignedUrl;
|
||||
}
|
||||
} else {
|
||||
let adapterConfig = {};
|
||||
if (fileAdapterId) {
|
||||
// `adapterConfig` is used to get file in user's fileAdapter
|
||||
adapterConfig =
|
||||
_resDoc?.ExtUserPtr?.TenantId?.FileAdapters?.find(x => x.id === fileAdapterId) ||
|
||||
{};
|
||||
}
|
||||
const presignedUrl = getPresignedUrl(url, adapterConfig);
|
||||
const presignedUrl = getPresignedUrl(
|
||||
url,
|
||||
);
|
||||
return presignedUrl;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +93,9 @@ export async function getSignedUrl(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
} else {
|
||||
if (useLocal !== 'true') {
|
||||
if (url?.includes('files')) {
|
||||
return presignedlocalUrl(url);
|
||||
} else if (useLocal !== 'true') {
|
||||
const presignedUrl = getPresignedUrl(url);
|
||||
return presignedUrl;
|
||||
} else {
|
||||
@@ -99,3 +111,71 @@ export async function getSignedUrl(request) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to generate a signed URL with JWT
|
||||
export function getSignedLocalUrl(fileUrl, expirationTimeInSeconds) {
|
||||
const secretKey = process.env.MASTER_KEY;
|
||||
const exp = expirationTimeInSeconds || 200;
|
||||
try {
|
||||
// Create the payload with the file URL and expiration time
|
||||
const payload = {
|
||||
fileUrl,
|
||||
exp: Math.floor(Date.now() / 1000) + exp, // Expiry time in seconds
|
||||
};
|
||||
|
||||
// Generate the JWT token
|
||||
const token = jwt.sign(payload, secretKey);
|
||||
// Return the signed URL containing the token
|
||||
return `${fileUrl}?token=${token}`;
|
||||
} catch (err) {
|
||||
console.log('Err while siging local url', err);
|
||||
throw new Error('Invalid or expired token.');
|
||||
}
|
||||
}
|
||||
|
||||
export function presignedlocalUrl(signedUrl, expirationTimeInSeconds) {
|
||||
if (signedUrl?.includes('files')) {
|
||||
const fileUrl = signedUrl.split('?')?.[0];
|
||||
const secretKey = process.env.MASTER_KEY;
|
||||
const exp = expirationTimeInSeconds || 200;
|
||||
try {
|
||||
// Create the payload with the file URL and expiration time
|
||||
const payload = {
|
||||
fileUrl,
|
||||
exp: Math.floor(Date.now() / 1000) + exp, // Expiry time in seconds
|
||||
};
|
||||
// Generate the JWT token
|
||||
const token = jwt.sign(payload, secretKey);
|
||||
// Return the signed URL containing the token
|
||||
return `${fileUrl}?token=${token}`;
|
||||
} catch (err) {
|
||||
throw new Error('Invalid or expired token.');
|
||||
}
|
||||
} else {
|
||||
return signedUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to validate the signed URL
|
||||
export async function validateSignedLocalUrl(signedUrl) {
|
||||
const urlParams = new URLSearchParams(signedUrl.split('?')[1]);
|
||||
const token = urlParams.get('token');
|
||||
try {
|
||||
if (!token) {
|
||||
throw new Error('No token provided.');
|
||||
}
|
||||
const secretKey = process.env.MASTER_KEY;
|
||||
// Now verify the token (validate signature and expiration automatically)
|
||||
const decoded = jwt.verify(token, secretKey);
|
||||
// Check if the file URL in the JWT matches the requested file URL
|
||||
const fileUrl = signedUrl.split('?')[0];
|
||||
if (decoded.fileUrl !== fileUrl) {
|
||||
throw new Error('Invalid file URL in token.');
|
||||
}
|
||||
// If the token is valid and not expired, return the file URL
|
||||
return signedUrl;
|
||||
} catch (error) {
|
||||
console.log('Error validating file', error.message);
|
||||
return 'Unauthorized';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +1,42 @@
|
||||
import { parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
// Function to escape special characters in the search string
|
||||
function escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escape special characters
|
||||
}
|
||||
|
||||
async function getContacts(searchObj, isJWT) {
|
||||
try {
|
||||
const escapedSearch = escapeRegExp(searchObj.search); // Escape the search input
|
||||
const searchRegex = new RegExp(escapedSearch, 'i'); // Create regex once to reuse
|
||||
const contactNameQuery = new Parse.Query('contracts_Contactbook');
|
||||
contactNameQuery.matches('Name', searchRegex);
|
||||
|
||||
const conatctEmailQuery = new Parse.Query('contracts_Contactbook');
|
||||
conatctEmailQuery.matches('Email', searchRegex);
|
||||
|
||||
// Combine the two queries with OR
|
||||
const mainQuery = Parse.Query.or(contactNameQuery, conatctEmailQuery);
|
||||
|
||||
// Add the common condition for 'CreatedBy'
|
||||
mainQuery.equalTo('CreatedBy', searchObj.CreatedBy);
|
||||
mainQuery.notEqualTo('IsDeleted', true);
|
||||
const findOpt = isJWT ? { useMasterKey: true } : { sessionToken: searchObj.sessionToken };
|
||||
const contactRes = await mainQuery.find(findOpt);
|
||||
const _contactRes = JSON.parse(JSON.stringify(contactRes));
|
||||
return _contactRes;
|
||||
} catch (err) {
|
||||
console.log('err while fetch contacts', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
export default async function getSigners(request) {
|
||||
const jwttoken = request.headers.jwttoken || '';
|
||||
const search = request.params.search || '';
|
||||
const searchEmail = request.params.searchEmail || '';
|
||||
const searchObj = { search: request.params.search || '', sessionToken: '' };
|
||||
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({ sessionToken: request.user.getSessionToken() });
|
||||
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 {
|
||||
searchObj.CreatedBy = { __type: 'Pointer', className: '_User', objectId: request?.user?.id };
|
||||
searchObj.sessionToken = request.user.getSessionToken();
|
||||
return await getContacts(searchObj);
|
||||
}
|
||||
else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
import axios from 'axios';
|
||||
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 (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
|
||||
if (!ispublic) {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
userId = userRes.data && userRes.data.objectId;
|
||||
}
|
||||
if (userId || ispublic) {
|
||||
const extCls = new Parse.Query('contracts_Users');
|
||||
const exUser = await extCls.get(extUserId, { 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 session token!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in get subscription', err.message);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
} else if (contactId) {
|
||||
try {
|
||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||
const contactUser = await contactCls.get(contactId, { useMasterKey: true });
|
||||
if (contactUser) {
|
||||
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||
subscriptionCls.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: contactUser.get('TenantId').id,
|
||||
});
|
||||
subscriptionCls.descending('createdAt');
|
||||
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||
if (subcripitions) {
|
||||
const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
|
||||
if (_subcripitions.PlanCode === 'freeplan') {
|
||||
return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } };
|
||||
} else if (_subcripitions?.Next_billing_date?.iso) {
|
||||
if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) {
|
||||
return { status: 'success', result: { isSubscribed: true } };
|
||||
} else {
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
} else {
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
} else {
|
||||
return { status: 'success', result: { isSubscribed: false } };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'User not found!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in get subscription2', err.message);
|
||||
return { status: 'error', result: err.message };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid session token!' };
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export default async function getTeams(request) {
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getOrganizations', err);
|
||||
console.log('err in getTeams', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
async function getTenantByUserId(userId, contactId) {
|
||||
try {
|
||||
@@ -50,34 +48,13 @@ async function getTenantByUserId(userId, contactId) {
|
||||
}
|
||||
}
|
||||
export default async function getTenant(request) {
|
||||
const jwttoken = request.headers.jwttoken || '';
|
||||
const userId = request.params.userId || '';
|
||||
const contactId = request.params.contactId || '';
|
||||
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 apiUserId = userRes?.id;
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('userId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: apiUserId,
|
||||
});
|
||||
const appRes = await tokenQuery.first({ useMasterKey: true });
|
||||
const decoded = jwt.verify(verifyToken, appRes?.get('token'));
|
||||
if (decoded?.user_email) {
|
||||
return await getTenantByUserId(apiUserId, contactId);
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid token!' };
|
||||
}
|
||||
}
|
||||
} else if (userId || contactId) {
|
||||
|
||||
if (userId || contactId) {
|
||||
return await getTenantByUserId(userId, contactId);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
export default async function getUserByOrg(req) {
|
||||
const OrganizationId = req.params.organizationId;
|
||||
const orgPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: OrganizationId,
|
||||
};
|
||||
if (!req?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
} else {
|
||||
try {
|
||||
const extUser = new Parse.Query('contracts_Users');
|
||||
extUser.include('TeamIds');
|
||||
extUser.equalTo('OrganizationId', orgPtr);
|
||||
const userRes = await extUser.first({ useMasterKey: true });
|
||||
if (userRes.length > 0) {
|
||||
const _userRes = JSON.parse(JSON.stringify(userRes));
|
||||
return _userRes;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in getuserlist', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
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;
|
||||
@@ -40,49 +36,8 @@ 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 {
|
||||
}
|
||||
else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
|
||||
export default async function getapitoken(request) {
|
||||
try {
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
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 (userId) {
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const res = await tokenQuery.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
return { status: 'success', result: res.get('token') };
|
||||
} else {
|
||||
return { error: 'api token found.' };
|
||||
}
|
||||
} else {
|
||||
return { error: 'Invalid session token.' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in getapitoken', err);
|
||||
if (err.code == 209) {
|
||||
return { error: 'Invalid session token.' };
|
||||
} else {
|
||||
return { error: "You don't have access." };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,7 @@
|
||||
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) {
|
||||
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');
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
|
||||
import fs from 'node:fs';
|
||||
import fontkit from '@pdf-lib/fontkit';
|
||||
import { formatTimeInTimezone } from '../../../Utils.js';
|
||||
|
||||
export default async function GenerateCertificate(docDetails) {
|
||||
const timezone = docDetails?.ExtUserPtr?.Timezone || '';
|
||||
const pdfDoc = await PDFDocument.create();
|
||||
// `fontBytes` is used to embed custom font in pdf
|
||||
const fontBytes = fs.readFileSync('./font/times.ttf'); //
|
||||
@@ -23,19 +25,23 @@ export default async function GenerateCertificate(docDetails) {
|
||||
const timeText = 11;
|
||||
const textKeyColor = rgb(0.12, 0.12, 0.12);
|
||||
const textValueColor = rgb(0.3, 0.3, 0.3);
|
||||
const completedAt = new Date();
|
||||
const completedUTCtime = completedAt.toUTCString();
|
||||
const completedAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date();
|
||||
const completedAtperTimezone = formatTimeInTimezone(completedAt, timezone);
|
||||
const completedUTCtime = completedAtperTimezone;
|
||||
const signersCount = docDetails?.Signers?.length || 1;
|
||||
const generateAt = new Date();
|
||||
const generatedUTCTime = generateAt.toUTCString();
|
||||
const generateAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date();
|
||||
const generatedAtperTimezone = formatTimeInTimezone(generateAt, timezone);
|
||||
const generatedUTCTime = generatedAtperTimezone;
|
||||
const generatedOn = 'Generated On ' + generatedUTCTime;
|
||||
const OriginIp = docDetails?.OriginIp || '';
|
||||
const company = docDetails?.ExtUserPtr?.Company || '';
|
||||
const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt;
|
||||
const createdAtperTimezone = formatTimeInTimezone(createdAt, timezone);
|
||||
const IsEnableOTP = docDetails?.IsEnableOTP || false;
|
||||
const filteredaudit = docDetails?.AuditTrail?.filter(x => x?.UserPtr?.objectId);
|
||||
const auditTrail =
|
||||
docDetails?.Signers?.length > 0
|
||||
? docDetails.AuditTrail.map(x => {
|
||||
? filteredaudit?.map(x => {
|
||||
const data = docDetails.Signers.find(y => y.objectId === x.UserPtr.objectId);
|
||||
return {
|
||||
...data,
|
||||
@@ -48,16 +54,15 @@ export default async function GenerateCertificate(docDetails) {
|
||||
: [
|
||||
{
|
||||
...docDetails.ExtUserPtr,
|
||||
ipAddress: docDetails?.AuditTrail[0].ipAddress,
|
||||
SignedOn: docDetails?.AuditTrail[0]?.SignedOn || generatedUTCTime,
|
||||
ViewedOn:
|
||||
docDetails?.AuditTrail[0]?.ViewedOn ||
|
||||
docDetails?.AuditTrail[0]?.SignedOn ||
|
||||
generatedUTCTime,
|
||||
Signature: docDetails?.AuditTrail[0]?.Signature || '',
|
||||
ipAddress: filteredaudit[0].ipAddress,
|
||||
SignedOn: filteredaudit[0]?.SignedOn || generatedUTCTime,
|
||||
ViewedOn: filteredaudit[0]?.ViewedOn || filteredaudit[0]?.SignedOn || generatedUTCTime,
|
||||
Signature: filteredaudit[0]?.Signature || '',
|
||||
},
|
||||
];
|
||||
|
||||
const ownerName = docDetails?.SenderName || docDetails.ExtUserPtr?.Name || 'n/a';
|
||||
const ownerEmail = docDetails?.SenderMail || docDetails.ExtUserPtr?.Email || 'n/a';
|
||||
const half = width / 2;
|
||||
// Draw a border
|
||||
page.drawRectangle({
|
||||
@@ -131,10 +136,10 @@ export default async function GenerateCertificate(docDetails) {
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(docDetails.Name, {
|
||||
page.drawText(docDetails?.Name, {
|
||||
x: 140,
|
||||
y: 665,
|
||||
size: text,
|
||||
size: docDetails?.Name?.length >= 78 ? 12 : text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
@@ -162,7 +167,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(`${new Date(createdAt).toUTCString()}`, {
|
||||
page.drawText(`${createdAtperTimezone}`, {
|
||||
x: 105,
|
||||
y: 625,
|
||||
size: text,
|
||||
@@ -213,7 +218,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText(`${docDetails.ExtUserPtr.Name}`, {
|
||||
page.drawText(ownerName, {
|
||||
x: 105,
|
||||
y: 545,
|
||||
size: text,
|
||||
@@ -227,7 +232,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText(`${docDetails.ExtUserPtr.Email}`, {
|
||||
page.drawText(ownerEmail, {
|
||||
x: 105,
|
||||
y: 525,
|
||||
size: text,
|
||||
@@ -287,15 +292,16 @@ export default async function GenerateCertificate(docDetails) {
|
||||
});
|
||||
|
||||
page.drawText('Viewed on :', {
|
||||
x: half + 55,
|
||||
x: half + 45,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(`${new Date(x.ViewedOn).toUTCString()}`, {
|
||||
x: half + 112,
|
||||
//new Date(x.ViewedOn).toUTCString()
|
||||
page.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, {
|
||||
x: half + 102,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
@@ -319,15 +325,16 @@ export default async function GenerateCertificate(docDetails) {
|
||||
});
|
||||
|
||||
page.drawText('Signed on :', {
|
||||
x: half + 55,
|
||||
x: half + 45,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(`${new Date(x.SignedOn).toUTCString()}`, {
|
||||
x: half + 108,
|
||||
// new Date(x.SignedOn).toUTCString()
|
||||
page.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, {
|
||||
x: half + 98,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
@@ -351,14 +358,14 @@ export default async function GenerateCertificate(docDetails) {
|
||||
});
|
||||
if (IsEnableOTP) {
|
||||
page.drawText('Security level :', {
|
||||
x: half + 55,
|
||||
x: half + 45,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText('Email, OTP Auth', {
|
||||
x: half + 125,
|
||||
x: half + 115,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
@@ -458,15 +465,16 @@ export default async function GenerateCertificate(docDetails) {
|
||||
});
|
||||
|
||||
currentPage.drawText('Viewed on :', {
|
||||
x: half + 55,
|
||||
x: half + 45,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
currentPage.drawText(`${new Date(x.ViewedOn).toUTCString()}`, {
|
||||
x: half + 112,
|
||||
// new Date(x.ViewedOn).toUTCString()
|
||||
currentPage.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, {
|
||||
x: half + 102,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
@@ -490,15 +498,16 @@ export default async function GenerateCertificate(docDetails) {
|
||||
});
|
||||
|
||||
currentPage.drawText('Signed on :', {
|
||||
x: half + 55,
|
||||
x: half + 45,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
currentPage.drawText(`${new Date(x.SignedOn).toUTCString()}`, {
|
||||
x: half + 108,
|
||||
// new Date(x.SignedOn).toUTCString()
|
||||
currentPage.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, {
|
||||
x: half + 98,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
@@ -523,14 +532,14 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
if (IsEnableOTP) {
|
||||
currentPage.drawText('Security level :', {
|
||||
x: half + 55,
|
||||
x: half + 45,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
currentPage.drawText(`Email, OTP Auth`, {
|
||||
x: half + 125,
|
||||
x: half + 115,
|
||||
y: yPosition4 + 10,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
|
||||
@@ -4,37 +4,31 @@ import { SignPdf } from '@signpdf/signpdf';
|
||||
import { P12Signer } from '@signpdf/signer-p12';
|
||||
import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib';
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
import { cloudServerUrl, replaceMailVaribles, saveFileUsage } from '../../../Utils.js';
|
||||
import {
|
||||
cloudServerUrl,
|
||||
replaceMailVaribles,
|
||||
saveFileUsage,
|
||||
getSecureUrl,
|
||||
} from '../../../Utils.js';
|
||||
import GenerateCertificate from './GenerateCertificate.js';
|
||||
import uploadFileToS3 from '../uploadFiletoS3.js';
|
||||
import { Placeholder } from './Placeholder.js';
|
||||
const serverUrl = cloudServerUrl; // process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
const eSignName = 'opensign';
|
||||
const eSigncontact = 'hello@opensignlabs.com';
|
||||
// `updateDoc` is used to create url in from pdfFile
|
||||
async function uploadFile(pdfName, filepath, adapter) {
|
||||
async function uploadFile(
|
||||
pdfName,
|
||||
filepath,
|
||||
) {
|
||||
try {
|
||||
const filedata = fs.readFileSync(filepath);
|
||||
let fileUrl;
|
||||
if (adapter?.bucketName) {
|
||||
const adapterConfig = {
|
||||
id: adapter?.id,
|
||||
fileAdapter: adapter?.fileAdapter,
|
||||
bucketName: adapter?.bucketName,
|
||||
region: adapter?.region,
|
||||
endpoint: adapter?.endpoint,
|
||||
accessKeyId: adapter?.accessKeyId,
|
||||
secretAccessKey: adapter?.secretAccessKey,
|
||||
baseUrl: adapter?.baseUrl,
|
||||
};
|
||||
// `uploadFileToS3` is used to save document in user's file storage
|
||||
fileUrl = await uploadFileToS3(filedata, pdfName, 'application/pdf', adapterConfig);
|
||||
} else {
|
||||
const file = new Parse.File(pdfName, [...filedata], 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
fileUrl = file.url();
|
||||
}
|
||||
const fileRes = getSecureUrl(file.url());
|
||||
fileUrl = fileRes.url;
|
||||
|
||||
return { imageUrl: fileUrl };
|
||||
} catch (err) {
|
||||
@@ -161,67 +155,80 @@ async function sendCompletedMail(obj) {
|
||||
const recipient = signersMail;
|
||||
let subject = `Document "${pdfName}" has been signed by all parties`;
|
||||
let body =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" +
|
||||
mailLogo +
|
||||
" height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document signed successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document " +
|
||||
`<b>"${pdfName}"</b>` +
|
||||
'. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ' +
|
||||
sender.Email +
|
||||
' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>';
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white;'>" +
|
||||
`<div><img src=${mailLogo} height='50' style='padding:20px'/></div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'>` +
|
||||
`<p style='font-size:20px;font-weight:400;color:white;padding-left:20px;'>Document signed successfully</p></div><div>` +
|
||||
`<p style='padding:20px;font-family:system-ui;font-size:14px;'>All parties have successfully signed the document <b>"${pdfName}"</b>. Kindly download the document from the attachment.</p>` +
|
||||
`</div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
|
||||
'If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>';
|
||||
|
||||
if (obj?.isCustomMail) {
|
||||
try {
|
||||
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
|
||||
tenantCreditsQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: sender.UserId.objectId,
|
||||
});
|
||||
const res = await tenantCreditsQuery.first();
|
||||
if (res) {
|
||||
const _res = JSON.parse(JSON.stringify(res));
|
||||
if (_res?.CompletionSubject) {
|
||||
subject = _res?.CompletionSubject;
|
||||
const tenant = sender?.TenantId;
|
||||
if (tenant) {
|
||||
subject = tenant?.CompletionSubject || '';
|
||||
body = tenant?.CompletionBody || '';
|
||||
} else {
|
||||
const userId = sender?.CreatedBy?.objectId || sender?.UserId?.objectId;
|
||||
if (userId) {
|
||||
try {
|
||||
const tenantQuery = new Parse.Query('partners_Tenant');
|
||||
tenantQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
const tenantRes = await tenantQuery.first();
|
||||
if (tenantRes) {
|
||||
const _tenantRes = JSON.parse(JSON.stringify(tenantRes));
|
||||
subject = _tenantRes?.CompletionSubject || '';
|
||||
body = _tenantRes?.CompletionBody || '';
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error in fetch tenant in signpdf', err.message);
|
||||
}
|
||||
if (_res?.CompletionBody) {
|
||||
body = _res?.CompletionBody;
|
||||
}
|
||||
const expireDate = doc.ExpiryDate.iso;
|
||||
const newDate = new Date(expireDate);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
|
||||
const variables = {
|
||||
document_title: pdfName,
|
||||
sender_name: sender.Name,
|
||||
sender_mail: sender.Email,
|
||||
sender_phone: sender?.Phone || '',
|
||||
receiver_name: sender.Name,
|
||||
receiver_email: sender.Email,
|
||||
receiver_phone: sender?.Phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: sender.Company,
|
||||
};
|
||||
const replaceVar = replaceMailVaribles(subject, body, variables);
|
||||
subject = replaceVar.subject;
|
||||
body = replaceVar.body;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error in fetch tenant in signpdf', err.message);
|
||||
}
|
||||
const expireDate = doc.ExpiryDate.iso;
|
||||
const newDate = new Date(expireDate);
|
||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
});
|
||||
|
||||
const variables = {
|
||||
document_title: pdfName,
|
||||
sender_name:
|
||||
sender.Name,
|
||||
sender_mail: doc?.SenderMail || sender.Email,
|
||||
sender_phone: sender?.Phone || '',
|
||||
receiver_name: sender.Name,
|
||||
receiver_email: sender.Email,
|
||||
receiver_phone: sender?.Phone || '',
|
||||
expiry_date: localExpireDate,
|
||||
company_name: sender.Company,
|
||||
};
|
||||
const replaceVar = replaceMailVaribles(subject, body, variables);
|
||||
subject = replaceVar.subject;
|
||||
body = replaceVar.body;
|
||||
}
|
||||
const Bcc = doc?.Bcc?.length > 0 ? doc.Bcc.map(x => x.Email) : '';
|
||||
const params = {
|
||||
extUserId: sender.objectId,
|
||||
url: url,
|
||||
from: 'OpenSign™',
|
||||
from:
|
||||
'OpenSign™',
|
||||
replyto:
|
||||
doc?.ExtUserPtr?.Email ||
|
||||
'',
|
||||
recipient: recipient,
|
||||
subject: subject,
|
||||
pdfName: pdfName,
|
||||
html: body,
|
||||
mailProvider: obj.mailProvider,
|
||||
bcc: Bcc,
|
||||
certificatePath: `./exports/certificate_${doc.objectId}.pdf`,
|
||||
filename: obj?.filename,
|
||||
};
|
||||
const res = await axios.post(serverUrl + '/functions/sendmailv3', params, {
|
||||
headers: {
|
||||
@@ -232,72 +239,15 @@ async function sendCompletedMail(obj) {
|
||||
});
|
||||
}
|
||||
|
||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||
async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) {
|
||||
let signers = [];
|
||||
if (signUser) {
|
||||
signers = { name: signUser?.Name, email: signUser?.Email, phone: signUser?.Phone };
|
||||
} else {
|
||||
signers = doc?.Signers?.map(x => ({ name: x.Name, email: x.Email, phone: x.Phone })) || [
|
||||
{ name: doc?.ExtUserPtr?.Name, email: doc?.ExtUserPtr?.Email, phone: doc?.ExtUserPtr?.Phone },
|
||||
];
|
||||
}
|
||||
|
||||
if (doc.ExtUserPtr?.Webhook) {
|
||||
const time =
|
||||
event === 'signed'
|
||||
? { signer: signers, signedAt: new Date() }
|
||||
: { signers: signers, completedAt: new Date() };
|
||||
const certificate = certificateUrl ? { certificate: certificateUrl } : {};
|
||||
const params = {
|
||||
event: event,
|
||||
objectId: doc?.objectId,
|
||||
file: Url || '',
|
||||
...certificate,
|
||||
name: doc?.Name,
|
||||
note: doc?.Note || '',
|
||||
description: doc?.Description || '',
|
||||
...time,
|
||||
createdAt: doc?.createdAt,
|
||||
};
|
||||
axios
|
||||
.post(doc?.ExtUserPtr?.Webhook, params, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
.then(res => {
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: doc.ExtUserPtr.UserId.objectId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err.message);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: doc.ExtUserPtr.UserId.objectId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// `sendMailsaveCertifcate` is used send completion mail and update complete status of document
|
||||
async function sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider, adapterConfig) {
|
||||
async function sendMailsaveCertifcate(
|
||||
doc,
|
||||
P12Buffer,
|
||||
isCustomMail,
|
||||
mailProvider,
|
||||
filename
|
||||
) {
|
||||
const certificate = await GenerateCertificate(doc);
|
||||
const certificatePdf = await PDFDocument.load(certificate);
|
||||
let passphrase = process.env.PASS_PHRASE;
|
||||
@@ -320,10 +270,13 @@ async function sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider
|
||||
const certificateOBJ = new SignPdf();
|
||||
// `signedCertificate` is used to sign certificate digitally
|
||||
const signedCertificate = await certificateOBJ.sign(CertificateBuffer, p12);
|
||||
|
||||
const certificatePath = `./exports/certificate_${doc.objectId}.pdf`;
|
||||
//below is used to save signed certificate in exports folder
|
||||
fs.writeFileSync('./exports/certificate.pdf', signedCertificate);
|
||||
const file = await uploadFile('certificate.pdf', './exports/certificate.pdf', adapterConfig);
|
||||
fs.writeFileSync(certificatePath, signedCertificate);
|
||||
const file = await uploadFile(
|
||||
'certificate.pdf',
|
||||
certificatePath,
|
||||
);
|
||||
const body = { CertificateUrl: file.imageUrl };
|
||||
await axios.put(serverUrl + '/classes/contracts_Document/' + doc.objectId, body, {
|
||||
headers: {
|
||||
@@ -336,10 +289,9 @@ async function sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider
|
||||
if (doc.IsSendMail === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
sendCompletedMail({ isCustomMail, doc, mailProvider });
|
||||
sendCompletedMail({ isCustomMail, doc, mailProvider, filename });
|
||||
}
|
||||
saveFileUsage(CertificateBuffer.length, file.imageUrl, doc?.CreatedBy?.objectId);
|
||||
sendDoctoWebhook(doc, doc?.SignedUrl, 'completed', '', file.imageUrl);
|
||||
}
|
||||
/**
|
||||
*
|
||||
@@ -357,7 +309,7 @@ async function PDF(req) {
|
||||
const sign = req.params.signature || '';
|
||||
// below bode is used to get info of docId
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.include('ExtUserPtr,Signers,ExtUserPtr.TenantId');
|
||||
docQuery.include('ExtUserPtr,Signers,ExtUserPtr.TenantId,Bcc');
|
||||
docQuery.equalTo('objectId', docId);
|
||||
const resDoc = await docQuery.first({ useMasterKey: true });
|
||||
if (!resDoc) {
|
||||
@@ -371,17 +323,6 @@ async function PDF(req) {
|
||||
}
|
||||
}
|
||||
const _resDoc = resDoc?.toJSON();
|
||||
// `fileAdapterId` is used check document uploaded in custom file adapter and get customFileAdapter id
|
||||
const fileAdapterId = _resDoc?.FileAdapterId || '';
|
||||
let adapterConfig = {};
|
||||
if (fileAdapterId) {
|
||||
// `FileAdapter` is used to credintials of file adapter
|
||||
const FileAdapter =
|
||||
_resDoc?.ExtUserPtr?.TenantId?.FileAdapters?.find(x => x.id === fileAdapterId) || {};
|
||||
if (FileAdapter) {
|
||||
adapterConfig = FileAdapter;
|
||||
}
|
||||
}
|
||||
let signUser;
|
||||
let className;
|
||||
// `reqUserId` is send throught pdfrequest signing flow
|
||||
@@ -433,38 +374,32 @@ async function PDF(req) {
|
||||
const randomNumber = Math.floor(Math.random() * 5000);
|
||||
// below regex is used to replace all word with "_" except A to Z, a to z, numbers
|
||||
const docName = _resDoc?.Name?.replace(/[^a-zA-Z0-9._-]/g, '_')?.toLowerCase();
|
||||
const name = `signed_${docName}_${randomNumber}.pdf`;
|
||||
const filename = docName?.length > 100 ? docName?.slice(0, 100) : docName;
|
||||
const name = `signed_${filename}_${randomNumber}.pdf`;
|
||||
const filePath = `./exports/${name}`;
|
||||
let pdfSize = PdfBuffer.length;
|
||||
if (isCompleted) {
|
||||
const signersName = _resDoc.Signers?.map(x => x.Name + ' <' + x.Email + '>');
|
||||
if (signersName && signersName.length > 0) {
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + signersName?.join(', '),
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
} else {
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget (signyourself)
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + username + ' <' + userEmail + '>',
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
}
|
||||
const reason =
|
||||
signersName && signersName.length > 0
|
||||
? signersName?.join(', ')
|
||||
: username + ' <' + userEmail + '>';
|
||||
const pdfDoc = await PDFDocument.load(PdfBuffer);
|
||||
const form = pdfDoc.getForm();
|
||||
// Updates the field appearances to ensure visual changes are reflected.
|
||||
form.updateFieldAppearances();
|
||||
// Flattens the form, converting all form fields into non-editable, static content
|
||||
form.flatten();
|
||||
Placeholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: 'Digitally signed by OpenSign for ' + reason,
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
//`new signPDF` create new instance of pdfBuffer and p12Buffer
|
||||
const OBJ = new SignPdf();
|
||||
// `signedDocs` is used to signpdf digitally
|
||||
@@ -480,7 +415,10 @@ async function PDF(req) {
|
||||
}
|
||||
|
||||
// `uploadFile` is used to upload pdf to aws s3 and get it's url
|
||||
const data = await uploadFile(name, filePath, adapterConfig);
|
||||
const data = await uploadFile(
|
||||
name,
|
||||
filePath,
|
||||
);
|
||||
|
||||
if (data && data.imageUrl) {
|
||||
// `axios` is used to update signed pdf url in contracts_Document classes for given DocId
|
||||
@@ -493,12 +431,17 @@ async function PDF(req) {
|
||||
className, // className based on flow
|
||||
sign // sign base64
|
||||
);
|
||||
sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser);
|
||||
sendNotifyMail(_resDoc, signUser, mailProvider);
|
||||
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
|
||||
if (updatedDoc && updatedDoc.isCompleted) {
|
||||
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl };
|
||||
sendMailsaveCertifcate(doc, P12Buffer, isCustomMail, mailProvider, adapterConfig);
|
||||
sendMailsaveCertifcate(
|
||||
doc,
|
||||
P12Buffer,
|
||||
isCustomMail,
|
||||
mailProvider,
|
||||
name
|
||||
);
|
||||
}
|
||||
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
|
||||
fs.unlinkSync(filePath);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { PDFArray, CharCodes } from 'pdf-lib';
|
||||
|
||||
/**
|
||||
* Extends PDFArray class in order to make ByteRange look like this:
|
||||
* /ByteRange [0 /********** /********** /**********]
|
||||
* Not this:
|
||||
* /ByteRange [ 0 /********** /********** /********** ]
|
||||
*/
|
||||
export default class PDFArrayCustom extends PDFArray {
|
||||
static withContext(context) {
|
||||
return new PDFArrayCustom(context);
|
||||
}
|
||||
|
||||
clone(context) {
|
||||
const clone = PDFArrayCustom.withContext(context || this.context);
|
||||
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
||||
clone.push(this.array[idx]);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
toString() {
|
||||
let arrayString = '[';
|
||||
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
||||
arrayString += this.get(idx).toString();
|
||||
if (idx < len - 1) arrayString += ' ';
|
||||
}
|
||||
arrayString += ']';
|
||||
return arrayString;
|
||||
}
|
||||
|
||||
sizeInBytes() {
|
||||
let size = 2;
|
||||
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
||||
size += this.get(idx).sizeInBytes();
|
||||
if (idx < len - 1) size += 1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
copyBytesInto(buffer, offset) {
|
||||
const initialOffset = offset;
|
||||
|
||||
buffer[offset++] = CharCodes.LeftSquareBracket;
|
||||
for (let idx = 0, len = this.size(); idx < len; idx++) {
|
||||
offset += this.get(idx).copyBytesInto(buffer, offset);
|
||||
if (idx < len - 1) buffer[offset++] = CharCodes.Space;
|
||||
}
|
||||
buffer[offset++] = CharCodes.RightSquareBracket;
|
||||
|
||||
return offset - initialOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import {
|
||||
DEFAULT_SIGNATURE_LENGTH,
|
||||
DEFAULT_BYTE_RANGE_PLACEHOLDER,
|
||||
SUBFILTER_ADOBE_PKCS7_DETACHED,
|
||||
ANNOTATION_FLAGS,
|
||||
SIG_FLAGS,
|
||||
SignPdfError,
|
||||
} from '@signpdf/utils';
|
||||
import {
|
||||
PDFArray,
|
||||
PDFNumber,
|
||||
PDFName,
|
||||
PDFHexString,
|
||||
PDFString,
|
||||
PDFInvalidObject,
|
||||
PDFDict,
|
||||
} from 'pdf-lib';
|
||||
|
||||
export const Placeholder = ({
|
||||
pdfDoc,
|
||||
pdfPage,
|
||||
reason,
|
||||
contactInfo,
|
||||
name,
|
||||
location,
|
||||
signingTime = new Date(),
|
||||
signatureLength = DEFAULT_SIGNATURE_LENGTH,
|
||||
byteRangePlaceholder = DEFAULT_BYTE_RANGE_PLACEHOLDER,
|
||||
subFilter = SUBFILTER_ADOBE_PKCS7_DETACHED,
|
||||
widgetRect = [0, 0, 0, 0],
|
||||
appName,
|
||||
}) => {
|
||||
if (!pdfDoc && !pdfPage) {
|
||||
throw new SignPdfError('PDFDoc or PDFPage must be set.', SignPdfError.TYPE_INPUT);
|
||||
}
|
||||
|
||||
const doc = pdfDoc || pdfPage.doc;
|
||||
const page = pdfPage || doc.getPages()[0];
|
||||
|
||||
const byteRange = PDFArray.withContext(doc.context);
|
||||
byteRange.push(PDFNumber.of(0));
|
||||
byteRange.push(PDFName.of(byteRangePlaceholder));
|
||||
byteRange.push(PDFName.of(byteRangePlaceholder));
|
||||
byteRange.push(PDFName.of(byteRangePlaceholder));
|
||||
|
||||
const placeholder = PDFHexString.of(String.fromCharCode(0).repeat(signatureLength));
|
||||
|
||||
const appBuild = appName ? { App: { Name: appName } } : {};
|
||||
const signatureDict = doc.context.obj({
|
||||
Type: 'Sig',
|
||||
Filter: 'Adobe.PPKLite',
|
||||
SubFilter: subFilter,
|
||||
ByteRange: byteRange,
|
||||
Contents: placeholder,
|
||||
Reason: PDFString.of(reason),
|
||||
M: PDFString.fromDate(signingTime),
|
||||
ContactInfo: PDFString.of(contactInfo),
|
||||
Name: PDFString.of(name),
|
||||
Location: PDFString.of(location),
|
||||
Prop_Build: {
|
||||
Filter: { Name: 'Adobe.PPKLite' },
|
||||
...appBuild,
|
||||
},
|
||||
});
|
||||
|
||||
const signatureBuffer = new Uint8Array(signatureDict.sizeInBytes());
|
||||
signatureDict.copyBytesInto(signatureBuffer, 0);
|
||||
const signatureObj = PDFInvalidObject.of(signatureBuffer);
|
||||
const signatureDictRef = doc.context.register(signatureObj);
|
||||
|
||||
const rect = PDFArray.withContext(doc.context);
|
||||
widgetRect.forEach(c => rect.push(PDFNumber.of(c)));
|
||||
const apStream = doc.context.formXObject([], {
|
||||
BBox: widgetRect,
|
||||
Resources: {},
|
||||
});
|
||||
|
||||
const widgetDict = doc.context.obj({
|
||||
Type: 'Annot',
|
||||
Subtype: 'Widget',
|
||||
FT: 'Sig',
|
||||
Rect: rect,
|
||||
V: signatureDictRef,
|
||||
T: PDFString.of('Signature1'),
|
||||
F: ANNOTATION_FLAGS.PRINT,
|
||||
P: page.ref,
|
||||
AP: { N: doc.context.register(apStream) },
|
||||
});
|
||||
|
||||
const widgetDictRef = doc.context.register(widgetDict);
|
||||
|
||||
let annotations = page.node.lookupMaybe(PDFName.of('Annots'), PDFArray);
|
||||
if (!annotations) {
|
||||
annotations = doc.context.obj([]);
|
||||
}
|
||||
annotations.push(widgetDictRef);
|
||||
page.node.set(PDFName.of('Annots'), annotations);
|
||||
|
||||
let acroForm = doc.catalog.lookupMaybe(PDFName.of('AcroForm'), PDFDict);
|
||||
if (!acroForm) {
|
||||
acroForm = doc.context.obj({ Fields: [] });
|
||||
const acroFormRef = doc.context.register(acroForm);
|
||||
doc.catalog.set(PDFName.of('AcroForm'), acroFormRef);
|
||||
}
|
||||
|
||||
let sigFlags = acroForm.has(PDFName.of('SigFlags'))
|
||||
? acroForm.get(PDFName.of('SigFlags'))
|
||||
: PDFNumber.of(0);
|
||||
|
||||
const updatedFlags = PDFNumber.of(
|
||||
sigFlags.asNumber() | SIG_FLAGS.SIGNATURES_EXIST | SIG_FLAGS.APPEND_ONLY
|
||||
);
|
||||
acroForm.set(PDFName.of('SigFlags'), updatedFlags);
|
||||
|
||||
let fields = acroForm.get(PDFName.of('Fields'));
|
||||
if (fields instanceof PDFArray) {
|
||||
fields.push(widgetDictRef);
|
||||
}
|
||||
// else if (fields) {
|
||||
// const newFields = PDFArray.withContext(doc.context);
|
||||
// fields.asArray().forEach(field => newFields.push(field));
|
||||
// newFields.push(widgetDictRef);
|
||||
// acroForm.set(PDFName.of('Fields'), newFields);
|
||||
// }
|
||||
else {
|
||||
const newFields = PDFArray.withContext(doc.context);
|
||||
newFields.push(widgetDictRef);
|
||||
acroForm.set(PDFName.of('Fields'), newFields);
|
||||
}
|
||||
};
|
||||
@@ -12,11 +12,7 @@ export default function reportJson(id, userId) {
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
SignedUrl: { $exists: false },
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
},
|
||||
keys: [
|
||||
'Name',
|
||||
@@ -29,7 +25,6 @@ export default function reportJson(id, userId) {
|
||||
'Signers.Phone',
|
||||
'Placeholders',
|
||||
'IsSignyourself',
|
||||
'FileAdapterId',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -43,19 +38,11 @@ export default function reportJson(id, userId) {
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
SignedUrl: { $ne: null },
|
||||
ExpiryDate: {
|
||||
$gt: { __type: 'Date', iso: new Date().toISOString() },
|
||||
},
|
||||
ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } },
|
||||
Placeholders: { $ne: null },
|
||||
Signers: {
|
||||
$inQuery: {
|
||||
where: {
|
||||
UserId: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
},
|
||||
where: { UserId: { __type: 'Pointer', className: '_User', objectId: currentUserId } },
|
||||
className: 'contracts_Contactbook',
|
||||
},
|
||||
},
|
||||
@@ -67,7 +54,6 @@ export default function reportJson(id, userId) {
|
||||
'URL',
|
||||
'ExtUserPtr.Name',
|
||||
'ExtUserPtr.Email',
|
||||
'ExtUserPtr.active_mail_adapter',
|
||||
'Signers.Name',
|
||||
'Signers.Email',
|
||||
'Signers.Phone',
|
||||
@@ -75,7 +61,6 @@ export default function reportJson(id, userId) {
|
||||
'AuditTrail',
|
||||
'Placeholders',
|
||||
'SignedUrl',
|
||||
'FileAdapterId',
|
||||
'ExpiryDate',
|
||||
],
|
||||
};
|
||||
@@ -90,14 +75,8 @@ export default function reportJson(id, userId) {
|
||||
IsCompleted: { $ne: true },
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
ExpiryDate: {
|
||||
$gt: { __type: 'Date', iso: new Date().toISOString() },
|
||||
},
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } },
|
||||
},
|
||||
keys: [
|
||||
'Name',
|
||||
@@ -106,7 +85,6 @@ export default function reportJson(id, userId) {
|
||||
'URL',
|
||||
'ExtUserPtr.Name',
|
||||
'ExtUserPtr.Email',
|
||||
'ExtUserPtr.active_mail_adapter',
|
||||
'Signers.Name',
|
||||
'Signers.Email',
|
||||
'Signers.Phone',
|
||||
@@ -116,7 +94,6 @@ export default function reportJson(id, userId) {
|
||||
'SendMail',
|
||||
'Placeholders',
|
||||
'SignedUrl',
|
||||
'FileAdapterId',
|
||||
],
|
||||
};
|
||||
// completed documents report
|
||||
@@ -126,13 +103,28 @@ export default function reportJson(id, userId) {
|
||||
params: {
|
||||
Type: { $ne: 'Folder' },
|
||||
IsCompleted: true,
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
// CreatedBy: {
|
||||
// __type: 'Pointer',
|
||||
// className: '_User',
|
||||
// objectId: currentUserId,
|
||||
// },
|
||||
$or: [
|
||||
// Condition 1: If `CreatedBy` exists, no need for `Signers` filter
|
||||
{ CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId } },
|
||||
// Condition 2: If `CreatedBy` does not exist, apply the `Signers` filter
|
||||
{
|
||||
Signers: {
|
||||
$inQuery: {
|
||||
where: {
|
||||
UserId: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
},
|
||||
className: 'contracts_Contactbook',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
keys: [
|
||||
'Name',
|
||||
@@ -148,7 +140,6 @@ export default function reportJson(id, userId) {
|
||||
'Placeholders',
|
||||
'IsSignyourself',
|
||||
'IsCompleted',
|
||||
'FileAdapterId',
|
||||
],
|
||||
};
|
||||
// declined documents report
|
||||
@@ -159,13 +150,8 @@ export default function reportJson(id, userId) {
|
||||
Type: null,
|
||||
IsArchive: { $ne: true },
|
||||
IsDeclined: true,
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
},
|
||||
|
||||
keys: [
|
||||
'Name',
|
||||
'Note',
|
||||
@@ -178,7 +164,6 @@ export default function reportJson(id, userId) {
|
||||
'Placeholders',
|
||||
'DeclineReason',
|
||||
'SignedUrl',
|
||||
'FileAdapterId',
|
||||
],
|
||||
};
|
||||
// Expired Documents report
|
||||
@@ -191,14 +176,8 @@ export default function reportJson(id, userId) {
|
||||
IsArchive: { $ne: true },
|
||||
Type: { $ne: 'Folder' },
|
||||
SignedUrl: { $ne: null },
|
||||
ExpiryDate: {
|
||||
$lt: { __type: 'Date', iso: new Date().toISOString() },
|
||||
},
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
ExpiryDate: { $lt: { __type: 'Date', iso: new Date().toISOString() } },
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
},
|
||||
keys: [
|
||||
'Name',
|
||||
@@ -211,7 +190,6 @@ export default function reportJson(id, userId) {
|
||||
'Signers.Phone',
|
||||
'Placeholders',
|
||||
'SignedUrl',
|
||||
'FileAdapterId',
|
||||
'ExpiryDate',
|
||||
],
|
||||
};
|
||||
@@ -226,14 +204,8 @@ export default function reportJson(id, userId) {
|
||||
IsCompleted: { $ne: true },
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
ExpiryDate: {
|
||||
$gt: { __type: 'Date', iso: new Date().toISOString() },
|
||||
},
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } },
|
||||
},
|
||||
keys: [
|
||||
'Name',
|
||||
@@ -241,7 +213,6 @@ export default function reportJson(id, userId) {
|
||||
'URL',
|
||||
'ExtUserPtr.Name',
|
||||
'ExtUserPtr.Email',
|
||||
'ExtUserPtr.active_mail_adapter',
|
||||
'Signers.Name',
|
||||
'Signers.Email',
|
||||
'Signers.Phone',
|
||||
@@ -250,7 +221,6 @@ export default function reportJson(id, userId) {
|
||||
'ExpiryDate',
|
||||
'Placeholders',
|
||||
'SignedUrl',
|
||||
'FileAdapterId',
|
||||
],
|
||||
};
|
||||
// Recent signature requests report show on dashboard
|
||||
@@ -263,19 +233,11 @@ export default function reportJson(id, userId) {
|
||||
IsCompleted: { $ne: true },
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
ExpiryDate: {
|
||||
$gt: { __type: 'Date', iso: new Date().toISOString() },
|
||||
},
|
||||
ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() } },
|
||||
Placeholders: { $ne: null },
|
||||
Signers: {
|
||||
$inQuery: {
|
||||
where: {
|
||||
UserId: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
},
|
||||
where: { UserId: { __type: 'Pointer', className: '_User', objectId: currentUserId } },
|
||||
className: 'contracts_Contactbook',
|
||||
},
|
||||
},
|
||||
@@ -285,7 +247,6 @@ export default function reportJson(id, userId) {
|
||||
'URL',
|
||||
'ExtUserPtr.Name',
|
||||
'ExtUserPtr.Email',
|
||||
'ExtUserPtr.active_mail_adapter',
|
||||
'Signers.Name',
|
||||
'Signers.UserId',
|
||||
'AuditTrail',
|
||||
@@ -293,7 +254,6 @@ export default function reportJson(id, userId) {
|
||||
'Signers.Phone',
|
||||
'Placeholders',
|
||||
'SignedUrl',
|
||||
'FileAdapterId',
|
||||
'ExpiryDate',
|
||||
],
|
||||
};
|
||||
@@ -307,11 +267,7 @@ export default function reportJson(id, userId) {
|
||||
IsDeclined: { $ne: true },
|
||||
IsArchive: { $ne: true },
|
||||
SignedUrl: { $exists: false },
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
},
|
||||
keys: [
|
||||
'Name',
|
||||
@@ -323,20 +279,15 @@ export default function reportJson(id, userId) {
|
||||
'Signers.Email',
|
||||
'Signers.Phone',
|
||||
'Placeholders',
|
||||
'FileAdapterId',
|
||||
],
|
||||
};
|
||||
// contact book report
|
||||
case '5KhaPr482K':
|
||||
case 'contacts':
|
||||
return {
|
||||
reportName: 'Contactbook',
|
||||
reportClass: 'contracts_Contactbook',
|
||||
params: {
|
||||
CreatedBy: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: currentUserId,
|
||||
},
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId },
|
||||
IsDeleted: { $ne: true },
|
||||
},
|
||||
keys: ['Name', 'Email', 'Phone'],
|
||||
@@ -346,17 +297,13 @@ export default function reportJson(id, userId) {
|
||||
return {
|
||||
reportName: 'Templates',
|
||||
reportClass: 'contracts_Template',
|
||||
params: {
|
||||
Type: { $ne: 'Folder' },
|
||||
IsArchive: { $ne: true },
|
||||
},
|
||||
params: { Type: { $ne: 'Folder' }, IsArchive: { $ne: true } },
|
||||
keys: [
|
||||
'Name',
|
||||
'Note',
|
||||
'Folder.Name',
|
||||
'URL',
|
||||
'ExtUserPtr.Name',
|
||||
'ExtUserPtr.active_mail_adapter',
|
||||
'Signers.Name',
|
||||
'Signers.Email',
|
||||
'Signers.Phone',
|
||||
@@ -364,7 +311,6 @@ export default function reportJson(id, userId) {
|
||||
'IsPublic',
|
||||
'SharedWith.Name',
|
||||
'SendinOrder',
|
||||
'FileAdapterId',
|
||||
'SignatureType',
|
||||
'NotifyOnSignatures',
|
||||
],
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import uploadFileToS3 from './uploadFiletoS3.js';
|
||||
import { parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import {
|
||||
flattenPdf,
|
||||
getSecureUrl,
|
||||
} from '../../Utils.js';
|
||||
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.');
|
||||
}
|
||||
@@ -17,111 +16,29 @@ export default async function saveFile(request) {
|
||||
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;
|
||||
let file;
|
||||
if (ext === 'pdf') {
|
||||
mimeType = 'application/pdf';
|
||||
const flatPdf = await flattenPdf(fileBase64);
|
||||
file = [...flatPdf];
|
||||
} else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') {
|
||||
mimeType = `image/${ext}`;
|
||||
file = { base64: fileBase64 };
|
||||
}
|
||||
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 });
|
||||
const pdfFile = new Parse.File(fileName, file, mimeType);
|
||||
// Save the Parse File if needed
|
||||
const pdfData = await pdfFile.save({ useMasterKey: true });
|
||||
const presignedUrl = pdfData.url();
|
||||
return { url: presignedUrl };
|
||||
}
|
||||
const fileRes = getSecureUrl(presignedUrl);
|
||||
return { url: fileRes.url };
|
||||
} 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 {
|
||||
}
|
||||
else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, planCredits } from '../../Utils.js';
|
||||
export default async function saveSubscription(request) {
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
const subscription = request.params.subscription;
|
||||
const SubscriptionId = subscription.data.subscription.subscription_id;
|
||||
const body = subscription;
|
||||
const Next_billing_date = subscription.data.subscription.next_billing_at;
|
||||
const planCode = subscription.data.subscription.plan.plan_code;
|
||||
const event = subscription?.data?.event_type || '';
|
||||
const credits = planCredits?.[planCode] || 0;
|
||||
const isTeamPlan = planCode?.includes('team');
|
||||
let newAddons = 0;
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
if (userRes.data && userRes.data.objectId) {
|
||||
const extUserCls = new Parse.Query('contracts_Users');
|
||||
extUserCls.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userRes.data.objectId,
|
||||
});
|
||||
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const subcriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||
subcriptionCls.equalTo('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
const resSubscription = await subcriptionCls.first({ useMasterKey: true });
|
||||
const addons = subscription?.data?.subscription?.addons || [];
|
||||
if (addons?.length > 0) {
|
||||
let allowedUsersMonthly = 0;
|
||||
let allowedUsersYearly = 0;
|
||||
addons?.forEach(item => {
|
||||
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||
allowedUsersYearly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-users') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
}
|
||||
});
|
||||
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||
newAddons = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
planCode === 'teams-yearly' ||
|
||||
planCode === 'teams-monthly' ||
|
||||
planCode === 'team-weekly'
|
||||
) {
|
||||
newAddons = 1; // 1 is Admin user
|
||||
}
|
||||
}
|
||||
if (resSubscription) {
|
||||
const _resSub = JSON.parse(JSON.stringify(resSubscription));
|
||||
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
updateSubscription.id = resSubscription.id;
|
||||
updateSubscription.set('SubscriptionId', SubscriptionId);
|
||||
updateSubscription.set('SubscriptionDetails', body);
|
||||
updateSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||
updateSubscription.set('PlanCode', planCode);
|
||||
if (newAddons > 0) {
|
||||
updateSubscription.set('AllowedUsers', parseInt(newAddons));
|
||||
}
|
||||
let existAddon = 0;
|
||||
let allowedUsersMonthly = 0;
|
||||
let allowedUsersYearly = 0;
|
||||
_resSub.SubscriptionDetails?.data?.subscription?.addons?.forEach(item => {
|
||||
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||
allowedUsersYearly += item.quantity;
|
||||
} else if (item.addon_code === 'extra-users') {
|
||||
allowedUsersMonthly += item.quantity;
|
||||
}
|
||||
});
|
||||
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||
existAddon = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user
|
||||
} else {
|
||||
if (
|
||||
planCode === 'teams-yearly' ||
|
||||
planCode === 'teams-monthly' ||
|
||||
planCode === 'team-weekly'
|
||||
) {
|
||||
existAddon = 1; // 1 is Admin user
|
||||
}
|
||||
}
|
||||
const isSameAsPrevPlan = resSubscription?.get('PlanCode') === planCode;
|
||||
if (isSameAsPrevPlan) {
|
||||
const planCredits = resSubscription?.get('PlanCredits');
|
||||
const existAllowedCredits = resSubscription?.get('AllowedCredits') || 0;
|
||||
if (planCredits) {
|
||||
const oldAddons = existAddon;
|
||||
const substractedAddon = newAddons - oldAddons;
|
||||
if (isTeamPlan && substractedAddon > 0) {
|
||||
const newCredits = existAllowedCredits + substractedAddon * planCredits;
|
||||
updateSubscription.set('AllowedCredits', newCredits);
|
||||
if (event === 'subscription_created') {
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
} else if (isTeamPlan) {
|
||||
const existCredits = existAddon * planCredits;
|
||||
updateSubscription.set('AllowedCredits', existCredits);
|
||||
if (event === 'subscription_created') {
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
} else {
|
||||
updateSubscription.set('AllowedCredits', planCredits);
|
||||
if (event === 'subscription_created') {
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isTeamPlan) {
|
||||
const newCredits = newAddons * credits;
|
||||
updateSubscription.set('AllowedCredits', newCredits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
} else {
|
||||
updateSubscription.set('AllowedCredits', credits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (credits > 0) {
|
||||
if (isTeamPlan) {
|
||||
const newCredits = newAddons * credits;
|
||||
updateSubscription.set('AllowedCredits', newCredits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
} else {
|
||||
updateSubscription.set('AllowedCredits', credits);
|
||||
updateSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
}
|
||||
await updateSubscription.save(null, { useMasterKey: true });
|
||||
return { status: 'update subscription!' };
|
||||
} else {
|
||||
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
createSubscription.set('SubscriptionId', SubscriptionId);
|
||||
createSubscription.set('SubscriptionDetails', body);
|
||||
createSubscription.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
createSubscription.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser.get('UserId').id,
|
||||
});
|
||||
createSubscription.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser.get('TenantId').id,
|
||||
});
|
||||
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||
createSubscription.set('PlanCode', planCode);
|
||||
if (newAddons > 0) {
|
||||
createSubscription.set('AllowedUsers', parseInt(newAddons));
|
||||
}
|
||||
if (credits > 0) {
|
||||
if (isTeamPlan) {
|
||||
const totalCredits = parseInt(newAddons) * credits;
|
||||
createSubscription.set('AllowedCredits', totalCredits);
|
||||
createSubscription.set('PlanCredits', credits);
|
||||
} else {
|
||||
createSubscription.set('AllowedCredits', credits);
|
||||
createSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
}
|
||||
await createSubscription.save(null, { useMasterKey: true });
|
||||
return { status: 'create subscription!' };
|
||||
}
|
||||
} else {
|
||||
return { status: 'user not found!' };
|
||||
}
|
||||
} else {
|
||||
return { status: 'user not found!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in save subscription', err);
|
||||
throw new Error(err.message);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
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);
|
||||
if (template?.SignatureType?.length > 0) {
|
||||
updateTemplate.set('SignatureType', template.SignatureType);
|
||||
}
|
||||
|
||||
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,
|
||||
SignatureType: request.params?.SignatureType || [],
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user