mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-19 22:25:51 +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:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import uploadFileToS3 from './uploadFiletoS3.js';
|
||||
|
||||
export default async function saveToFileAdapter(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
|
||||
if (!request.params.fileBase64) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide file.');
|
||||
}
|
||||
const fileBase64 = request.params.fileBase64;
|
||||
const id = request.params.id;
|
||||
try {
|
||||
const extCls = new Parse.Query('contracts_Users');
|
||||
extCls.equalTo('UserId', request.user);
|
||||
extCls.include('TenantId');
|
||||
const resExt = await extCls.first({ useMasterKey: true });
|
||||
if (resExt) {
|
||||
const _resExt = JSON.parse(JSON.stringify(resExt));
|
||||
const fileAdapters = _resExt?.TenantId.FileAdapters || [];
|
||||
const fileAdapter = fileAdapters?.find(x => x.id === id) || {};
|
||||
if (fileAdapter?.accessKeyId) {
|
||||
const adapterConfig = {
|
||||
id: id,
|
||||
fileAdapter: fileAdapter?.fileAdapter,
|
||||
bucketName: fileAdapter?.bucketName,
|
||||
region: fileAdapter?.region,
|
||||
endpoint: fileAdapter?.endpoint,
|
||||
accessKeyId: fileAdapter?.accessKeyId,
|
||||
secretAccessKey: fileAdapter?.secretAccessKey,
|
||||
baseUrl: fileAdapter?.baseUrl,
|
||||
};
|
||||
const buffer = Buffer.from(fileBase64, 'base64');
|
||||
const fileName = request.params.fileName;
|
||||
const ext = request.params.fileName?.split('.')?.pop();
|
||||
let mimeType;
|
||||
if (ext === 'pdf') {
|
||||
mimeType = 'application/pdf';
|
||||
} else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') {
|
||||
mimeType = `image/${ext}`;
|
||||
}
|
||||
try {
|
||||
const presignedUrl = await uploadFileToS3(buffer, fileName, mimeType, adapterConfig);
|
||||
return { url: presignedUrl };
|
||||
} catch (err) {
|
||||
console.error('Error generate presigned url:', err);
|
||||
const msg = 'Fileadapter credentials are invalid.';
|
||||
throw new Parse.Error(400, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'S3 credentials not found.');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in savetoS3', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
export default async function savewebhook(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;
|
||||
const contractuser = new Parse.Query('contracts_Users');
|
||||
contractuser.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const user = await contractuser.first({ useMasterKey: true });
|
||||
|
||||
if (user) {
|
||||
const updateUser = new Parse.Object('contracts_Users');
|
||||
updateUser.id = user.id;
|
||||
updateUser.set('Webhook', request.params.url);
|
||||
const updatedRes = await updateUser.save(null, { useMasterKey: true });
|
||||
if (updatedRes) {
|
||||
return { code: 200, Webhook: updatedRes.get('Webhook') };
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('update user', err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
import { parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
export default async function savecontact(request) {
|
||||
const name = request.params.name;
|
||||
const phone = request.params.phone;
|
||||
const email = request.params.email;
|
||||
const tenantId = request.params.tenantId;
|
||||
const jwttoken = request.headers.jwttoken;
|
||||
|
||||
if (request.user) {
|
||||
const currentUser = request?.user;
|
||||
@@ -84,97 +80,5 @@ export default async function savecontact(request) {
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
|
||||
}
|
||||
} else if (jwttoken) {
|
||||
const jwtDecode = parseJwt(jwttoken);
|
||||
const userCls = new Parse.Query(Parse.User);
|
||||
userCls.equalTo('email', jwtDecode?.user_email);
|
||||
const userRes = await userCls.first({ useMasterKey: true });
|
||||
const userId = userRes?.id;
|
||||
const tokenQuery = new Parse.Query('appToken');
|
||||
tokenQuery.equalTo('userId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
const appRes = await tokenQuery.first({ useMasterKey: true });
|
||||
const decoded = jwt.verify(jwttoken, appRes?.get('token'));
|
||||
const currentUser = userRes;
|
||||
const currentUserPtr = { __type: 'Pointer', className: '_User', objectId: userId };
|
||||
if (decoded?.user_email) {
|
||||
const query = new Parse.Query('contracts_Contactbook');
|
||||
query.equalTo('CreatedBy', currentUserPtr);
|
||||
query.notEqualTo('IsDeleted', true);
|
||||
query.equalTo('Email', email);
|
||||
const res = await query.first({ useMasterKey: true });
|
||||
if (!res) {
|
||||
const contactQuery = new Parse.Object('contracts_Contactbook');
|
||||
contactQuery.set('Name', name);
|
||||
if (phone) {
|
||||
contactQuery.set('Phone', phone);
|
||||
}
|
||||
contactQuery.set('Email', email);
|
||||
contactQuery.set('UserRole', 'contracts_Guest');
|
||||
contactQuery.set('IsDeleted', false);
|
||||
if (tenantId) {
|
||||
contactQuery.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
});
|
||||
}
|
||||
try {
|
||||
const _users = Parse.Object.extend('User');
|
||||
const _user = new _users();
|
||||
_user.set('name', name);
|
||||
_user.set('username', email);
|
||||
_user.set('email', email);
|
||||
_user.set('password', email);
|
||||
if (phone) {
|
||||
_user.set('phone', phone);
|
||||
}
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
contactQuery.set('CreatedBy', currentUserPtr);
|
||||
contactQuery.set('UserId', user);
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(user.id, true);
|
||||
acl.setWriteAccess(user.id, true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
contactQuery.setACL(acl);
|
||||
|
||||
const res = await contactQuery.save();
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
return parseData;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err ', err);
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run('getUserId', params);
|
||||
contactQuery.set('CreatedBy', currentUserPtr);
|
||||
contactQuery.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userRes.id,
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(userRes.id, true);
|
||||
acl.setWriteAccess(userRes.id, true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.save();
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
return parseData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid token.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import axios from 'axios';
|
||||
import { google } from 'googleapis';
|
||||
import fs from 'node:fs';
|
||||
import https from 'https';
|
||||
import http from 'http';
|
||||
import { useLocal } from '../../Utils.js';
|
||||
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
||||
// Function to create a Gmail client
|
||||
@@ -27,10 +25,24 @@ const refreshAccessToken = async refreshToken => {
|
||||
};
|
||||
|
||||
// Function to create a raw email message
|
||||
const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
const makeEmail = async (
|
||||
to,
|
||||
from,
|
||||
subject,
|
||||
html,
|
||||
url,
|
||||
pdfName,
|
||||
bcc,
|
||||
filename,
|
||||
certificatePath,
|
||||
replyto
|
||||
) => {
|
||||
const publicUrl = new URL(process.env.SERVER_URL);
|
||||
const htmlContent = html;
|
||||
const boundary = 'boundary_' + Date.now().toString(16);
|
||||
const bccHeader = bcc && bcc.length > 0 ? `BCC: ${bcc.join(',')}\n` : ''; // Construct BCC header if provided
|
||||
const replyToHeader = replyto ? `Reply-To: ${replyto}\n` : ''; // Construct Reply-To header if provided
|
||||
|
||||
let str;
|
||||
if (url) {
|
||||
let attachments;
|
||||
@@ -39,18 +51,24 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const isSecure =
|
||||
new URL(url)?.protocol === 'https:' && new URL(url)?.hostname !== 'localhost';
|
||||
if (useLocal !== 'true' || isSecure) {
|
||||
if (isSecure) {
|
||||
https.get(url, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
} else {
|
||||
const path = new URL(url)?.pathname;
|
||||
const localurl = 'http://localhost:8080' + path;
|
||||
http.get(localurl, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
|
||||
axios
|
||||
.get(url, { responseType: 'stream', httpsAgent })
|
||||
.then(response => {
|
||||
response.data.pipe(Pdf);
|
||||
Pdf.on('finish', () => resolve('success'));
|
||||
Pdf.on('error', () => resolve('error'));
|
||||
})
|
||||
.catch(e => {
|
||||
console.log('error', e.message);
|
||||
resolve('error');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -58,7 +76,7 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
const ress = await writeToLocalDisk();
|
||||
if (ress) {
|
||||
const file = {
|
||||
filename: `${pdfName}.pdf` || 'exported.pdf',
|
||||
filename: filename || `${pdfName}.pdf` || 'exported.pdf',
|
||||
type: 'application/pdf',
|
||||
path: Pdf.path,
|
||||
};
|
||||
@@ -68,7 +86,7 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
const certificate = {
|
||||
filename: 'certificate.pdf',
|
||||
type: 'application/pdf',
|
||||
path: './exports/certificate.pdf',
|
||||
path: certificatePath || './exports/certificate.pdf',
|
||||
};
|
||||
if (fs.existsSync(certificate.path)) {
|
||||
attachments = [file, certificate];
|
||||
@@ -99,6 +117,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
'MIME-Version: 1.0\n',
|
||||
`To: ${to}\n`,
|
||||
`From: ${from}\n`,
|
||||
bccHeader,
|
||||
replyToHeader,
|
||||
`Subject: ${subject}\n\n`,
|
||||
'--' + boundary + '\n',
|
||||
'Content-Type: text/html; charset="UTF-8"\n',
|
||||
@@ -114,6 +134,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
'MIME-Version: 1.0\n',
|
||||
`To: ${to}\n`,
|
||||
`From: ${from}\n`,
|
||||
bccHeader,
|
||||
replyToHeader,
|
||||
`Subject: ${subject}\n\n`,
|
||||
'--' + boundary + '\n',
|
||||
'Content-Type: text/html; charset="UTF-8"\n',
|
||||
@@ -127,7 +149,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||
return encodedMail;
|
||||
};
|
||||
export default async function sendMailGmailProvider(_extRes, template) {
|
||||
const { sender, receiver, subject, html, url, pdfName } = template;
|
||||
const { sender, receiver, subject, html, url, pdfName, bcc, filename, certificatePath, replyto } =
|
||||
template;
|
||||
|
||||
if (_extRes) {
|
||||
const refresh_token = _extRes.google_refresh_token;
|
||||
@@ -138,21 +161,30 @@ export default async function sendMailGmailProvider(_extRes, template) {
|
||||
// Construct email message
|
||||
const from = sender || _extRes.Email || 'me';
|
||||
const to = receiver;
|
||||
const email = await makeEmail(to, from, subject, html, url, pdfName);
|
||||
const email = await makeEmail(
|
||||
to,
|
||||
from,
|
||||
subject,
|
||||
html,
|
||||
url,
|
||||
pdfName,
|
||||
bcc,
|
||||
filename,
|
||||
certificatePath,
|
||||
replyto
|
||||
);
|
||||
// Update Gmail client with new access token
|
||||
const newGmail = createGmailClient(access_token);
|
||||
// sending email with new client
|
||||
const response = await newGmail.users.messages.send({
|
||||
userId: 'me',
|
||||
requestBody: {
|
||||
raw: email,
|
||||
},
|
||||
requestBody: { raw: email },
|
||||
});
|
||||
console.log('gmail provider res: ', response?.status);
|
||||
const certificatePath = './exports/certificate.pdf';
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
const certificatepath = certificatePath || './exports/certificate.pdf';
|
||||
if (fs.existsSync(certificatepath)) {
|
||||
try {
|
||||
fs.unlinkSync(certificatePath);
|
||||
fs.unlinkSync(certificatepath);
|
||||
} catch (err) {
|
||||
console.log('Err in unlink certificate sendmailgmail provider');
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import fs from 'node:fs';
|
||||
import https from 'https';
|
||||
import http from 'http';
|
||||
import formData from 'form-data';
|
||||
import Mailgun from 'mailgun.js';
|
||||
import { smtpenable, smtpsecure, updateMailCount, useLocal } from '../../Utils.js';
|
||||
import sendMailGmailProvider from './sendMailGmailProvider.js';
|
||||
import { smtpenable, smtpsecure, updateMailCount } from '../../Utils.js';
|
||||
import { createTransport } from 'nodemailer';
|
||||
import axios from 'axios';
|
||||
async function sendMailProvider(req, plan, monthchange) {
|
||||
const mailgunApiKey = process.env.MAILGUN_API_KEY;
|
||||
try {
|
||||
@@ -36,18 +35,29 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
const isSecure =
|
||||
new URL(req.params.url)?.protocol === 'https:' &&
|
||||
new URL(req.params.url)?.hostname !== 'localhost';
|
||||
if (useLocal !== 'true' || isSecure) {
|
||||
https.get(req.params.url, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
if (isSecure) {
|
||||
https
|
||||
.get(req.params.url, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
})
|
||||
.on('error', e => {
|
||||
console.error(`error: ${e.message}`);
|
||||
resolve('error');
|
||||
});
|
||||
} else {
|
||||
const path = new URL(req.params.url)?.pathname;
|
||||
const localurl = 'http://localhost:8080' + path;
|
||||
http.get(localurl, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
|
||||
axios
|
||||
.get(req.params.url, { responseType: 'stream', httpsAgent })
|
||||
.then(response => {
|
||||
response.data.pipe(Pdf);
|
||||
Pdf.on('finish', () => resolve('success'));
|
||||
Pdf.on('error', () => resolve('error'));
|
||||
})
|
||||
.catch(e => {
|
||||
console.log('error', e.message);
|
||||
resolve('error');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -65,14 +75,15 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
// `PdfBuffer` used to create buffer from pdf file
|
||||
let PdfBuffer = await readTolocal();
|
||||
const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`;
|
||||
const filename = req.params.filename;
|
||||
const file = {
|
||||
filename: pdfName || 'exported.pdf',
|
||||
filename: filename || pdfName || 'exported.pdf',
|
||||
content: smtpenable ? PdfBuffer : undefined,
|
||||
data: smtpenable ? undefined : PdfBuffer,
|
||||
};
|
||||
|
||||
let attachment;
|
||||
const certificatePath = './exports/certificate.pdf';
|
||||
const certificatePath = req.params.certificatePath || `./exports/certificate.pdf`;
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
try {
|
||||
// `certificateBuffer` used to create buffer from pdf file
|
||||
@@ -92,7 +103,7 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
}
|
||||
const from = req.params.from || '';
|
||||
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
||||
|
||||
const replyto = req.params?.replyto || '';
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: req.params.recipient,
|
||||
@@ -101,6 +112,8 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
html: req.params.html || '',
|
||||
attachments: smtpenable ? attachment : undefined,
|
||||
attachment: smtpenable ? undefined : attachment,
|
||||
bcc: req.params.bcc ? req.params.bcc : undefined,
|
||||
replyTo: replyto ? replyto : undefined,
|
||||
};
|
||||
if (transporterSMTP) {
|
||||
const res = await transporterSMTP.sendMail(messageParams);
|
||||
@@ -150,13 +163,15 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
} else {
|
||||
const from = req.params.from || '';
|
||||
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
||||
|
||||
const replyto = req.params?.replyto || '';
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: req.params.recipient,
|
||||
subject: req.params.subject,
|
||||
text: req.params.text || 'mail',
|
||||
html: req.params.html || '',
|
||||
bcc: req.params.bcc ? req.params.bcc : undefined,
|
||||
replyTo: replyto ? replyto : undefined,
|
||||
};
|
||||
|
||||
if (transporterSMTP) {
|
||||
@@ -190,189 +205,10 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
}
|
||||
}
|
||||
}
|
||||
async function sendcustomsmtp(extRes, req) {
|
||||
const smtpsecure = extRes.SmtpConfig.port !== '465' ? false : true;
|
||||
const transporterSMTP = createTransport({
|
||||
host: extRes.SmtpConfig.host,
|
||||
port: extRes.SmtpConfig.port,
|
||||
secure: smtpsecure,
|
||||
auth: { user: extRes.SmtpConfig.username, pass: extRes.SmtpConfig.password },
|
||||
});
|
||||
if (req.params.url) {
|
||||
let Pdf = fs.createWriteStream('test.pdf');
|
||||
const writeToLocalDisk = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const isSecure =
|
||||
new URL(req.params.url)?.protocol === 'https:' &&
|
||||
new URL(req.params.url)?.hostname !== 'localhost';
|
||||
if (useLocal !== 'true' || isSecure) {
|
||||
https.get(req.params.url, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
} else {
|
||||
const path = new URL(req.params.url)?.pathname;
|
||||
const localurl = 'http://localhost:8080' + path;
|
||||
http.get(localurl, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// `writeToLocalDisk` is used to create pdf file from doc url
|
||||
const ress = await writeToLocalDisk();
|
||||
if (ress) {
|
||||
function readTolocal() {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
let PdfBuffer = fs.readFileSync(Pdf.path);
|
||||
resolve(PdfBuffer);
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
// `PdfBuffer` used to create buffer from pdf file
|
||||
let PdfBuffer = await readTolocal();
|
||||
const pdfName = req.params.pdfName ? `${req.params.pdfName}.pdf` : 'exported.pdf';
|
||||
const file = { filename: pdfName, content: PdfBuffer };
|
||||
let attachment;
|
||||
const certificatePath = './exports/certificate.pdf';
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
try {
|
||||
// `certificateBuffer` used to create buffer from pdf file
|
||||
const certificateBuffer = fs.readFileSync(certificatePath);
|
||||
const certificate = { filename: 'certificate.pdf', content: certificateBuffer };
|
||||
attachment = [file, certificate];
|
||||
} catch (err) {
|
||||
attachment = [file];
|
||||
console.log('Err in read certificate sendmailv3', err);
|
||||
}
|
||||
} else {
|
||||
attachment = [file];
|
||||
}
|
||||
const from = req.params.from || '';
|
||||
const mailsender = extRes.SmtpConfig.username;
|
||||
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: req.params.recipient,
|
||||
subject: req.params.subject,
|
||||
text: req.params.text || 'mail',
|
||||
html: req.params.html || '',
|
||||
attachments: attachment,
|
||||
};
|
||||
const res = await transporterSMTP.sendMail(messageParams);
|
||||
console.log('custom smtp transporter res: ', res?.response);
|
||||
if (!res.err) {
|
||||
if (req.params?.extUserId) {
|
||||
await updateMailCount(req.params.extUserId); //, plan, monthchange
|
||||
}
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
try {
|
||||
fs.unlinkSync(certificatePath);
|
||||
} catch (err) {
|
||||
console.log('Err in unlink certificate sendmailv3');
|
||||
}
|
||||
}
|
||||
return { status: 'success', code: 200 };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const from = req.params.from || '';
|
||||
const mailsender = extRes.SmtpConfig.username;
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: req.params.recipient,
|
||||
subject: req.params.subject,
|
||||
text: req.params.text || 'mail',
|
||||
html: req.params.html || '',
|
||||
};
|
||||
|
||||
const res = await transporterSMTP.sendMail(messageParams);
|
||||
console.log('custom smtp transporter res: ', res?.response);
|
||||
if (!res.err) {
|
||||
if (req.params?.extUserId) {
|
||||
await updateMailCount(req.params.extUserId); //, plan, monthchange
|
||||
}
|
||||
return { status: 'success', code: 200 };
|
||||
}
|
||||
}
|
||||
}
|
||||
async function sendmailv3(req) {
|
||||
const mailProvider = req.params.mailProvider || 'default';
|
||||
if (mailProvider) {
|
||||
try {
|
||||
const Plan = req.params.plan;
|
||||
const extUserId = req.params.extUserId || '';
|
||||
const pdfName = req.params.pdfName || '';
|
||||
const template = {
|
||||
sender: req.params.from || '',
|
||||
receiver: req.params.recipient,
|
||||
subject: req.params.subject,
|
||||
html: req.params.html || '',
|
||||
url: req.params.url ? req.params.url : '',
|
||||
pdfName: pdfName,
|
||||
};
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
const extRes = await extUserQuery.get(extUserId, { useMasterKey: true });
|
||||
if (extRes) {
|
||||
const _extRes = JSON.parse(JSON.stringify(extRes));
|
||||
if (
|
||||
_extRes.active_mail_adapter === 'google' &&
|
||||
_extRes.google_refresh_token &&
|
||||
mailProvider === 'google'
|
||||
) {
|
||||
const res = await sendMailGmailProvider(_extRes, template);
|
||||
if (res.code === 200) {
|
||||
await updateMailCount(req.params.extUserId);
|
||||
return { status: 'success' };
|
||||
} else {
|
||||
return { status: 'error' };
|
||||
}
|
||||
} else if (_extRes.active_mail_adapter === 'smtp' && mailProvider === 'smtp') {
|
||||
const res = await sendcustomsmtp(_extRes, req);
|
||||
if (res.code === 200) {
|
||||
await updateMailCount(req.params.extUserId);
|
||||
return { status: 'success' };
|
||||
} else {
|
||||
return { status: 'error' };
|
||||
}
|
||||
} else {
|
||||
if (Plan && Plan === 'freeplan') {
|
||||
let MonthlyFreeEmails = _extRes?.MonthlyFreeEmails || 0;
|
||||
if (_extRes?.LastEmailCountReset?.iso) {
|
||||
const lastDate = new Date(_extRes?.LastEmailCountReset?.iso);
|
||||
const newDate = new Date();
|
||||
const isMonthChange = newDate.getMonth() > lastDate.getMonth();
|
||||
if (isMonthChange) {
|
||||
const nonCustomMail = await sendMailProvider(req, Plan, true);
|
||||
return nonCustomMail;
|
||||
} else {
|
||||
if (MonthlyFreeEmails >= 15) {
|
||||
return { status: 'quota-reached' };
|
||||
} else {
|
||||
const nonCustomMail = await sendMailProvider(req, Plan);
|
||||
return nonCustomMail;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const nonCustomMail = await sendMailProvider(req, Plan);
|
||||
return nonCustomMail;
|
||||
}
|
||||
} else {
|
||||
const nonCustomMail = await sendMailProvider(req, '');
|
||||
return nonCustomMail;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in send custom mail', err);
|
||||
return { status: 'error' };
|
||||
}
|
||||
} else {
|
||||
const nonCustomMail = await sendMailProvider(req);
|
||||
return nonCustomMail;
|
||||
}
|
||||
}
|
||||
|
||||
export default sendmailv3;
|
||||
|
||||
@@ -1,133 +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;
|
||||
const clientUrl = process.env.PUBLIC_URL;
|
||||
const ssoApiUrl = process.env.SSO_API_URL || 'https://sso.opensignlabs.com/api'; //'https://osl-jacksonv2.vercel.app/api';
|
||||
/**
|
||||
* ssoSign is function which is used to sign up/sign in with SSO
|
||||
* @param code It is code return by jackson using authorize endpoint
|
||||
* @param email It is user's email with user sign in/sign up
|
||||
* @returns if success {email, name, phone message, sessiontoken} else on reject error {code, message}
|
||||
*/
|
||||
|
||||
export default async function ssoSignin(request) {
|
||||
const code = request.params.code;
|
||||
const userEmail = request.params.email;
|
||||
try {
|
||||
const headers = { 'content-type': 'application/x-www-form-urlencoded' };
|
||||
const axiosRes = await axios.post(
|
||||
ssoApiUrl + '/oauth/token',
|
||||
{
|
||||
grant_type: 'authorization_code',
|
||||
client_id: 'dummy',
|
||||
tenant: 'Okta-dev-nxglabs-in',
|
||||
product: 'OpenSign',
|
||||
client_secret: 'dummy',
|
||||
redirect_uri: clientUrl + '/sso',
|
||||
code: code,
|
||||
},
|
||||
{ headers: headers }
|
||||
);
|
||||
const ssoAccessToken = axiosRes.data && axiosRes.data.access_token;
|
||||
const authData = { sso: { id: userEmail, access_token: ssoAccessToken } };
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('username', 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) {
|
||||
const response = await axios.get(ssoApiUrl + '/oauth/userinfo', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${ssoAccessToken}`,
|
||||
},
|
||||
});
|
||||
const sessiontoken = SignIn.data.sessionToken;
|
||||
// console.log('sso sessiontoken', sessiontoken);
|
||||
const payload = {
|
||||
email: userEmail,
|
||||
name: response.data?.firstName + ' ' + response.data?.lastName,
|
||||
phone: response?.data?.phone || '',
|
||||
message: 'User Sign In',
|
||||
sessiontoken: sessiontoken,
|
||||
};
|
||||
return payload;
|
||||
}
|
||||
} catch (err) {
|
||||
const errCode = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||
const message =
|
||||
err?.response?.data?.error ||
|
||||
err?.response?.data ||
|
||||
err?.message ||
|
||||
'Internal server error.';
|
||||
console.log('err in user sso sign in', errCode, message);
|
||||
throw new Parse.Error(errCode, message);
|
||||
}
|
||||
} else {
|
||||
// console.log("in sign up condition");
|
||||
const response = await axios.get(ssoApiUrl + '/oauth/userinfo', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${ssoAccessToken}`,
|
||||
},
|
||||
});
|
||||
if (response.data && response.data.id) {
|
||||
try {
|
||||
const SignUp = await axios.post(
|
||||
serverUrl + '/users',
|
||||
{
|
||||
authData: authData,
|
||||
username: response.data.email,
|
||||
email: response.data.email,
|
||||
phone: response.data?.phone,
|
||||
name: response.data?.firstName + ' ' + response.data?.lastName,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Revocable-Session': '1',
|
||||
},
|
||||
}
|
||||
);
|
||||
if (SignUp.data) {
|
||||
const sessiontoken = SignUp.data.sessionToken;
|
||||
const payload = {
|
||||
email: userEmail,
|
||||
name: SignUp?.data?.name,
|
||||
phone: SignUp?.data?.phone || '',
|
||||
message: 'User Sign Up',
|
||||
sessiontoken: sessiontoken,
|
||||
};
|
||||
return payload;
|
||||
}
|
||||
} catch (err) {
|
||||
const errCode = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||
const message =
|
||||
err?.response?.data?.error ||
|
||||
err?.response?.data ||
|
||||
err?.message ||
|
||||
'Internal server error.';
|
||||
console.log('err in user sso sign up', errCode, message);
|
||||
throw new Parse.Error(errCode, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const errCode = err?.response?.status || err?.code || 400;
|
||||
const message = err?.response?.data || err?.message || 'Internal server error.';
|
||||
console.log('err in ssoSign', errCode, message);
|
||||
throw new Parse.Error(errCode, message);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
export default async function updateOrganization(request) {
|
||||
const orgId = request.params.orgId;
|
||||
const isactive = request.params.isactive;
|
||||
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('objectId', orgId);
|
||||
orgQuery.equalTo('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
const resOrg = await orgQuery.first({ useMasterKey: true });
|
||||
if (resOrg) {
|
||||
const newOrg = new Parse.Object('contracts_Organizations');
|
||||
newOrg.id = orgId;
|
||||
newOrg.set('IsActive', isactive);
|
||||
const newResOrg = await newOrg.save(null, { useMasterKey: true });
|
||||
if (newResOrg) {
|
||||
return newResOrg;
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.');
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ export default async function updatePreferences(request) {
|
||||
}
|
||||
const SignatureType = request.params.SignatureType || [];
|
||||
const NotifyOnSignatures = request.params.NotifyOnSignatures;
|
||||
if (SignatureType?.length > 0 || NotifyOnSignatures !== undefined) {
|
||||
const Timezone = request.params.Timezone;
|
||||
if (SignatureType?.length > 0 || NotifyOnSignatures !== undefined || Timezone) {
|
||||
try {
|
||||
const orgQuery = new Parse.Query('contracts_Users');
|
||||
orgQuery.equalTo('UserId', {
|
||||
@@ -19,6 +20,9 @@ export default async function updatePreferences(request) {
|
||||
if (NotifyOnSignatures !== undefined) {
|
||||
newOrg.set('NotifyOnSignatures', NotifyOnSignatures);
|
||||
}
|
||||
if (Timezone) {
|
||||
newOrg.set('Timezone', Timezone);
|
||||
}
|
||||
if (SignatureType.length > 0) {
|
||||
const enabledSignTypes = SignatureType?.filter(x => x.enabled);
|
||||
const isDefaultSignTypeOnly =
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
export default async function updateTeam(request) {
|
||||
const TeamId = request.params.TeamId;
|
||||
const IsActive = request.params.IsActive;
|
||||
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 });
|
||||
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('objectId', TeamId);
|
||||
teamCls.equalTo('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: extUser.OrganizationId.objectId,
|
||||
});
|
||||
const teamRes = await teamCls.first({ useMasterKey: true });
|
||||
if (teamRes) {
|
||||
const updateteam = new Parse.Object('contracts_Teams');
|
||||
updateteam.id = TeamId;
|
||||
if (Name) {
|
||||
updateteam.set('Name', Name);
|
||||
}
|
||||
if (IsActive) {
|
||||
const active = IsActive === 'false' ? false : true;
|
||||
updateteam.set('IsActive', active);
|
||||
}
|
||||
const updateTeamRes = await updateteam.save(null, { useMasterKey: true });
|
||||
return updateTeamRes;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.');
|
||||
}
|
||||
} 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,73 +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;
|
||||
|
||||
const isPublic = template?.IsPublic !== undefined ? template?.IsPublic : false;
|
||||
if (template?.IsPublic !== undefined) {
|
||||
updateTemplate.set('IsPublic', isPublic);
|
||||
updateTemplate.set('PublicRole', template.PublicRole);
|
||||
}
|
||||
|
||||
let updateTemplateRes;
|
||||
if (isJwt) {
|
||||
updateTemplateRes = await updateTemplate.save(null, { useMasterKey: true });
|
||||
} else {
|
||||
updateTemplateRes = await updateTemplate.save();
|
||||
}
|
||||
return updateTemplateRes;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide Id.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in update template', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
export default async function updateToPublicTemplate(request) {
|
||||
const jwttoken = request.headers.jwttoken || '';
|
||||
const Role = request.params.Role;
|
||||
if (!Role) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide public role.');
|
||||
}
|
||||
const PublicRole = [Role];
|
||||
const template = {
|
||||
Id: request.params.templateId,
|
||||
IsPublic: request.params?.IsPublic,
|
||||
PublicRole: PublicRole,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import { parseJwt } from '../../Utils.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
export default async function updateTourStatus(request) {
|
||||
const tourstatus = request.params.TourStatus;
|
||||
const extUserId = request.params.ExtUserId;
|
||||
const jwttoken = request?.headers?.jwttoken || '';
|
||||
|
||||
if (request.user) {
|
||||
try {
|
||||
const updateUser = new Parse.Object('contracts_Users');
|
||||
@@ -18,41 +15,8 @@ export default async function updateTourStatus(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 updateUser = new Parse.Object('contracts_Users');
|
||||
updateUser.id = extUserId;
|
||||
updateUser.set('TourStatus', tourstatus);
|
||||
const res = await updateUser.save(null, { useMasterKey: true });
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.log('Err ', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid token!' };
|
||||
}
|
||||
} else {
|
||||
return { status: 'error', result: 'Invalid token!' };
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import * as crypto from 'node:crypto';
|
||||
async function uploadFileToS3(buffer, fileName, mimeType, adapter) {
|
||||
const bucketName = adapter?.bucketName;
|
||||
let client;
|
||||
if (adapter?.fileAdapter === 'digitalocean') {
|
||||
client = new S3Client({
|
||||
endpoint: adapter?.endpoint,
|
||||
region: adapter?.region,
|
||||
credentials: { accessKeyId: adapter?.accessKeyId, secretAccessKey: adapter?.secretAccessKey },
|
||||
});
|
||||
} else {
|
||||
client = new S3Client({
|
||||
region: adapter?.region,
|
||||
credentials: { accessKeyId: adapter?.accessKeyId, secretAccessKey: adapter?.secretAccessKey },
|
||||
signatureVersion: 'v4'
|
||||
});
|
||||
}
|
||||
const prefixId = crypto.randomBytes(16).toString('hex');
|
||||
const fileKey = `${prefixId}_${fileName}`;
|
||||
const uploadParams = { Bucket: bucketName, Key: fileKey, Body: buffer, ContentType: mimeType };
|
||||
|
||||
try {
|
||||
// Upload the buffer to the Space
|
||||
const command = new PutObjectCommand(uploadParams);
|
||||
await client.send(command);
|
||||
const getCommand = new GetObjectCommand({ Bucket: bucketName, Key: fileKey });
|
||||
|
||||
// Generate a presigned URL for the uploaded file
|
||||
const presignedUrl = await getSignedUrl(client, getCommand, { expiresIn: 900 }); // URL expiration time in seconds (e.g., 15 min)
|
||||
return presignedUrl;
|
||||
} catch (error) {
|
||||
console.error('Error uploading file to aws:', error?.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export default uploadFileToS3;
|
||||
@@ -1,5 +1,7 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl, planCredits } from '../../Utils.js';
|
||||
import {
|
||||
cloudServerUrl,
|
||||
} from '../../Utils.js';
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
@@ -43,7 +45,6 @@ async function saveUser(userDetails) {
|
||||
}
|
||||
export default async function usersignup(request) {
|
||||
const userDetails = request.params.userDetails;
|
||||
const subscription = request.params.subscription;
|
||||
const user = await saveUser(userDetails);
|
||||
|
||||
try {
|
||||
@@ -120,10 +121,10 @@ export default async function usersignup(request) {
|
||||
if (userDetails && userDetails.jobTitle) {
|
||||
newObj.set('JobTitle', userDetails.jobTitle);
|
||||
}
|
||||
const extRes = await newObj.save(null, { useMasterKey: true });
|
||||
if (subscription) {
|
||||
await saveSubscription(extRes.id, user.id, tenantRes.id, subscription);
|
||||
if (userDetails && userDetails?.timezone) {
|
||||
newObj.set('Timezone', userDetails.timezone);
|
||||
}
|
||||
const extRes = await newObj.save(null, { useMasterKey: true });
|
||||
return { message: 'User sign up', sessionToken: user.sessionToken };
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -131,39 +132,3 @@ export default async function usersignup(request) {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSubscription(extUserId, UserId, tenantId, subscription) {
|
||||
const SubscriptionId = subscription?.data?.subscription?.subscription_id || '';
|
||||
const Next_billing_date = subscription?.data?.subscription?.next_billing_at || '';
|
||||
const planCode = subscription?.data?.subscription?.plan?.plan_code || '';
|
||||
const credits = planCredits?.[planCode] || 0;
|
||||
|
||||
try {
|
||||
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
createSubscription.set('SubscriptionId', SubscriptionId);
|
||||
createSubscription.set('SubscriptionDetails', subscription);
|
||||
createSubscription.set('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUserId,
|
||||
});
|
||||
createSubscription.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: UserId,
|
||||
});
|
||||
createSubscription.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
});
|
||||
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||
createSubscription.set('PlanCode', planCode);
|
||||
if (credits > 0) {
|
||||
createSubscription.set('AllowedCredits', credits);
|
||||
createSubscription.set('PlanCredits', credits);
|
||||
}
|
||||
await createSubscription.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err in save subscription pgsignup', err);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user