This commit is contained in:
prafull-opensignlabs
2026-01-07 09:40:36 +00:00
parent bce0e4971e
commit eb8e7b089b
73 changed files with 20018 additions and 2260 deletions
@@ -2,59 +2,23 @@ async function DocumentAftersave(request) {
try {
if (!request.original) {
console.log('new entry is insert in contracts_Document');
const createdAt = request.object.get('createdAt');
const Folder = request.object.get('Type');
const obj = request.object;
const objId = obj?.id;
const createdAt = obj?.get?.('createdAt');
const folder = obj?.get?.('Type');
const ip = request?.headers?.['x-real-ip'] || '';
const originIp = request?.object?.get('OriginIp') || '';
if (createdAt && Folder === undefined) {
// console.log("IN If condition")
const TimeToCompleteDays = request.object.get('TimeToCompleteDays') || 15;
const ExpiryDate = new Date(createdAt);
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
const documentQuery = new Parse.Query('contracts_Document');
documentQuery.include('ExtUserPtr.TenantId');
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
updateQuery.set('ExpiryDate', ExpiryDate);
if (!originIp) {
updateQuery.set('OriginIp', ip);
}
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
if (AutoReminder) {
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
const ReminderDate = new Date(createdAt);
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
updateQuery.set('NextReminderDate', ReminderDate);
}
await updateQuery.save(null, { useMasterKey: true });
} else if (createdAt && Folder === 'AIDoc') {
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
const ExpiryDate = new Date(createdAt);
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
const documentQuery = new Parse.Query('contracts_Document');
documentQuery.include('ExtUserPtr.TenantId');
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
updateQuery.set('ExpiryDate', ExpiryDate);
if (!originIp) {
updateQuery.set('OriginIp', ip);
}
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
if (AutoReminder) {
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
const ReminderDate = new Date(createdAt);
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
updateQuery.set('NextReminderDate', ReminderDate);
}
await updateQuery.save(null, { useMasterKey: true });
const originIp = obj?.get?.('OriginIp') || '';
if (createdAt) {
await updateDocumentMeta({ objId, createdAt, folder, ip, originIp });
}
const signers = request.object.get('Signers');
const signers = obj?.get?.('Signers');
const hasSigners = Array.isArray(signers) && signers.length > 0;
// update acl of New Document If There are signers present in array
if (signers && signers.length > 0) {
await updateAclDoc(request.object.id);
} else {
if (request?.object?.id && request.user) {
await updateSelfDoc(request.object.id);
}
if (hasSigners) {
await updateAclDoc(objId);
} else if (objId && request?.user) {
await updateSelfDoc(objId);
}
} else {
if (request?.user) {
@@ -73,17 +37,49 @@ async function DocumentAftersave(request) {
console.log(err);
}
async function updateDocumentMeta({ objId, createdAt, folder, ip, originIp }) {
const documentQuery = new Parse.Query('contracts_Document');
documentQuery.include('ExtUserPtr.TenantId');
const doc = await documentQuery.get(objId, { useMasterKey: true });
if (folder === undefined || folder === 'AIDoc') {
// ExpiryDate
const timeToCompleteDays =
folder === undefined
? doc.get('TimeToCompleteDays') || 15 // keep your default=15 only for "undefined folder"
: doc.get('TimeToCompleteDays'); // keep original behavior for AIDoc (no forced default)
if (typeof timeToCompleteDays === 'number' && createdAt) {
const expiryDate = new Date(createdAt);
expiryDate.setDate(expiryDate.getDate() + timeToCompleteDays);
doc.set('ExpiryDate', expiryDate);
}
// OriginIp
if (!originIp) {
doc.set('OriginIp', ip);
}
// Automatic reminders
const autoReminder = doc.get('AutomaticReminders') || false;
if (autoReminder && createdAt) {
const remindOnceInEvery = doc.get('RemindOnceInEvery') || 5;
const reminderDate = new Date(createdAt);
reminderDate.setDate(reminderDate.getDate() + remindOnceInEvery);
doc.set('NextReminderDate', reminderDate);
}
}
await doc.save(null, { useMasterKey: true });
}
async function updateAclDoc(objId) {
// console.log("In side updateAclDoc func")
// console.log(objId)
const Query = new Parse.Query('contracts_Document');
Query.include('Signers');
Query.include('ExtUserPtr.TenantId');
Query.include('CreatedBy');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const UsersPtr = res.Signers.map(item => item.UserId);
if (res.Signers[0].ExtUserPtr) {
@@ -97,8 +93,6 @@ async function DocumentAftersave(request) {
updateACL.set('Signers', ExtUserSigners);
}
// console.log("UsersPtr")
// console.log(JSON.stringify(UsersPtr))
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
@@ -116,14 +110,11 @@ async function DocumentAftersave(request) {
}
async function updateSelfDoc(objId) {
// console.log(objId)
const Query = new Parse.Query('contracts_Document');
Query.include('CreatedBy');
Query.include('ExtUserPtr.TenantId');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
@@ -1,4 +1,5 @@
import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
import { setDocumentCount } from '../../utils/CountUtils.js';
async function DocumentBeforesave(request) {
if (!request.original) {
@@ -33,24 +34,8 @@ async function DocumentBeforesave(request) {
// Check if SignedUrl field has been added (transition from undefined to defined)
if (oldDocument && !oldDocument?.get('SignedUrl') && document?.get('SignedUrl')) {
// Update count in contracts_Users class
const query = new Parse.Query('contracts_Users');
query.equalTo('objectId', oldDocument.get('ExtUserPtr').id);
try {
const contractUser = await query.first({ useMasterKey: true });
if (contractUser) {
contractUser.increment('DocumentCount', 1);
await contractUser.save(null, { useMasterKey: true });
} else {
// Create new entry if not found
const ContractsUsers = Parse.Object.extend('contracts_Users');
const newContractUser = new ContractsUsers();
newContractUser.set('DocumentCount', 1);
await newContractUser.save(null, { useMasterKey: true });
}
} catch (error) {
console.log('Error updating document count in contracts_Users: ' + error.message);
if (oldDocument?.get('ExtUserPtr')?.id) {
setDocumentCount(oldDocument?.get('ExtUserPtr')?.id);
}
if (document?.get('Signers') && document.get('Signers').length > 0) {
document.set('DocSentAt', new Date());
@@ -36,7 +36,7 @@ export default async function forwardDoc(request) {
let mailRes;
for (let i = 0; i < recipients.length; i++) {
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>`;
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
const themeColor = '#47a3ad';
let params = {
@@ -52,7 +52,7 @@ export default async function forwardDoc(request) {
`${logo}</div><div style='padding:2px;font-family:system-ui;background-color:${themeColor}'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document Copy</p></div><div>` +
`<p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>${docName}</strong> is attached to this email. Kindly download the document from the attachment.</p>` +
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`,
`If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`,
};
mailRes = await axios.post(`${cloudServerUrl}/functions/sendmailv3`, params, {
headers: {
@@ -2,27 +2,20 @@ export default async function TemplateAfterSave(request) {
try {
if (!request.original) {
console.log('new entry is insert in contracts_Template');
// update acl of New Document If There are signers present in array
const signers = request.object.get('Signers');
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
const obj = request.object;
const objId = obj?.id;
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);
}
if (!originIp) {
request.object.set('OriginIp', ip);
}
await request.object.save(null, { useMasterKey: true });
if (signers && signers.length > 0) {
await updateAclDoc(request.object.id);
} else {
if (request?.object?.id && request?.user) {
await updateSelfDoc(request.object.id);
}
const originIp = obj?.get?.('OriginIp') || '';
const createdAt = obj?.get?.('createdAt');
// update acl of New template If There are signers present in array
const signers = obj?.get('Signers');
const hasSigners = Array.isArray(signers) && signers.length > 0;
updateTemplateMeta({ objId, createdAt, ip, originIp });
if (hasSigners) {
await updateAclDoc(objId);
} else if (objId && request?.user) {
await updateSelfDoc(objId);
}
} else {
if (request?.user) {
@@ -41,17 +34,33 @@ export default async function TemplateAfterSave(request) {
console.log(err);
}
async function updateTemplateMeta({ objId, createdAt, ip, originIp }) {
const templateQuery = new Parse.Query('contracts_Template');
templateQuery.include('ExtUserPtr.TenantId');
const obj = await templateQuery.get(objId, { useMasterKey: true });
// Automatic reminders
const AutoReminder = obj?.get('AutomaticReminders') || false;
if (AutoReminder) {
const RemindOnceInEvery = obj?.get('RemindOnceInEvery') || 5;
const ReminderDate = new Date(createdAt);
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
obj.set('NextReminderDate', ReminderDate);
}
if (!originIp) {
obj.set('OriginIp', ip);
}
await obj.save(null, { useMasterKey: true });
}
async function updateAclDoc(objId) {
// console.log("In side updateAclDoc func")
// console.log(objId)
const Query = new Parse.Query('contracts_Template');
Query.include('Signers');
Query.include('CreatedBy');
Query.include('ExtUserPtr.TenantId');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const UsersPtr = res.Signers.map(item => item.UserId);
if (res.Signers[0].ExtUserPtr) {
@@ -65,8 +74,6 @@ export default async function TemplateAfterSave(request) {
updateACL.set('Signers', ExtUserSigners);
}
// console.log("UsersPtr")
// console.log(JSON.stringify(UsersPtr))
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
@@ -85,15 +92,11 @@ export default async function TemplateAfterSave(request) {
}
async function updateSelfDoc(objId) {
// console.log("Inside updateSelfDoc func")
const Query = new Parse.Query('contracts_Template');
Query.include('CreatedBy');
Query.include('ExtUserPtr.TenantId');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
@@ -1,4 +1,5 @@
import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
import { setTemplateCount } from '../../utils/CountUtils.js';
async function TemplateBeforeSave(request) {
if (!request.original) {
@@ -31,24 +32,8 @@ async function TemplateBeforeSave(request) {
// below code is used to update template when user sent template or self signed
const template = request.object;
// Update count in contracts_Users class
const query = new Parse.Query('contracts_Users');
query.equalTo('objectId', template.get('ExtUserPtr').id);
try {
const contractUser = await query.first({ useMasterKey: true });
if (contractUser) {
contractUser.increment('TemplateCount', 1);
await contractUser.save(null, { useMasterKey: true });
} else {
// Create new entry if not found
const ContractsUsers = Parse.Object.extend('contracts_Users');
const newContractUser = new ContractsUsers();
newContractUser.set('TemplateCount', 1);
await newContractUser.save(null, { useMasterKey: true });
}
} catch (error) {
console.log('Error updating template count in contracts_Users: ' + error.message);
if (template?.get('ExtUserPtr')?.id) {
setTemplateCount(template?.get('ExtUserPtr')?.id);
}
}
} catch (err) {
@@ -1,13 +1,14 @@
import axios from 'axios';
import { cloudServerUrl, mailTemplate, replaceMailVaribles, serverAppId } from '../../Utils.js';
import { setDocumentCount } from '../../utils/CountUtils.js';
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = serverAppId;
async function deductcount(docsCount, extUserId) {
try {
const extCls = new Parse.Object('contracts_Users');
extCls.id = extUserId;
extCls.increment('DocumentCount', docsCount);
const resExt = await extCls.save(null, { useMasterKey: true });
if (extUserId) {
setDocumentCount(extUserId);
}
} catch (err) {
console.log('Err in deduct in quick send', err);
}
@@ -14,7 +14,7 @@ async function sendDeclineMail(doc, publicUrl, userId, reason) {
const TenantAppName = appName;
const logo =
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
const removePrefill =
doc?.Placeholders?.length > 0 && doc?.Placeholders?.filter(x => x?.Role !== 'prefill');
const signUser =
@@ -36,7 +36,7 @@ async function sendDeclineMail(doc, publicUrl, userId, reason) {
`<p>${pdfName} has been declined by ${signerName} "${signerEmail}" on ${new Date().toLocaleDateString()}.</p>` +
`<p>Decline Reason: ${reason || 'Not specified'}</p>` +
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
const params = {
extUserId: sender.objectId,
@@ -1,12 +1,16 @@
import { cloudServerUrl, serverAppId } from '../../Utils.js';
import reportJson from './reportsJson.js';
import reportJson, { applySearch } from './reportsJson.js';
import axios from 'axios';
// Escape regex special characters. Copied from filterDocs.js
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
function buildClassesUrl({ serverUrl, clsName, paramsObj, keys, orderBy, skip, limit, include }) {
const url = new URL(`${serverUrl}/classes/${clsName}`);
url.searchParams.set('where', JSON.stringify(paramsObj));
url.searchParams.set('keys', keys.join(','));
url.searchParams.set('order', orderBy);
url.searchParams.set('skip', String(skip));
url.searchParams.set('limit', String(limit));
if (include) url.searchParams.set('include', include);
return url.toString();
}
export default async function getReport(request) {
const reportId = request.params.reportId;
const limit = request.params.limit;
@@ -25,78 +29,76 @@ export default async function getReport(request) {
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const json = reportId && reportJson(reportId, userId);
const clsName = json?.reportClass ? json.reportClass : 'contracts_Document';
if (json) {
const { params, keys } = json;
const orderBy = '-updatedAt';
const strKeys = keys.join();
let paramsObj = { ...params };
if (reportId == '6TeaPr321t') {
const extUserQuery = new Parse.Query('contracts_Users');
extUserQuery.equalTo('Email', userRes.data.email);
extUserQuery.include('TeamIds');
const extUser = await extUserQuery.first({ useMasterKey: true });
if (extUser) {
const _extUser = JSON.parse(JSON.stringify(extUser));
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
let teamArr = [];
_extUser?.TeamIds?.forEach(x => (teamArr = [...teamArr, ...x.Ancestors]));
paramsObj = {
...paramsObj,
$or: [
{ SharedWith: { $in: teamArr } },
{
ExtUserPtr: {
__type: 'Pointer',
className: 'contracts_Users',
objectId: extUser.id,
},
},
{
SharedWithUsers: {
__type: 'Pointer',
className: 'contracts_Users',
objectId: extUser.id,
},
},
],
};
} else {
paramsObj = {
...paramsObj,
CreatedBy: { __type: 'Pointer', className: '_User', objectId: userId },
};
}
}
if (!userId) {
return { error: 'Invalid session token' };
}
const json = reportId && reportJson(reportId, userId);
if (json) {
let paramsObj = { ...(json.params || {}) };
if (reportId == '6TeaPr321t') {
const extUserQuery = new Parse.Query('contracts_Users');
extUserQuery.equalTo('Email', userRes.data.email);
extUserQuery.include('TeamIds');
const extUser = await extUserQuery.first({ useMasterKey: true });
const userPtr = { __type: 'Pointer', className: '_User', objectId: userId };
if (!extUser) {
paramsObj = { ...paramsObj, CreatedBy: userPtr };
}
if (searchTerm) {
const escaped = escapeRegExp(searchTerm);
const _extUser = JSON.parse(JSON.stringify(extUser));
const extPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id };
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
// Collect ancestors efficiently + de-dupe
const teamSet = new Set();
for (const team of _extUser?.TeamIds) {
const ancestors = team.Ancestors || [];
for (const a of ancestors) teamSet.add(a);
}
const teamArr = [...teamSet];
paramsObj = {
...paramsObj,
Name: { $regex: `.*${escaped}.*`, $options: 'i' },
$or: [
{ SharedWith: { $in: teamArr } },
{ ExtUserPtr: extPtr },
{ SharedWithUsers: extPtr },
],
};
}
const strParams = JSON.stringify(paramsObj);
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': masterKey,
};
const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId`;
const res = await axios.get(url, { headers: headers });
if (res.data && res.data.results) {
return res.data.results;
} else {
return [];
paramsObj = { ...paramsObj, CreatedBy: userPtr };
}
} else {
return { error: 'Report is not available!' };
}
paramsObj = applySearch({ reportId, baseWhere: paramsObj, searchTerm });
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': masterKey,
};
const clsName = json?.reportClass ? json.reportClass : 'contracts_Document';
const orderBy = '-updatedAt';
const include = 'AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId';
const url = buildClassesUrl({
serverUrl,
clsName,
paramsObj,
keys: json.keys || [],
orderBy,
skip,
limit,
include,
});
const res = await axios.get(url, { headers: headers });
if (res.data && res.data.results) {
return res.data.results;
} else {
return [];
}
} else {
return { error: 'Report is not available!' };
}
} catch (err) {
console.log('err', err.message);
const message = err?.response?.data?.error || err?.message || 'Something went wrong';
console.log('getreport error:', message);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
@@ -122,7 +122,7 @@ async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
const TenantAppName = appName;
const logo =
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
const auditTrailCount = doc?.AuditTrail?.filter(x => x.Activity === 'Signed')?.length || 0;
const removePrefill =
doc?.Placeholders?.length > 0 && doc?.Placeholders?.filter(x => x?.Role !== 'prefill');
@@ -142,7 +142,7 @@ async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
`<div>${logo}</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 by ${signerName}</p>` +
`</div><div style='padding:20px;font-family:system-ui;font-size:14px'><p>Dear ${creatorName},</p><p>${pdfName} has been signed by ${signerName} "${signerEmail}" successfully</p>` +
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
const params = {
extUserId: sender.objectId,
@@ -169,7 +169,7 @@ async function sendCompletedMail(obj) {
const TenantAppName = appName;
const logo =
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
let signersMail;
if (doc?.Signers?.length > 0) {
const isOwnerExistsinSigners = doc?.Signers?.find(x => x.Email === sender.Email);
@@ -186,7 +186,7 @@ async function sendCompletedMail(obj) {
`<div>${logo}</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 ${TenantAppName}. 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 ${TenantAppName}${opurl}.</p></div></div></body></html>`;
`If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
if (obj?.isCustomMail) {
const tenant = sender?.TenantId;
@@ -98,11 +98,6 @@ export default function reportJson(id, currentUserId) {
IsCompleted: true,
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 } },
@@ -230,3 +225,36 @@ export default function reportJson(id, currentUserId) {
return null;
}
}
// Escape regex special characters. Copied from filterDocs.js
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**
* Applies searchTerm rules; combines existing access $or with search $or using $and.
*/
export function applySearch({ reportId, baseWhere, searchTerm }) {
if (!searchTerm) return baseWhere;
const escaped = escapeRegExp(searchTerm);
const nameMatch = { Name: { $regex: `.*${escaped}.*`, $options: 'i' } };
const emailMatch = { Email: { $regex: `.*${escaped}.*`, $options: 'i' } };
if (reportId === 'contacts') {
return { ...baseWhere, $or: [nameMatch, emailMatch] };
}
const searchOr = [
nameMatch,
{ Signers: { $inQuery: { className: 'contracts_Contactbook', where: emailMatch } } },
];
// If baseWhere already has an access-control $or, combine using $and
if (baseWhere.$or) {
const { $or: accessOr, ...rest } = baseWhere;
return { ...rest, $and: [{ $or: accessOr }, { $or: searchOr }] };
}
return { ...baseWhere, $or: searchOr };
}
@@ -58,15 +58,20 @@ async function sendMailProvider(req, plan, monthchange) {
});
} else {
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
const localUrl = req.params.url;
const newlocalUrl = localUrl.replace(
'https://localhost:3001/api',
'http://localhost:8080'
);
axios
.get(req.params.url, { responseType: 'stream', httpsAgent })
.get(newlocalUrl, { responseType: 'stream', httpsAgent: httpsAgent })
.then(response => {
response.data.pipe(Pdf);
Pdf.on('finish', () => resolve('success'));
Pdf.on('error', () => resolve('error'));
})
.catch(e => {
console.log('error', e.message);
console.log('error in localurl', e.message);
resolve('error');
});
}
@@ -0,0 +1,49 @@
export default async function setWidgetPreferences(request) {
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
const dateWidgetParams = request?.params?.dateWidget;
if (!dateWidgetParams || Object.keys(dateWidgetParams).length === 0) {
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.');
}
try {
const orgQuery = new Parse.Query('contracts_Users');
orgQuery.equalTo('UserId', request.user);
const userObj = await orgQuery.first({ useMasterKey: true });
if (!userObj) {
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Permission denied.');
}
const widgetPreferencesRaw = userObj?.get('WidgetPreferences');
const widgetPreferences = Array.isArray(widgetPreferencesRaw) ? widgetPreferencesRaw : [];
// Normalize booleans (simple + safe)
const dateWidget = {
type: 'date',
isSigningDate: !!dateWidgetParams.isSigningDate,
isReadOnly: !!dateWidgetParams.isReadOnly,
date: dateWidgetParams?.isSigningDate ? '' : dateWidgetParams?.date || '',
format: dateWidgetParams.format || 'MM/dd/yyyy',
};
// Upsert: replace if exists, otherwise append
const updatedWidgetPreferences =
widgetPreferences?.length > 0
? widgetPreferences.map(w => (w.type === 'date' ? dateWidget : w))
: [...widgetPreferences, dateWidget];
userObj.set('WidgetPreferences', updatedWidgetPreferences);
const saved = await userObj.save(null, { useMasterKey: true });
if (saved) {
const response = typeof saved.toJSON === 'function' ? saved.toJSON() : saved;
return {
WidgetPreferences: response.WidgetPreferences,
updatedAt: response.updatedAt,
createdAt: response.createdAt,
};
}
} catch (err) {
console.log('set widget preferences error:', err);
throw new Parse.Error(err?.code || 400, err?.message || 'Something went wrong.');
}
}