From 0576123a77787be0a18880dd606c3930d2ad9c1e Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Fri, 1 Dec 2023 18:04:05 +0530 Subject: [PATCH 01/73] add api for get, delete contact, getUser & get Documents --- .../cloud/customRoute/v1/apiV1.js | 34 ++++++++++ .../customRoute/v1/routes/deleteContact.js | 42 ++++++++++++ .../cloud/customRoute/v1/routes/getContact.js | 30 +++++++++ .../customRoute/v1/routes/getContacts.js | 29 ++++++++ .../customRoute/v1/routes/getDocument.js | 30 +++++++++ .../customRoute/v1/routes/getDocuments.js | 67 +++++++++++++++++++ .../cloud/customRoute/v1/routes/getUser.js | 27 ++++++++ apps/OpenSignServer/index.js | 4 ++ 8 files changed, 263 insertions(+) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/apiV1.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js new file mode 100644 index 000000000..6e4eb839f --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -0,0 +1,34 @@ +//--npm modules +import express from 'express'; +import cors from 'cors'; +export const app = express(); +import dotenv from 'dotenv'; +import getUser from './routes/getUser.js'; +import getDocuments from './routes/getDocuments.js'; +import getDocument from './routes/getDocument.js'; +import getContact from './routes/getContact.js'; +import deleteContact from './routes/deleteContact.js'; +import getContacts from './routes/getContacts.js'; + +dotenv.config(); +app.use(cors()); +app.use(express.json({ limit: '50mb' })); +app.use(express.urlencoded({ limit: '50mb', extended: true })); + +// get user details whose api token used +app.get('/getuser', getUser); + +// get all types of documents on the basis of doctype +app.get('/getdocuments', getDocuments); + +// get Document on the basis of id +app.get('/document/:document_id', getDocument); + +// get contact on the basis of id +app.get('/contact/:contact_id', getContact); + +// soft delete contact +app.delete('/contact/:contact_id', deleteContact); + +// get list of contacts +app.get('/getcontacts', getContacts); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js new file mode 100644 index 000000000..89a3926d1 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -0,0 +1,42 @@ +export default async function deleteContact(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Contactbook = new Parse.Query('contracts_Contactbook'); + Contactbook.equalTo('objectId', request.params.contact_id); + Contactbook.equalTo('CreatedBy', userId); + const res = await Contactbook.first({ useMasterKey: true }); + if (res) { + const isDeleted = res.get('IsDeleted'); + if (isDeleted && isDeleted) { + return response.json({ code: 404, message: 'Record not found!' }); + } else { + const Contactbook = Parse.Object.extend('contracts_Contactbook'); + const deleteQuery = new Contactbook(); + deleteQuery.id = request.params.contact_id; + deleteQuery.set('IsDeleted', true); + const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); + if (deleteRes) { + return response.json({ code: 200, result: 'Record delete successfully!' }); + } + } + } else { + return response.json({ code: 404, message: 'Record not found!' }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js new file mode 100644 index 000000000..3dcf56a24 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -0,0 +1,30 @@ +export default async function getContact(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Contactbook = new Parse.Query('contracts_Contactbook'); + Contactbook.equalTo('objectId', request.params.contact_id); + Contactbook.equalTo('CreatedBy', userId); + const res = await Contactbook.first({ useMasterKey: true }); + if (res) { + return response.json({ code: 200, result: res }); + } else { + return response.json({ code: 404, message: 'Record not found!' }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js new file mode 100644 index 000000000..7c0eeaa9f --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js @@ -0,0 +1,29 @@ +export default async function getContacts(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Contactbook = new Parse.Query('contracts_Contactbook'); + Contactbook.equalTo('CreatedBy', userId); + const res = await Contactbook.find({ useMasterKey: true }); + if (res && res.length > 0) { + return response.json({ code: 200, result: res }); + } else { + return response.json({ code: 200, result: [] }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js new file mode 100644 index 000000000..2c5a7e98f --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -0,0 +1,30 @@ +export default async function getDocument(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Document = new Parse.Query('contracts_Document'); + Document.equalTo('objectId', request.params.document_id); + Document.equalTo('CreatedBy', userId); + const res = await Document.first({ useMasterKey: true }); + if (res) { + return response.json({ code: 200, result: res }); + } else { + return response.json({ code: 404, message: 'Document not found!' }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js new file mode 100644 index 000000000..4450f248c --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js @@ -0,0 +1,67 @@ +import axios from 'axios'; +import reportJson from '../../../parsefunction/reportsJson.js'; +import dotenv from 'dotenv'; +dotenv.config(); + +export default async function getDocuments(request, response) { + const reqToken = request.headers['x-api-token']; + const appId = process.env.APP_ID; + const serverUrl = process.env.SERVER_URL; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userId = token.get('Id'); + const docType = request.body.doctype; + const limit = request.body.limit; + const skip = request.body.skip; + let reportId; + switch (docType) { + case 'draftDocuments': + reportId = 'ByHuevtCFY'; + break; + case 'signatureRequest': + reportId = '4Hhwbp482K'; + break; + case 'inprogressDocuments': + reportId = '1MwEuxLEkF'; + break; + case 'completeDocuments': + reportId = 'kQUoW4hUXz'; + break; + case 'expiredDocuments': + reportId = 'zNqBHXHsYH'; + break; + case 'declinedDocuments': + reportId = 'UPr2Fm5WY3'; + break; + } + const json = reportId && reportJson(reportId, userId); + const clsName = 'contracts_Document'; + if (json) { + const { params, keys } = json; + const orderBy = '-updatedAt'; + const strParams = JSON.stringify(params); + const strKeys = keys.join(); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results) { + return response.json({ code: 200, result: res.data.results }); + } else { + return response.json({ code: 200, result: [] }); + } + } else { + return response.json({ code: 404, message: 'Report is not available!' }); + } + } + return response.json({ code: 404, message: 'Invalid API Token!' }); +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js new file mode 100644 index 000000000..300db2dfd --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -0,0 +1,27 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +export default async function getUser(request, response) { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userId = token.get('Id'); + const query = new Parse.Query(Parse.User); + query.equalTo('objectId', userId); + query.exclude('authData'); + let user = await query.first({ useMasterKey: true }); + const result = user; + if (result) { + return response.json({ code: 200, result: result }); + } else { + return response.json({ code: 404, message: 'Record not found!' }); + } + } + return response.json({ code: 404, message: 'Invalid API Token!' }); +} diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 819940954..c5b621de7 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -19,6 +19,7 @@ import AWS from 'aws-sdk'; import { app as customRoute } from './cloud/customRoute/customApp.js'; import { exec } from 'child_process'; import { createTransport } from 'nodemailer'; +import { app as v1 } from './cloud/customRoute/v1/apiV1.js'; const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT); // console.log("configuration ", configuration); @@ -162,6 +163,9 @@ if (!process.env.TESTING) { // Mount your custom express app app.use('/', customRoute); +// Mount v1 +app.use('/v1', v1); + // Parse Server plays nicely with the rest of your web routes app.get('/', function (req, res) { // res.statusCode = 200; From c44149050c5d00024622badbf9193f56658fb70b Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Fri, 1 Dec 2023 18:34:27 +0530 Subject: [PATCH 02/73] rename files --- apps/OpenSignServer/cloud/customRoute/v1/apiV1.js | 8 ++++---- .../v1/routes/{getContacts.js => getContactList.js} | 2 +- .../v1/routes/{getDocuments.js => getDocumentList.js} | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename apps/OpenSignServer/cloud/customRoute/v1/routes/{getContacts.js => getContactList.js} (94%) rename apps/OpenSignServer/cloud/customRoute/v1/routes/{getDocuments.js => getDocumentList.js} (97%) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 6e4eb839f..44adcae7a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -4,11 +4,11 @@ import cors from 'cors'; export const app = express(); import dotenv from 'dotenv'; import getUser from './routes/getUser.js'; -import getDocuments from './routes/getDocuments.js'; +import getDocumentList from './routes/getDocumentList.js'; import getDocument from './routes/getDocument.js'; import getContact from './routes/getContact.js'; import deleteContact from './routes/deleteContact.js'; -import getContacts from './routes/getContacts.js'; +import getContactList from './routes/getContactList.js'; dotenv.config(); app.use(cors()); @@ -19,7 +19,7 @@ app.use(express.urlencoded({ limit: '50mb', extended: true })); app.get('/getuser', getUser); // get all types of documents on the basis of doctype -app.get('/getdocuments', getDocuments); +app.get('/documentlist', getDocumentList); // get Document on the basis of id app.get('/document/:document_id', getDocument); @@ -31,4 +31,4 @@ app.get('/contact/:contact_id', getContact); app.delete('/contact/:contact_id', deleteContact); // get list of contacts -app.get('/getcontacts', getContacts); +app.get('/contactlist', getContactList); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js similarity index 94% rename from apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js rename to apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 7c0eeaa9f..da8f0302b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContacts.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -1,4 +1,4 @@ -export default async function getContacts(request, response) { +export default async function getContactList(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js similarity index 97% rename from apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js rename to apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 4450f248c..0756c28b4 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocuments.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -3,7 +3,7 @@ import reportJson from '../../../parsefunction/reportsJson.js'; import dotenv from 'dotenv'; dotenv.config(); -export default async function getDocuments(request, response) { +export default async function getDocumentList(request, response) { const reqToken = request.headers['x-api-token']; const appId = process.env.APP_ID; const serverUrl = process.env.SERVER_URL; From b47bf437a92cffb060037a12a9b6653411ff9ca4 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Sat, 2 Dec 2023 21:16:56 +0530 Subject: [PATCH 03/73] created generateapitoken, getapitoken cloud function & generatetoken route --- apps/OpenSign/src/App.js | 9 ++ apps/OpenSign/src/routes/GenerateToken.js | 139 ++++++++++++++++++ apps/OpenSignServer/cloud/main.js | 8 +- .../cloud/parsefunction/generateApiToken.js | 44 ++++++ .../cloud/parsefunction/getapitoken.js | 24 +++ apps/OpenSignServer/package-lock.json | 31 +++- apps/OpenSignServer/package.json | 1 + 7 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 apps/OpenSign/src/routes/GenerateToken.js create mode 100644 apps/OpenSignServer/cloud/parsefunction/generateApiToken.js create mode 100644 apps/OpenSignServer/cloud/parsefunction/getapitoken.js diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index 500e00808..b14bfb284 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -15,6 +15,7 @@ import ForgetPassword from "./routes/ForgetPassword"; import ChangePassword from "./routes/ChangePassword"; import ReportMicroapp from "./components/ReportMicroapp"; import LoadMf from "./routes/LoadMf"; +import GenerateToken from "./routes/GenerateToken"; function App() { const [isloading, setIsLoading] = useState(true); @@ -138,6 +139,14 @@ function App() { } /> + + + + } + /> } /> {/* } /> */} diff --git a/apps/OpenSign/src/routes/GenerateToken.js b/apps/OpenSign/src/routes/GenerateToken.js new file mode 100644 index 000000000..a507d29aa --- /dev/null +++ b/apps/OpenSign/src/routes/GenerateToken.js @@ -0,0 +1,139 @@ +import React, { useEffect, useState } from "react"; +import Title from "../components/Title"; +import axios from "axios"; + +function GenerateToken() { + const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); + const [parseAppId] = useState(localStorage.getItem("parseAppId")); + const [apiToken, SetApiToken] = useState(""); + const [isLoader, setIsLoader] = useState(true); + const [copied, setCopied] = useState(false); + + useEffect(() => { + fetchToken(); + // eslint-disable-next-line + }, []); + + const fetchToken = async () => { + try { + const url = parseBaseUrl + "functions/getapitoken"; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessiontoken: localStorage.getItem("accesstoken") + }; + const res = await axios.post(url, {}, { headers: headers }); + if (res) { + SetApiToken(res.data.result.result); + } + setIsLoader(false); + } catch (err) { + SetApiToken(); + setIsLoader(false); + console.log("Err", err); + } + }; + const handleSubmit = async (e) => { + e.preventDefault(); + setIsLoader(true); + try { + const url = parseBaseUrl + "functions/generateapitoken"; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessiontoken: localStorage.getItem("accesstoken") + }; + await axios.post(url, {}, { headers: headers }).then((res) => { + if (res) { + SetApiToken(res.data.result.token); + // localStorage.setItem("apiToken", res.data.result.token); + alert("Token generated successfully!"); + setIsLoader(false); + } else { + alert("Something went wrong!"); + console.error("Error while generating Token"); + setIsLoader(false); + } + }); + } catch (error) { + setIsLoader(false); + alert("Something went wrong!"); + console.log("err", error); + } + }; + + const copytoclipboard = (text) => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 1500); // Reset copied state after 1.5 seconds + }; + return ( + + + {copied && ( + <div className={`alert alert-success alertBox`} role="alert"> + Copied + </div> + )} + {isLoader ? ( + <div + style={{ + height: "100vh", + display: "flex", + alignItems: "center", + justifyContent: "center" + }} + > + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + ) : ( + <div className="bg-white flex flex-col justify-center shadow rounded"> + <ul className="w-full flex flex-col p-2 text-sm"> + <li + className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all py-2`} + > + <span className="w-[40%]">Api Token:</span>{" "} + <span + id="token" + className="w-[60%] md:text-end cursor-pointer" + onClick={() => copytoclipboard(apiToken)} + > + {apiToken && apiToken} + </span> + </li> + <li + className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} + > + <span className="w-[40%]">Application Id:</span>{" "} + <span + className="w-[60%] md:text-end cursor-pointer" + onClick={() => copytoclipboard(localStorage.getItem("AppID12"))} + > + {localStorage.getItem("AppID12")} + </span> + </li> + </ul> + <div className="flex justify-center pb-4"> + <button + type="button" + onClick={handleSubmit} + className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base" + > + {apiToken ? "Regenerate Token" : "Generate Token"} + </button> + </div> + </div> + )} + </React.Fragment> + ); +} + +export default GenerateToken; diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index e42ee38e5..97b5ab466 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -17,6 +17,8 @@ import getUserDetails from './parsefunction/getUserDetails.js'; import getDocument from './parsefunction/getDocument.js'; import getDrive from './parsefunction/getDrive.js'; import getReport from './parsefunction/getReport.js'; +import generateApiToken from './parsefunction/generateApiToken.js'; +import getapitoken from './parsefunction/getapitoken.js'; Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('UserGroups', getUserGroups); @@ -35,5 +37,7 @@ Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); Parse.Cloud.define('getUserId', getUserId); Parse.Cloud.define('getUserDetails', getUserDetails); Parse.Cloud.define('getDocument', getDocument); -Parse.Cloud.define('getDrive', getDrive) -Parse.Cloud.define('getReport', getReport) \ No newline at end of file +Parse.Cloud.define('getDrive', getDrive); +Parse.Cloud.define('getReport', getReport); +Parse.Cloud.define('generateapitoken', generateApiToken); +Parse.Cloud.define('getapitoken', getapitoken); diff --git a/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js new file mode 100644 index 000000000..bdf7842cc --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js @@ -0,0 +1,44 @@ +import { generateApiKey } from 'generate-api-key'; +import axios from 'axios'; +export default async function generateApiToken(request) { + const serverUrl = 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('Id', 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('Id', userId); + const newRes = await appTokenQuery.save(null, { useMasterKey: true }); + return newRes; + } + } else { + return 'User not found!'; + } + } catch (err) { + console.log('err ', err); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/getapitoken.js b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js new file mode 100644 index 000000000..5e12d6a39 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js @@ -0,0 +1,24 @@ +import axios from 'axios'; +export default async function getapitoken(request) { + const serverUrl = 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('Id', userId); + const res = await tokenQuery.first({ useMasterKey: true }); + if (res) { + return { status: 'success', result: res.get('token') }; + } + } + } catch (err) { + console.log('Err', err); + return { status: 'error', result: err }; + } +} diff --git a/apps/OpenSignServer/package-lock.json b/apps/OpenSignServer/package-lock.json index e57104d95..fac7ba41c 100644 --- a/apps/OpenSignServer/package-lock.json +++ b/apps/OpenSignServer/package-lock.json @@ -17,6 +17,7 @@ "express": "4.18.2", "express-sse": "^0.5.3", "form-data": "^4.0.0", + "generate-api-key": "^1.0.2", "jsonschema": "^1.4.1", "mailgun.js": "^9.3.0", "mongoose": "^7.2.1", @@ -2037,6 +2038,11 @@ "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==" }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2401,6 +2407,11 @@ "node": ">=4" } }, + "node_modules/chance": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.11.tgz", + "integrity": "sha512-kqTg3WWywappJPqtgrdvbA380VoXO2eu9VCV895JgbyHsaErXdyHK9LOZ911OvAk6L0obK7kDk9CGs8+oBawVA==" + }, "node_modules/charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -4373,6 +4384,20 @@ "lodash.padstart": "^4.1.0" } }, + "node_modules/generate-api-key": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/generate-api-key/-/generate-api-key-1.0.2.tgz", + "integrity": "sha512-4rPSpXyboIXfugOTN3/0Qaoqpzbk0sepzPS0XyxPh3UMuu+Trk+0JMyJ6mB/7FEgp7oZ1juqsRW+8wSYeKDbfA==", + "dependencies": { + "base-x": "^4.0.0", + "chance": "^1.1.8", + "rfc4648": "^1.5.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -8804,6 +8829,11 @@ "node": ">=0.10.0" } }, + "node_modules/rfc4648": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.3.tgz", + "integrity": "sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -9897,7 +9927,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, "bin": { "uuid": "dist/bin/uuid" } diff --git a/apps/OpenSignServer/package.json b/apps/OpenSignServer/package.json index 4725d28d5..350f10979 100644 --- a/apps/OpenSignServer/package.json +++ b/apps/OpenSignServer/package.json @@ -26,6 +26,7 @@ "express": "4.18.2", "express-sse": "^0.5.3", "form-data": "^4.0.0", + "generate-api-key": "^1.0.2", "jsonschema": "^1.4.1", "mailgun.js": "^9.3.0", "mongoose": "^7.2.1", From 4866447f334bedca8485e98da312c93b0a6e6f65 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Tue, 12 Dec 2023 19:37:59 +0530 Subject: [PATCH 04/73] add api for template, createDocument --- .../cloud/customRoute/v1/apiV1.js | 21 +++++++ .../customRoute/v1/routes/createDocument.js | 55 ++++++++++++++++++ .../customRoute/v1/routes/createTemplate.js | 54 +++++++++++++++++ .../customRoute/v1/routes/deleteTemplate.js | 42 ++++++++++++++ .../customRoute/v1/routes/getTemplate.js | 31 ++++++++++ .../customRoute/v1/routes/getTemplateList.js | 58 +++++++++++++++++++ 6 files changed, 261 insertions(+) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 44adcae7a..794337cca 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -9,6 +9,11 @@ import getDocument from './routes/getDocument.js'; import getContact from './routes/getContact.js'; import deleteContact from './routes/deleteContact.js'; import getContactList from './routes/getContactList.js'; +import createDocument from './routes/createDocument.js'; +import createTemplate from './routes/createTemplate.js'; +import getTemplate from './routes/getTemplate.js'; +import deletedTemplate from './routes/deleteTemplate.js'; +import getTemplatetList from './routes/getTemplateList.js'; dotenv.config(); app.use(cors()); @@ -32,3 +37,19 @@ app.delete('/contact/:contact_id', deleteContact); // get list of contacts app.get('/contactlist', getContactList); + +// create Document +app.post('/createdocument', createDocument); + +// create Template +app.post('/createtemplate', createTemplate); + +// get template on the basis of id +app.get('/template/:template_id', getTemplate); + +// get template on the basis of id +app.delete('/template/:template_id', deletedTemplate); + +// get all types of documents on the basis of doctype +app.get('/templatelist', getTemplatetList); + diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js new file mode 100644 index 000000000..f1e499751 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -0,0 +1,55 @@ +export default async function createDocument(request, response) { + const name = request.body.name; + const note = request.body.note; + const description = request.body.description; + const signers = request.body.signer; + const folderId = request.body.folderId; + const file = request.body.file; + + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userId); + const extUser = await contractsUser.first({ useMasterKey: true }); + const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; + + const folderPtr = { __type: 'Pointer', className: 'contracts_Document', objectId: folderId }; + + const object = new Parse.Object('contracts_Document'); + object.set('Name', name); + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', file); + object.set('CreatedBy', userId); + object.set('ExtUserPtr', extUserPtr); + if (signers) { + object.set('Signers', signers); + } + if (folderId) { + object.set('Folder', folderPtr); + } + const res = await object.save(null, { useMasterKey: true }); + return response.json({ code: 200, result: res }); + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js new file mode 100644 index 000000000..3852cdadd --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -0,0 +1,54 @@ +export default async function createTemplate(request, response) { + const name = request.body.name; + const note = request.body.note; + const description = request.body.description; + const signers = request.body.signer; + const folderId = request.body.folderId; + const file = request.body.file; + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userId); + const extUser = await contractsUser.first({ useMasterKey: true }); + const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; + + const folderPtr = { __type: 'Pointer', className: 'contracts_Template', objectId: folderId }; + + const object = new Parse.Object('contracts_Template'); + object.set('Name', name); + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', file); + object.set('CreatedBy', userId); + object.set('ExtUserPtr', extUserPtr); + if (signers) { + object.set('Signers', signers); + } + if (folderId) { + object.set('Folder', folderPtr); + } + const res = await object.save(null, { useMasterKey: true }); + return response.json({ code: 200, result: res }); + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js new file mode 100644 index 000000000..5c029019e --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -0,0 +1,42 @@ +export default async function deletedTemplate(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const template = new Parse.Query('contracts_Template'); + template.equalTo('objectId', request.params.template_id); + template.equalTo('CreatedBy', userId); + const res = await template.first({ useMasterKey: true }); + if (res) { + const isDeleted = res.get('IsArchive'); + if (isDeleted && isDeleted) { + return response.json({ code: 404, message: 'Record not found!' }); + } else { + const template = Parse.Object.extend('contracts_Template'); + const deleteQuery = new template(); + deleteQuery.id = request.params.template_id; + deleteQuery.set('IsArchive', true); + const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); + if (deleteRes) { + return response.json({ code: 200, result: 'Record delete successfully!' }); + } + } + } else { + return response.json({ code: 404, message: 'Record not found!' }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js new file mode 100644 index 000000000..c7faafcb1 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -0,0 +1,31 @@ +export default async function getTemplate(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Document = new Parse.Query('contracts_Template'); + Document.equalTo('objectId', request.params.template_id); + Document.equalTo('CreatedBy', userId); + const res = await Document.first({ useMasterKey: true }); + if (res) { + return response.json({ code: 200, result: res }); + } else { + return response.json({ code: 404, message: 'Document not found!' }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } + } + \ No newline at end of file diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js new file mode 100644 index 000000000..b94b4b65d --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -0,0 +1,58 @@ +import axios from 'axios'; +import reportJson from '../../../parsefunction/reportsJson.js'; +import dotenv from 'dotenv'; +dotenv.config(); + +export default async function getTemplatetList(request, response) { + const reqToken = request.headers['x-api-token']; + const appId = process.env.APP_ID; + const serverUrl = process.env.SERVER_URL; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userId = token.get('Id'); + const limit = request.body.limit ? request.body.limit : 200; + const skip = request.body.skip ? request.body.skip : 0; + + const clsName = 'contracts_Template'; + const params = { + Type: { $ne: 'Folder' }, + CreatedBy: { + __type: 'Pointer', + className: '_User', + objectId: userId, + }, + IsArchive: { $ne: true }, + }; + const keys = [ + 'Name', + 'Note', + 'Description', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + ]; + const orderBy = '-updatedAt'; + const strParams = JSON.stringify(params); + const strKeys = keys.join(); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results) { + return response.json({ code: 200, result: res.data.results }); + } else { + return response.json({ code: 200, result: [] }); + } + } + return response.json({ code: 404, message: 'Invalid API Token!' }); +} From 0c14d71fa854c5a1b2b28ec1e97eb11809797701 Mon Sep 17 00:00:00 2001 From: Amol <amol@nxglabs.in> Date: Wed, 20 Dec 2023 19:02:47 +0530 Subject: [PATCH 05/73] docs: Add openapi spec --- apps/OpenSignServer/public/openapi.json | 934 ++++++++++++++++++++++++ 1 file changed, 934 insertions(+) create mode 100644 apps/OpenSignServer/public/openapi.json diff --git a/apps/OpenSignServer/public/openapi.json b/apps/OpenSignServer/public/openapi.json new file mode 100644 index 000000000..de11c91e4 --- /dev/null +++ b/apps/OpenSignServer/public/openapi.json @@ -0,0 +1,934 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "OpenSign API v1", + "description": "This is API documentation for OpenSign API v1 based on the OpenAPI 3.1 specification. \n\nSome useful links:\n- [Official Website](https://www.opensignlabs.com)\n- [Github repo](https://github.com/opensignlabs/opensign)", + "termsOfService": "http://www.opensignlabs.com/terms/", + "contact": { + "email": "contact@opensignlabs.com" + }, + "license": { + "name": "AGPL 3.0", + "url": "http://github.com/opensignlabs/opensign/LICENSE" + }, + "version": "1.0.0" + }, + "externalDocs": { + "description": "Find out more about OpenSign", + "url": "http://docs.opensignlabs.com" + }, + "servers": [ + { + "url": "https://app.opensignlabs.com/api/v1" + } + ], + "tags": [ + { + "name": "OpenSign", + "description": "OpenSource DocuSign alternative", + "externalDocs": { + "description": "Find out more", + "url": "http://www.opensignlabs.com" + } + }, + { + "name": "Github repo", + "description": "Access the source code", + "externalDocs": { + "description": "Visit github", + "url": "http://github.com/opensignlabs/opensign" + } + }, + { + "name": "templates", + "description": "Operations about templates" + }, + { + "name": "users", + "description": "Operations about users" + }, + { + "name": "documents", + "description": "Operations about documents" + } + ], + "paths": { + "/getuser": { + "put": { + "tags": [ + "users" + ], + "summary": "Update an existing pet", + "description": "Update an existing pet by Id", + "operationId": "updatePet", + "requestBody": { + "description": "Update an existent pet in the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "post": { + "tags": [ + "users" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "addPet", + "requestBody": { + "description": "Create a new pet in the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/documentlist": { + "get": { + "tags": [ + "documents" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "Status values that need to be considered for filter", + "required": false, + "explode": true, + "schema": { + "type": "string", + "default": "available", + "enum": [ + "available", + "pending", + "sold" + ] + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid status value" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/document/": { + "get": { + "tags": [ + "documents" + ], + "summary": "Finds Pets by tags", + "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "parameters": [ + { + "name": "tags", + "in": "query", + "description": "Tags to filter by", + "required": false, + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid tag value" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/contact/{contact_id}": { + "get": { + "tags": [ + "contacts" + ], + "summary": "Find pet by ID", + "description": "Returns a single pet", + "operationId": "getPetById", + "parameters": [ + { + "name": "contact_id", + "in": "path", + "description": "ID of pet to return", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "post": { + "tags": [ + "contacts" + ], + "summary": "Updates a pet in the store with form data", + "description": "", + "operationId": "updatePetWithForm", + "parameters": [ + { + "name": "contact_id", + "in": "path", + "description": "ID of pet that needs to be updated", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "name", + "in": "query", + "description": "Name of pet that needs to be updated", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Status of pet that needs to be updated", + "schema": { + "type": "string" + } + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "delete": { + "tags": [ + "contacts" + ], + "summary": "Deletes a pet", + "description": "delete a pet", + "operationId": "deletePet", + "parameters": [ + { + "name": "api_key", + "in": "header", + "description": "", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "contact_id", + "in": "path", + "description": "Pet id to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "400": { + "description": "Invalid pet value" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/contactlist": { + "post": { + "tags": [ + "contacts" + ], + "summary": "uploads an image", + "description": "", + "operationId": "uploadFile", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/createdocument": { + "get": { + "tags": [ + "documents" + ], + "summary": "Returns pet inventories by status", + "description": "Returns a map of status codes to quantities", + "operationId": "getInventory", + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/createtemplate": { + "post": { + "tags": [ + "templates" + ], + "summary": "Place an order for a pet", + "description": "Place a new order in the store", + "operationId": "placeOrder", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "405": { + "description": "Invalid input" + } + } + } + }, + "/template/{template_id}": { + "get": { + "tags": [ + "templates" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "operationId": "getOrderById", + "parameters": [ + { + "name": "template_id", + "in": "path", + "description": "ID of order that needs to be fetched", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + }, + "delete": { + "tags": [ + "templates" + ], + "summary": "Delete purchase order by ID", + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "operationId": "deleteOrder", + "parameters": [ + { + "name": "template_id", + "in": "path", + "description": "ID of the order that needs to be deleted", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + }, + "/templatelist": { + "post": { + "tags": [ + "templates" + ], + "summary": "Create user", + "description": "This can only be done by the logged in user.", + "operationId": "createUser", + "requestBody": { + "description": "Created user object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "responses": { + "default": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Order": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "petId": { + "type": "integer", + "format": "int64", + "example": 198772 + }, + "quantity": { + "type": "integer", + "format": "int32", + "example": 7 + }, + "shipDate": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "Order Status", + "example": "approved", + "enum": [ + "placed", + "approved", + "delivered" + ] + }, + "complete": { + "type": "boolean" + } + }, + "xml": { + "name": "order" + } + }, + "Customer": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 100000 + }, + "username": { + "type": "string", + "example": "fehguy" + }, + "address": { + "type": "array", + "xml": { + "name": "addresses", + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Address" + } + } + }, + "xml": { + "name": "customer" + } + }, + "Address": { + "type": "object", + "properties": { + "street": { + "type": "string", + "example": "437 Lytton" + }, + "city": { + "type": "string", + "example": "Palo Alto" + }, + "state": { + "type": "string", + "example": "CA" + }, + "zip": { + "type": "string", + "example": "94301" + } + }, + "xml": { + "name": "address" + } + }, + "Category": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 1 + }, + "name": { + "type": "string", + "example": "Dogs" + } + }, + "xml": { + "name": "category" + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "username": { + "type": "string", + "example": "theUser" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "James" + }, + "email": { + "type": "string", + "example": "john@email.com" + }, + "password": { + "type": "string", + "example": "12345" + }, + "phone": { + "type": "string", + "example": "12345" + }, + "userStatus": { + "type": "integer", + "description": "User Status", + "format": "int32", + "example": 1 + } + }, + "xml": { + "name": "user" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "tag" + } + }, + "Pet": { + "required": [ + "name", + "photoUrls" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "name": { + "type": "string", + "example": "doggie" + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "photoUrls": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": "string", + "xml": { + "name": "photoUrl" + } + } + }, + "tags": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "xml": { + "name": "pet" + } + }, + "ApiResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "xml": { + "name": "##default" + } + } + }, + "requestBodies": { + "Pet": { + "description": "Pet object that needs to be added to the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "UserArray": { + "description": "List of user object", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + }, + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "X-Parse-ApiKey", + "in": "header" + } + } + } +} \ No newline at end of file From e264511a6e5609fc462f149c160df8e08060809b Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 11 Jan 2024 16:29:26 +0530 Subject: [PATCH 06/73] feat: add limit and skip variables in query & contact creation api --- .../customRoute/v1/routes/createContact.js | 120 ++++++++++++++++++ .../customRoute/v1/routes/deleteTemplate.js | 4 +- .../customRoute/v1/routes/getContactList.js | 5 + .../customRoute/v1/routes/getDocumentList.js | 4 +- .../customRoute/v1/routes/getTemplateList.js | 5 +- 5 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js new file mode 100644 index 000000000..c6f38442c --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -0,0 +1,120 @@ +import axios from 'axios'; +export default async function createContact(request, response) { + const serverUrl = process.env.SERVER_URL; + const appId = process.env.APP_ID; + const name = request.body.name; + const phone = request.body.phone; + const email = request.body.email; + + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + try { + const Tenant = new Parse.Query('partners_Tenant'); + Tenant.equalTo('UserId', userId); + const tenantRes = Tenant.first({ useMasterKey: true }); + + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + contactQuery.set('Phone', phone); + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + + if (tenantRes) { + contactQuery.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: tenantRes.id, + }); + } + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', name); + _user.set('username', email); + _user.set('email', email); + _user.set('phone', phone); + _user.set('password', phone); + + const user = await _user.save(); + if (user) { + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: user.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set('CreatedBy', Parse.User.createWithoutData(currentUser.id)); + + contactQuery.set('UserId', user); + const acl = new Parse.ACL(); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + + contactQuery.setACL(acl); + + await contactQuery.save(); + // const parseData = JSON.parse(JSON.stringify(res)); + return response.json({ code: 200, message: 'Contact create sucessfully!' }); + } + } catch (err) { + console.log('err ', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': parseAppId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: userRes.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set('CreatedBy', Parse.User.createWithoutData(currentUser.id)); + + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + + contactQuery.setACL(acl); + await contactQuery.save(); + return response.json({ code: 200, message: 'Contact create sucessfully!' }); + // const parseData = JSON.parse(JSON.stringify(res)); + } + } + } catch (err) { + return response.json({ code: 404, message: 'Something went wrong, please try again later!' }); + } + } else { + return response.json({ code: 404, message: 'Invalid API Token!' }); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index 5c029019e..763505268 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -16,8 +16,8 @@ export default async function deletedTemplate(request, response) { template.equalTo('CreatedBy', userId); const res = await template.first({ useMasterKey: true }); if (res) { - const isDeleted = res.get('IsArchive'); - if (isDeleted && isDeleted) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { return response.json({ code: 404, message: 'Record not found!' }); } else { const template = Parse.Object.extend('contracts_Template'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index da8f0302b..e2a2762f0 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -11,8 +11,13 @@ export default async function getContactList(request, response) { // Valid Token then proceed request const id = token.get('Id'); const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const limit = request?.body?.limit ? request.body.limit : 100; + const skip = request?.body?.skip ? request.body.skip : 0; const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('CreatedBy', userId); + Contactbook.notEqualTo('IsDeleted', true); + Contactbook.limit(limit); + Contactbook.skip(skip); const res = await Contactbook.find({ useMasterKey: true }); if (res && res.length > 0) { return response.json({ code: 200, result: res }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 0756c28b4..d17387d74 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -17,8 +17,8 @@ export default async function getDocumentList(request, response) { // Valid Token then proceed request const userId = token.get('Id'); const docType = request.body.doctype; - const limit = request.body.limit; - const skip = request.body.skip; + const limit = request?.body?.limit ? request.body.limit : 100; + const skip = request?.body?.skip ? request.body.skip : 0; let reportId; switch (docType) { case 'draftDocuments': diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index b94b4b65d..36a73bc91 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -1,5 +1,4 @@ import axios from 'axios'; -import reportJson from '../../../parsefunction/reportsJson.js'; import dotenv from 'dotenv'; dotenv.config(); @@ -16,8 +15,8 @@ export default async function getTemplatetList(request, response) { if (token !== undefined) { // Valid Token then proceed request const userId = token.get('Id'); - const limit = request.body.limit ? request.body.limit : 200; - const skip = request.body.skip ? request.body.skip : 0; + const limit = request?.body?.limit ? request.body.limit : 100; + const skip = request?.body?.skip ? request.body.skip : 0; const clsName = 'contracts_Template'; const params = { From eebcfe94d970a0d7a2addebcb397713e0b82ba13 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 11 Jan 2024 22:19:40 +0530 Subject: [PATCH 07/73] feat: add update template api and update all apis --- .../cloud/customRoute/v1/apiV1.js | 5 +- .../customRoute/v1/routes/createContact.js | 18 +++-- .../customRoute/v1/routes/createDocument.js | 9 ++- .../customRoute/v1/routes/createTemplate.js | 9 ++- .../customRoute/v1/routes/deleteContact.js | 4 +- .../customRoute/v1/routes/deleteTemplate.js | 4 +- .../cloud/customRoute/v1/routes/getContact.js | 11 ++- .../customRoute/v1/routes/getContactList.js | 2 +- .../customRoute/v1/routes/getDocument.js | 3 +- .../customRoute/v1/routes/getDocumentList.js | 2 +- .../customRoute/v1/routes/getTemplate.js | 5 +- .../customRoute/v1/routes/getTemplateList.js | 2 +- .../cloud/customRoute/v1/routes/getUser.js | 8 +-- .../customRoute/v1/routes/updateTemplate.js | 68 +++++++++++++++++++ 14 files changed, 124 insertions(+), 26 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 794337cca..b5d3f1b5b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -14,6 +14,7 @@ import createTemplate from './routes/createTemplate.js'; import getTemplate from './routes/getTemplate.js'; import deletedTemplate from './routes/deleteTemplate.js'; import getTemplatetList from './routes/getTemplateList.js'; +import updateTemplate from './routes/updateTemplate.js'; dotenv.config(); app.use(cors()); @@ -47,9 +48,11 @@ app.post('/createtemplate', createTemplate); // get template on the basis of id app.get('/template/:template_id', getTemplate); +// get template on the basis of id +app.put('/template/:template_id', updateTemplate); + // get template on the basis of id app.delete('/template/:template_id', deletedTemplate); // get all types of documents on the basis of doctype app.get('/templatelist', getTemplatetList); - diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index c6f38442c..e429e173c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -70,9 +70,13 @@ export default async function createContact(request, response) { contactQuery.setACL(acl); - await contactQuery.save(); + const contactRes = await contactQuery.save(); // const parseData = JSON.parse(JSON.stringify(res)); - return response.json({ code: 200, message: 'Contact create sucessfully!' }); + return response.json({ + code: 200, + message: 'Contact created sucessfully!', + result: { id: contactRes.id }, + }); } } catch (err) { console.log('err ', err); @@ -106,8 +110,12 @@ export default async function createContact(request, response) { acl.setWriteAccess(userRes.id, true); contactQuery.setACL(acl); - await contactQuery.save(); - return response.json({ code: 200, message: 'Contact create sucessfully!' }); + const contactRes = await contactQuery.save(); + return response.json({ + code: 200, + message: 'Contact created sucessfully!', + result: { id: contactRes.id }, + }); // const parseData = JSON.parse(JSON.stringify(res)); } } @@ -115,6 +123,6 @@ export default async function createContact(request, response) { return response.json({ code: 404, message: 'Something went wrong, please try again later!' }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index f1e499751..d58cca4de 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -5,6 +5,7 @@ export default async function createDocument(request, response) { const signers = request.body.signer; const folderId = request.body.folderId; const file = request.body.file; + const url = process.env.SERVER_URL; try { const reqToken = request.headers['x-api-token']; @@ -44,9 +45,13 @@ export default async function createDocument(request, response) { object.set('Folder', folderPtr); } const res = await object.save(null, { useMasterKey: true }); - return response.json({ code: 200, result: res }); + return response.json({ + code: 200, + message: 'Document created successfully!', + result: { id: res.id, url: url }, + }); } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 3852cdadd..65863d764 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -5,6 +5,7 @@ export default async function createTemplate(request, response) { const signers = request.body.signer; const folderId = request.body.folderId; const file = request.body.file; + const url = process.env.SERVER_URL try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -43,9 +44,13 @@ export default async function createTemplate(request, response) { object.set('Folder', folderPtr); } const res = await object.save(null, { useMasterKey: true }); - return response.json({ code: 200, result: res }); + return response.json({ + code: 200, + message: 'Template created successfully!', + result: { id: res.id, url: url }, + }); } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, result: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index 89a3926d1..b0e883a51 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -26,14 +26,14 @@ export default async function deleteContact(request, response) { deleteQuery.set('IsDeleted', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ code: 200, result: 'Record delete successfully!' }); + return response.json({ code: 200, message: 'Record delete successfully!' }); } } } else { return response.json({ code: 404, message: 'Record not found!' }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index 763505268..3c1707f5a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -26,14 +26,14 @@ export default async function deletedTemplate(request, response) { deleteQuery.set('IsArchive', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ code: 200, result: 'Record delete successfully!' }); + return response.json({ code: 200, message: 'Template delete successfully!' }); } } } else { return response.json({ code: 404, message: 'Record not found!' }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index 3dcf56a24..cefc3d496 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -14,14 +14,21 @@ export default async function getContact(request, response) { const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('objectId', request.params.contact_id); Contactbook.equalTo('CreatedBy', userId); + Contactbook.notEqualTo('IsDeleted', true); + Contactbook.select('Name,Email,Phone'); + const res = await Contactbook.first({ useMasterKey: true }); if (res) { - return response.json({ code: 200, result: res }); + const parseRes = JSON.parse(JSON.stringify(res)); + return response.json({ + code: 200, + result: { objectId: parseRes.objectId, Name: parseRes.Name, Email: parseRes.Email }, + }); } else { return response.json({ code: 404, message: 'Record not found!' }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index e2a2762f0..0b3ad0b9f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -25,7 +25,7 @@ export default async function getContactList(request, response) { return response.json({ code: 200, result: [] }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index 2c5a7e98f..e732e16cd 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -14,6 +14,7 @@ export default async function getDocument(request, response) { const Document = new Parse.Query('contracts_Document'); Document.equalTo('objectId', request.params.document_id); Document.equalTo('CreatedBy', userId); + Document.notEqualTo('IsArchive', true); const res = await Document.first({ useMasterKey: true }); if (res) { return response.json({ code: 200, result: res }); @@ -21,7 +22,7 @@ export default async function getDocument(request, response) { return response.json({ code: 404, message: 'Document not found!' }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index d17387d74..01d6a0acb 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -63,5 +63,5 @@ export default async function getDocumentList(request, response) { return response.json({ code: 404, message: 'Report is not available!' }); } } - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index c7faafcb1..c57638f04 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -14,14 +14,15 @@ export default async function getTemplate(request, response) { const Document = new Parse.Query('contracts_Template'); Document.equalTo('objectId', request.params.template_id); Document.equalTo('CreatedBy', userId); + Document.notEqualTo('IsArchive', true); const res = await Document.first({ useMasterKey: true }); if (res) { return response.json({ code: 200, result: res }); } else { - return response.json({ code: 404, message: 'Document not found!' }); + return response.json({ code: 404, message: 'Template not found!' }); } } else { - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 36a73bc91..1a4ee3820 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -53,5 +53,5 @@ export default async function getTemplatetList(request, response) { return response.json({ code: 200, result: [] }); } } - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index 300db2dfd..c81ebed50 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -12,9 +12,9 @@ export default async function getUser(request, response) { if (token !== undefined) { // Valid Token then proceed request const userId = token.get('Id'); - const query = new Parse.Query(Parse.User); - query.equalTo('objectId', userId); - query.exclude('authData'); + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); + query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); let user = await query.first({ useMasterKey: true }); const result = user; if (result) { @@ -23,5 +23,5 @@ export default async function getUser(request, response) { return response.json({ code: 404, message: 'Record not found!' }); } } - return response.json({ code: 404, message: 'Invalid API Token!' }); + return response.json({ code: 405, message: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js new file mode 100644 index 000000000..1703aab08 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -0,0 +1,68 @@ +export default async function updateTemplate(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.json({ message: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const allowedKeys = ['Name', 'Note', 'Description']; + const objectKeys = Object.keys(request.body); + const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + if (isValid) { + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const template = new Parse.Query('contracts_Template'); + template.equalTo('objectId', request.params.template_id); + template.equalTo('CreatedBy', userId); + const res = await template.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.json({ code: 404, message: 'Record not found!' }); + } else { + const template = Parse.Object.extend('contracts_Template'); + const updateQuery = new template(); + updateQuery.id = request.params.template_id; + if (request?.body?.Name) { + updateQuery.set('Name', request?.body?.Name); + } + if (request?.body?.Note) { + updateQuery.set('Note', request?.body?.Note); + } + if (request?.body?.Description) { + updateQuery.set('Name', request?.body?.Description); + } + if (request?.body?.FolderId) { + updateQuery.set('Folder', { + __type: 'Pointer', + className: 'contracts_Template', + objectId: request?.body?.FolderId, + }); + } + const updatedRes = await updateQuery.save(null, { useMasterKey: true }); + if (updatedRes) { + return response.json({ + code: 200, + message: 'Template updated successfully!', + result: updatedRes.id, + }); + } + } + } else { + return response.json({ code: 404, message: 'Record not found!' }); + } + } else { + return response.json({ code: 400, message: 'Please provide valid field names!' }); + } + } else { + return response.json({ code: 405, message: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} From a8d564d74d4f3704bcf9d00233e724b6290dc6fa Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 12 Jan 2024 13:24:41 +0530 Subject: [PATCH 08/73] update api --- .../cloud/customRoute/v1/apiV1.js | 18 +++++++++++------- .../cloud/customRoute/v1/routes/getContact.js | 2 +- apps/OpenSignServer/cloud/main.js | 6 ++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index b5d3f1b5b..5b9e986c5 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -15,6 +15,7 @@ import getTemplate from './routes/getTemplate.js'; import deletedTemplate from './routes/deleteTemplate.js'; import getTemplatetList from './routes/getTemplateList.js'; import updateTemplate from './routes/updateTemplate.js'; +import createContact from './routes/createContact.js'; dotenv.config(); app.use(cors()); @@ -24,11 +25,8 @@ app.use(express.urlencoded({ limit: '50mb', extended: true })); // get user details whose api token used app.get('/getuser', getUser); -// get all types of documents on the basis of doctype -app.get('/documentlist', getDocumentList); - -// get Document on the basis of id -app.get('/document/:document_id', getDocument); +// get contact on the basis of id +app.post('/createcontact', createContact); // get contact on the basis of id app.get('/contact/:contact_id', getContact); @@ -37,11 +35,17 @@ app.get('/contact/:contact_id', getContact); app.delete('/contact/:contact_id', deleteContact); // get list of contacts -app.get('/contactlist', getContactList); +app.post('/contactlist', getContactList); // create Document app.post('/createdocument', createDocument); +// get Document on the basis of id +app.get('/document/:document_id', getDocument); + +// get all types of documents on the basis of doctype +app.post('/documentlist', getDocumentList); + // create Template app.post('/createtemplate', createTemplate); @@ -55,4 +59,4 @@ app.put('/template/:template_id', updateTemplate); app.delete('/template/:template_id', deletedTemplate); // get all types of documents on the basis of doctype -app.get('/templatelist', getTemplatetList); +app.post('/templatelist', getTemplatetList); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index cefc3d496..f9101ac7d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -25,7 +25,7 @@ export default async function getContact(request, response) { result: { objectId: parseRes.objectId, Name: parseRes.Name, Email: parseRes.Email }, }); } else { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Contact not found!' }); } } else { return response.json({ code: 405, message: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index c29d384cd..b6ff1ed7a 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -40,10 +40,8 @@ Parse.Cloud.define('getDrive', getDrive); Parse.Cloud.define('getReport', getReport); Parse.Cloud.define('generateapitoken', generateApiToken); Parse.Cloud.define('getapitoken', getapitoken); -Parse.Cloud.define('getDrive', getDrive) -Parse.Cloud.define('getReport', getReport) -Parse.Cloud.define("getTemplate", GetTemplate) +Parse.Cloud.define('getTemplate', GetTemplate); Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); -Parse.Cloud.afterSave("contracts_Template", TemplateAfterSave) +Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave); From 629bf7f51f418937d20c3a68aeb9d63b0722692b Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 12 Jan 2024 20:29:40 +0530 Subject: [PATCH 09/73] update documentlist api --- .../OpenSignServer/cloud/customRoute/v1/apiV1.js | 2 +- .../customRoute/v1/routes/getDocumentList.js | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 5b9e986c5..b17ff3997 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -44,7 +44,7 @@ app.post('/createdocument', createDocument); app.get('/document/:document_id', getDocument); // get all types of documents on the basis of doctype -app.post('/documentlist', getDocumentList); +app.post('/documentlist/:doctype', getDocumentList); // create Template app.post('/createtemplate', createTemplate); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 01d6a0acb..069482a95 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -16,33 +16,35 @@ export default async function getDocumentList(request, response) { if (token !== undefined) { // Valid Token then proceed request const userId = token.get('Id'); - const docType = request.body.doctype; + const docType = request.params.doctype; const limit = request?.body?.limit ? request.body.limit : 100; const skip = request?.body?.skip ? request.body.skip : 0; let reportId; switch (docType) { - case 'draftDocuments': + case 'draftdocuments': reportId = 'ByHuevtCFY'; break; case 'signatureRequest': reportId = '4Hhwbp482K'; break; - case 'inprogressDocuments': + case 'inprogressdocuments': reportId = '1MwEuxLEkF'; break; - case 'completeDocuments': + case 'completedocuments': reportId = 'kQUoW4hUXz'; break; - case 'expiredDocuments': + case 'expiredocuments': reportId = 'zNqBHXHsYH'; break; - case 'declinedDocuments': + case 'declinedocuments': reportId = 'UPr2Fm5WY3'; break; + default: + reportId = ''; } const json = reportId && reportJson(reportId, userId); const clsName = 'contracts_Document'; - if (json) { + if (reportId && json) { const { params, keys } = json; const orderBy = '-updatedAt'; const strParams = JSON.stringify(params); From a5fe4a345b1bf2e9abff4d5d22d6c814689cc168 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 12 Jan 2024 20:31:04 +0530 Subject: [PATCH 10/73] update response message in delete contact api --- .../cloud/customRoute/v1/routes/deleteContact.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index b0e883a51..5cae4e32d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -26,11 +26,11 @@ export default async function deleteContact(request, response) { deleteQuery.set('IsDeleted', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ code: 200, message: 'Record delete successfully!' }); + return response.json({ code: 200, message: 'Contact deleted successfully!' }); } } } else { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Contact not found!' }); } } else { return response.json({ code: 405, message: 'Invalid API Token!' }); From ebdc5ef5666bc031f76131024d1c22918c090a2b Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 15 Jan 2024 16:16:03 +0530 Subject: [PATCH 11/73] update response of apis --- .../customRoute/v1/routes/createContact.js | 4 ++-- .../customRoute/v1/routes/createDocument.js | 2 +- .../customRoute/v1/routes/deleteContact.js | 2 +- .../customRoute/v1/routes/deleteTemplate.js | 6 +++--- .../customRoute/v1/routes/getDocumentList.js | 18 +++++++++++++++--- .../customRoute/v1/routes/getTemplateList.js | 15 ++++++++++++++- .../cloud/customRoute/v1/routes/getUser.js | 2 +- .../customRoute/v1/routes/updateTemplate.js | 6 +++--- .../cloud/parsefunction/reportsJson.js | 13 +++++++++++-- 9 files changed, 51 insertions(+), 17 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index e429e173c..cee2a2b0b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -75,7 +75,7 @@ export default async function createContact(request, response) { return response.json({ code: 200, message: 'Contact created sucessfully!', - result: { id: contactRes.id }, + result: { objectId: contactRes.id }, }); } } catch (err) { @@ -114,7 +114,7 @@ export default async function createContact(request, response) { return response.json({ code: 200, message: 'Contact created sucessfully!', - result: { id: contactRes.id }, + result: { objectId: contactRes.id }, }); // const parseData = JSON.parse(JSON.stringify(res)); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index d58cca4de..9e036fa4e 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -48,7 +48,7 @@ export default async function createDocument(request, response) { return response.json({ code: 200, message: 'Document created successfully!', - result: { id: res.id, url: url }, + result: { objectId: res.id, url: url }, }); } else { return response.json({ code: 405, message: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index 5cae4e32d..86636f96c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -18,7 +18,7 @@ export default async function deleteContact(request, response) { if (res) { const isDeleted = res.get('IsDeleted'); if (isDeleted && isDeleted) { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Contact not found!' }); } else { const Contactbook = Parse.Object.extend('contracts_Contactbook'); const deleteQuery = new Contactbook(); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index 3c1707f5a..b2c0518a0 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -18,7 +18,7 @@ export default async function deletedTemplate(request, response) { if (res) { const isArchive = res.get('IsArchive'); if (isArchive && isArchive) { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Template not found!' }); } else { const template = Parse.Object.extend('contracts_Template'); const deleteQuery = new template(); @@ -26,11 +26,11 @@ export default async function deletedTemplate(request, response) { deleteQuery.set('IsArchive', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ code: 200, message: 'Template delete successfully!' }); + return response.json({ code: 200, message: 'Template deleted successfully!' }); } } } else { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Template not found!' }); } } else { return response.json({ code: 405, message: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 069482a95..3be07d83e 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -24,7 +24,7 @@ export default async function getDocumentList(request, response) { case 'draftdocuments': reportId = 'ByHuevtCFY'; break; - case 'signatureRequest': + case 'signaturerequest': reportId = '4Hhwbp482K'; break; case 'inprogressdocuments': @@ -57,12 +57,24 @@ export default async function getDocumentList(request, response) { const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; const res = await axios.get(url, { headers: headers }); if (res.data && res.data.results) { - return response.json({ code: 200, result: res.data.results }); + const updateRes = + res.data.results.length > 0 + ? res.data.results.map(x => ({ + objectId: x.objectId, + Title: x.Name, + Note: x.Note || '', + Folder: x?.Folder?.Name || 'OpenSign™ Drive', + File: x?.SignedUrl || x.URL, + Owner: x?.ExtUserPtr?.Name, + Signers: x?.Signers?.map(y => y?.Name) || '', + })) + : []; + return response.json({ code: 200, result: updateRes }); } else { return response.json({ code: 200, result: [] }); } } else { - return response.json({ code: 404, message: 'Report is not available!' }); + return response.json({ code: 404, message: 'Report not available!' }); } } return response.json({ code: 405, message: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 1a4ee3820..59ab9f864 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -34,6 +34,7 @@ export default async function getTemplatetList(request, response) { 'Description', 'Folder.Name', 'URL', + 'SignedUrl', 'ExtUserPtr.Name', 'Signers.Name', ]; @@ -48,7 +49,19 @@ export default async function getTemplatetList(request, response) { const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; const res = await axios.get(url, { headers: headers }); if (res.data && res.data.results) { - return response.json({ code: 200, result: res.data.results }); + const updateRes = + res.data.results.length > 0 + ? res.data.results.map(x => ({ + objectId: x.objectId, + Title: x.Name, + Note: x.Note || '', + Folder: x?.Folder?.Name || 'OpenSign™ Drive', + File: x?.SignedUrl || x.URL, + Owner: x?.ExtUserPtr?.Name, + Signers: x?.Signers?.map(y => y?.Name) || '', + })) + : []; + return response.json({ code: 200, result: updateRes }); } else { return response.json({ code: 200, result: [] }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index c81ebed50..8d88218d9 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -20,7 +20,7 @@ export default async function getUser(request, response) { if (result) { return response.json({ code: 200, result: result }); } else { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'User not found!' }); } } return response.json({ code: 405, message: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 1703aab08..8dd0936fd 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -22,7 +22,7 @@ export default async function updateTemplate(request, response) { if (res) { const isArchive = res.get('IsArchive'); if (isArchive && isArchive) { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Template not found!' }); } else { const template = Parse.Object.extend('contracts_Template'); const updateQuery = new template(); @@ -48,12 +48,12 @@ export default async function updateTemplate(request, response) { return response.json({ code: 200, message: 'Template updated successfully!', - result: updatedRes.id, + result: { objectId: updatedRes.id }, }); } } } else { - return response.json({ code: 404, message: 'Record not found!' }); + return response.json({ code: 404, message: 'Template not found!' }); } } else { return response.json({ code: 400, message: 'Please provide valid field names!' }); diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js index 2031cd076..24bc07dae 100644 --- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js +++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js @@ -11,7 +11,11 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - $or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }], + $or: [ + { Signers: { $eq: [] } }, + { Signers: null }, + { Signers: { $exists: true }, Placeholders: null }, + ], CreatedBy: { __type: 'Pointer', className: '_User', @@ -99,6 +103,7 @@ export default function reportJson(id, userId) { 'Note', 'Folder.Name', 'URL', + 'SignedUrl', 'ExtUserPtr.Name', 'Signers.Name', 'TimeToCompleteDays', @@ -211,7 +216,11 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - $or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }], + $or: [ + { Signers: { $eq: [] } }, + { Signers: null }, + { Signers: { $exists: true }, Placeholders: null }, + ], CreatedBy: { __type: 'Pointer', className: '_User', From e52c7c97cf67e76b4d48dab177967318f20a35c1 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 15 Jan 2024 18:15:16 +0530 Subject: [PATCH 12/73] remove code from response and add update Document api --- .../cloud/customRoute/v1/apiV1.js | 55 ++++++++++++++- .../customRoute/v1/routes/createContact.js | 8 +-- .../customRoute/v1/routes/createDocument.js | 5 +- .../customRoute/v1/routes/createTemplate.js | 7 +- .../customRoute/v1/routes/deleteContact.js | 10 +-- .../customRoute/v1/routes/deleteTemplate.js | 10 +-- .../cloud/customRoute/v1/routes/getContact.js | 7 +- .../customRoute/v1/routes/getContactList.js | 12 ++-- .../customRoute/v1/routes/getDocument.js | 8 +-- .../customRoute/v1/routes/getDocumentList.js | 14 ++-- .../customRoute/v1/routes/getTemplate.js | 53 +++++++-------- .../customRoute/v1/routes/getTemplateList.js | 12 ++-- .../cloud/customRoute/v1/routes/getUser.js | 8 +-- .../customRoute/v1/routes/updateDocument.js | 68 +++++++++++++++++++ .../customRoute/v1/routes/updateTemplate.js | 11 ++- 15 files changed, 199 insertions(+), 89 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index b17ff3997..3b3b2cfe5 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -16,8 +16,13 @@ import deletedTemplate from './routes/deleteTemplate.js'; import getTemplatetList from './routes/getTemplateList.js'; import updateTemplate from './routes/updateTemplate.js'; import createContact from './routes/createContact.js'; +import multer from 'multer'; +import fs from 'node:fs'; dotenv.config(); +const storage = multer.memoryStorage(); +const upload = multer({ storage: storage }); + app.use(cors()); app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ limit: '50mb', extended: true })); @@ -35,16 +40,19 @@ app.get('/contact/:contact_id', getContact); app.delete('/contact/:contact_id', deleteContact); // get list of contacts -app.post('/contactlist', getContactList); +app.get('/contactlist', getContactList); // create Document app.post('/createdocument', createDocument); +// get template on the basis of id +app.put('/template/:document_id', updateTemplate); + // get Document on the basis of id app.get('/document/:document_id', getDocument); // get all types of documents on the basis of doctype -app.post('/documentlist/:doctype', getDocumentList); +app.get('/documentlist/:doctype', getDocumentList); // create Template app.post('/createtemplate', createTemplate); @@ -59,4 +67,45 @@ app.put('/template/:template_id', updateTemplate); app.delete('/template/:template_id', deletedTemplate); // get all types of documents on the basis of doctype -app.post('/templatelist', getTemplatetList); +app.get('/templatelist', getTemplatetList); + +app.post('/tempupload', upload.single('file'), async (req, res) => { + const name = req.body.name; + const note = req.body.note; + const description = req.body.description; + const fileFormat = req.body.fileFormat; // 'binary' or 'base64' + const filePath = req.body.filePath; // Path to the file + + let fileData; + + if (fileFormat === 'binary') { + // Read file content if the file is in binary format + fileData = fs.readFileSync(filePath); + } else if (fileFormat === 'base64') { + // Convert base64 data to binary + fileData = req.file ? req.file.buffer : null; + } else { + return res.status(400).json({ error: 'Invalid file format' }); + } + + // Create a Parse.File object + const file = new Parse.File('myfile', { base64: fileData.toString('base64') }); + + // Save the file to Parse Server + try { + await file.save(); + } catch (error) { + console.error('Error saving file to Parse Server:', error); + return res.status(500).json({ error: 'Internal Server Error' }); + } + + // Perform any desired processing with the received data + + // Respond to the client with the file URL + res.json({ + name: name, + note: note, + description: description, + fileUrl: file.url(), + }); +}); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index cee2a2b0b..a6187afc9 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -8,7 +8,7 @@ export default async function createContact(request, response) { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -73,7 +73,6 @@ export default async function createContact(request, response) { const contactRes = await contactQuery.save(); // const parseData = JSON.parse(JSON.stringify(res)); return response.json({ - code: 200, message: 'Contact created sucessfully!', result: { objectId: contactRes.id }, }); @@ -112,7 +111,6 @@ export default async function createContact(request, response) { contactQuery.setACL(acl); const contactRes = await contactQuery.save(); return response.json({ - code: 200, message: 'Contact created sucessfully!', result: { objectId: contactRes.id }, }); @@ -120,9 +118,9 @@ export default async function createContact(request, response) { } } } catch (err) { - return response.json({ code: 404, message: 'Something went wrong, please try again later!' }); + return response.status(404).json({ error: 'Something went wrong, please try again later!' }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 9e036fa4e..e36f3ac0f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -10,7 +10,7 @@ export default async function createDocument(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -46,12 +46,11 @@ export default async function createDocument(request, response) { } const res = await object.save(null, { useMasterKey: true }); return response.json({ - code: 200, message: 'Document created successfully!', result: { objectId: res.id, url: url }, }); } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 65863d764..eae3cb92c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -5,11 +5,11 @@ export default async function createTemplate(request, response) { const signers = request.body.signer; const folderId = request.body.folderId; const file = request.body.file; - const url = process.env.SERVER_URL + const url = process.env.SERVER_URL; try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -45,12 +45,11 @@ export default async function createTemplate(request, response) { } const res = await object.save(null, { useMasterKey: true }); return response.json({ - code: 200, message: 'Template created successfully!', result: { id: res.id, url: url }, }); } else { - return response.json({ code: 405, result: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index 86636f96c..e40c25114 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -2,7 +2,7 @@ export default async function deleteContact(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -18,7 +18,7 @@ export default async function deleteContact(request, response) { if (res) { const isDeleted = res.get('IsDeleted'); if (isDeleted && isDeleted) { - return response.json({ code: 404, message: 'Contact not found!' }); + return response.status(404).json({ error: 'Contact not found!' }); } else { const Contactbook = Parse.Object.extend('contracts_Contactbook'); const deleteQuery = new Contactbook(); @@ -26,14 +26,14 @@ export default async function deleteContact(request, response) { deleteQuery.set('IsDeleted', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ code: 200, message: 'Contact deleted successfully!' }); + return response.json({ message: 'Contact deleted successfully!' }); } } } else { - return response.json({ code: 404, message: 'Contact not found!' }); + return response.status(404).json({ error: 'Contact not found!' }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index b2c0518a0..953f8c6e1 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -2,7 +2,7 @@ export default async function deletedTemplate(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -18,7 +18,7 @@ export default async function deletedTemplate(request, response) { if (res) { const isArchive = res.get('IsArchive'); if (isArchive && isArchive) { - return response.json({ code: 404, message: 'Template not found!' }); + return response.status(404).json({ error: 'Template not found!' }); } else { const template = Parse.Object.extend('contracts_Template'); const deleteQuery = new template(); @@ -26,14 +26,14 @@ export default async function deletedTemplate(request, response) { deleteQuery.set('IsArchive', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ code: 200, message: 'Template deleted successfully!' }); + return response.json({ message: 'Template deleted successfully!' }); } } } else { - return response.json({ code: 404, message: 'Template not found!' }); + return response.status(404).json({ error: 'Template not found!' }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index f9101ac7d..d57d8dae2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -2,7 +2,7 @@ export default async function getContact(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -21,14 +21,13 @@ export default async function getContact(request, response) { if (res) { const parseRes = JSON.parse(JSON.stringify(res)); return response.json({ - code: 200, result: { objectId: parseRes.objectId, Name: parseRes.Name, Email: parseRes.Email }, }); } else { - return response.json({ code: 404, message: 'Contact not found!' }); + return response.status(404).json({ error: 'Contact not found!' }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 0b3ad0b9f..707092da3 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -2,7 +2,7 @@ export default async function getContactList(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -11,8 +11,8 @@ export default async function getContactList(request, response) { // Valid Token then proceed request const id = token.get('Id'); const userId = { __type: 'Pointer', className: '_User', objectId: id }; - const limit = request?.body?.limit ? request.body.limit : 100; - const skip = request?.body?.skip ? request.body.skip : 0; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('CreatedBy', userId); Contactbook.notEqualTo('IsDeleted', true); @@ -20,12 +20,12 @@ export default async function getContactList(request, response) { Contactbook.skip(skip); const res = await Contactbook.find({ useMasterKey: true }); if (res && res.length > 0) { - return response.json({ code: 200, result: res }); + return response.json({ result: res }); } else { - return response.json({ code: 200, result: [] }); + return response.json({ result: [] }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index e732e16cd..533454ef3 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -2,7 +2,7 @@ export default async function getDocument(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -17,12 +17,12 @@ export default async function getDocument(request, response) { Document.notEqualTo('IsArchive', true); const res = await Document.first({ useMasterKey: true }); if (res) { - return response.json({ code: 200, result: res }); + return response.json({ result: res }); } else { - return response.json({ code: 404, message: 'Document not found!' }); + return response.status(404).json({ error: 'Document not found!' }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 3be07d83e..1ae887158 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -8,7 +8,7 @@ export default async function getDocumentList(request, response) { const appId = process.env.APP_ID; const serverUrl = process.env.SERVER_URL; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -17,8 +17,8 @@ export default async function getDocumentList(request, response) { // Valid Token then proceed request const userId = token.get('Id'); const docType = request.params.doctype; - const limit = request?.body?.limit ? request.body.limit : 100; - const skip = request?.body?.skip ? request.body.skip : 0; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; let reportId; switch (docType) { case 'draftdocuments': @@ -69,13 +69,13 @@ export default async function getDocumentList(request, response) { Signers: x?.Signers?.map(y => y?.Name) || '', })) : []; - return response.json({ code: 200, result: updateRes }); + return response.json({ result: updateRes }); } else { - return response.json({ code: 200, result: [] }); + return response.json({ result: [] }); } } else { - return response.json({ code: 404, message: 'Report not available!' }); + return response.status(404).json({ error: 'Report not available!' }); } } - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index c57638f04..9e7457d82 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -1,32 +1,31 @@ export default async function getTemplate(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; - const Document = new Parse.Query('contracts_Template'); - Document.equalTo('objectId', request.params.template_id); - Document.equalTo('CreatedBy', userId); - Document.notEqualTo('IsArchive', true); - const res = await Document.first({ useMasterKey: true }); - if (res) { - return response.json({ code: 200, result: res }); - } else { - return response.json({ code: 404, message: 'Template not found!' }); - } + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Document = new Parse.Query('contracts_Template'); + Document.equalTo('objectId', request.params.template_id); + Document.equalTo('CreatedBy', userId); + Document.notEqualTo('IsArchive', true); + const res = await Document.first({ useMasterKey: true }); + if (res) { + return response.json({ result: res }); } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(404).json({ error: 'Template not found!' }); } - } catch (err) { - console.log('err ', err); - return response.json(err); + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); } + } catch (err) { + console.log('err ', err); + return response.json(err); } - \ No newline at end of file +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 59ab9f864..2cbc319d9 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -7,7 +7,7 @@ export default async function getTemplatetList(request, response) { const appId = process.env.APP_ID; const serverUrl = process.env.SERVER_URL; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -15,8 +15,8 @@ export default async function getTemplatetList(request, response) { if (token !== undefined) { // Valid Token then proceed request const userId = token.get('Id'); - const limit = request?.body?.limit ? request.body.limit : 100; - const skip = request?.body?.skip ? request.body.skip : 0; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; const clsName = 'contracts_Template'; const params = { @@ -61,10 +61,10 @@ export default async function getTemplatetList(request, response) { Signers: x?.Signers?.map(y => y?.Name) || '', })) : []; - return response.json({ code: 200, result: updateRes }); + return response.json({ result: updateRes }); } else { - return response.json({ code: 200, result: [] }); + return response.json({ result: [] }); } } - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index 8d88218d9..725a31109 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -4,7 +4,7 @@ dotenv.config(); export default async function getUser(request, response) { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -18,10 +18,10 @@ export default async function getUser(request, response) { let user = await query.first({ useMasterKey: true }); const result = user; if (result) { - return response.json({ code: 200, result: result }); + return response.json({ result: result }); } else { - return response.json({ code: 404, message: 'User not found!' }); + return response.status(404).json({ error: 'User not found!' }); } } - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js new file mode 100644 index 000000000..cd475be77 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -0,0 +1,68 @@ +export default async function updateDocument(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const allowedKeys = ['Name', 'Note', 'Description']; + const objectKeys = Object.keys(request.body); + const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + if (isValid) { + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const document = new Parse.Query('contracts_Document'); + document.equalTo('objectId', request.params.document_id); + document.equalTo('CreatedBy', userId); + const res = await document.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ message: 'Document not found!' }); + } else { + const document = Parse.Object.extend('contracts_Document'); + const updateQuery = new document(); + updateQuery.id = request.params.document_id; + if (request?.body?.Name) { + updateQuery.set('Name', request?.body?.Name); + } + if (request?.body?.Note) { + updateQuery.set('Note', request?.body?.Note); + } + if (request?.body?.Description) { + updateQuery.set('Name', request?.body?.Description); + } + if (request?.body?.FolderId) { + updateQuery.set('Folder', { + __type: 'Pointer', + className: 'contracts_Document', + objectId: request?.body?.FolderId, + }); + } + const updatedRes = await updateQuery.save(null, { useMasterKey: true }); + if (updatedRes) { + return response.json({ + message: 'Document updated successfully!', + result: { objectId: updatedRes.id }, + }); + } + } + } else { + return response.status(404).json({ error: 'Document not found!' }); + } + } else { + return response.status(400).json({ error: 'Please provide valid field names!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } + } + \ No newline at end of file diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 8dd0936fd..bc654bcbc 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -2,7 +2,7 @@ export default async function updateTemplate(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.json({ message: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -22,7 +22,7 @@ export default async function updateTemplate(request, response) { if (res) { const isArchive = res.get('IsArchive'); if (isArchive && isArchive) { - return response.json({ code: 404, message: 'Template not found!' }); + return response.status(404).json({ message: 'Template not found!' }); } else { const template = Parse.Object.extend('contracts_Template'); const updateQuery = new template(); @@ -46,20 +46,19 @@ export default async function updateTemplate(request, response) { const updatedRes = await updateQuery.save(null, { useMasterKey: true }); if (updatedRes) { return response.json({ - code: 200, message: 'Template updated successfully!', result: { objectId: updatedRes.id }, }); } } } else { - return response.json({ code: 404, message: 'Template not found!' }); + return response.status(404).json({ error: 'Template not found!' }); } } else { - return response.json({ code: 400, message: 'Please provide valid field names!' }); + return response.status(400).json({ error: 'Please provide valid field names!' }); } } else { - return response.json({ code: 405, message: 'Invalid API Token!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } } catch (err) { console.log('err ', err); From 9500b2d6787e61c5f49369d97d3405d7bf32744a Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 15 Jan 2024 20:22:07 +0530 Subject: [PATCH 13/73] update apis response and add delete document api --- .../cloud/customRoute/v1/apiV1.js | 11 +- .../customRoute/v1/routes/createContact.js | 15 ++- .../customRoute/v1/routes/createDocument.js | 5 +- .../customRoute/v1/routes/createTemplate.js | 7 +- .../customRoute/v1/routes/deleteContact.js | 5 +- .../customRoute/v1/routes/deleteDocument.js | 45 +++++++ .../customRoute/v1/routes/deleteTemplate.js | 5 +- .../cloud/customRoute/v1/routes/getContact.js | 7 +- .../customRoute/v1/routes/getContactList.js | 11 +- .../customRoute/v1/routes/getDocument.js | 16 ++- .../customRoute/v1/routes/getDocumentList.js | 25 ++-- .../customRoute/v1/routes/getTemplate.js | 26 +++- .../customRoute/v1/routes/getTemplateList.js | 26 ++-- .../cloud/customRoute/v1/routes/getUser.js | 17 ++- .../customRoute/v1/routes/updateDocument.js | 117 +++++++++--------- .../customRoute/v1/routes/updateTemplate.js | 4 +- 16 files changed, 224 insertions(+), 118 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 3b3b2cfe5..ba6340f9b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -18,6 +18,8 @@ import updateTemplate from './routes/updateTemplate.js'; import createContact from './routes/createContact.js'; import multer from 'multer'; import fs from 'node:fs'; +import updateDocument from './routes/updateDocument.js'; +import deleteDocument from './routes/deleteDocument.js'; dotenv.config(); const storage = multer.memoryStorage(); @@ -45,12 +47,15 @@ app.get('/contactlist', getContactList); // create Document app.post('/createdocument', createDocument); -// get template on the basis of id -app.put('/template/:document_id', updateTemplate); - // get Document on the basis of id app.get('/document/:document_id', getDocument); +// get document on the basis of id +app.put('/document/:document_id', updateDocument); + +// get document on the basis of id +app.delete('/document/:document_id', deleteDocument); + // get all types of documents on the basis of doctype app.get('/documentlist/:doctype', getDocumentList); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index a6187afc9..b335f4889 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -110,10 +110,17 @@ export default async function createContact(request, response) { contactQuery.setACL(acl); const contactRes = await contactQuery.save(); - return response.json({ - message: 'Contact created sucessfully!', - result: { objectId: contactRes.id }, - }); + if (contactRes) { + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updateAt: parseRes.updateAt, + }); + } // const parseData = JSON.parse(JSON.stringify(res)); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index e36f3ac0f..af2deae8b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -45,10 +45,7 @@ export default async function createDocument(request, response) { object.set('Folder', folderPtr); } const res = await object.save(null, { useMasterKey: true }); - return response.json({ - message: 'Document created successfully!', - result: { objectId: res.id, url: url }, - }); + return response.json({ objectId: res.id, url: url }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index eae3cb92c..381e85489 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -9,7 +9,7 @@ export default async function createTemplate(request, response) { try { const reqToken = request.headers['x-api-token']; if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); + return response.status(400).json({ error: 'Please Provide API Token' }); } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); @@ -44,10 +44,7 @@ export default async function createTemplate(request, response) { object.set('Folder', folderPtr); } const res = await object.save(null, { useMasterKey: true }); - return response.json({ - message: 'Template created successfully!', - result: { id: res.id, url: url }, - }); + return response.json({ objectId: res.id, url: url }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index e40c25114..e0997f160 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -26,7 +26,10 @@ export default async function deleteContact(request, response) { deleteQuery.set('IsDeleted', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ message: 'Contact deleted successfully!' }); + return response.json({ + objectId: request.params.contact_id, + deletedAt: deleteRes.get('updatedAt'), + }); } } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js new file mode 100644 index 000000000..d3faa0c9d --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js @@ -0,0 +1,45 @@ +export default async function deleteDocument(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Document = new Parse.Query('contracts_Document'); + Document.equalTo('objectId', request.params.document_id); + Document.equalTo('CreatedBy', userId); + const res = await Document.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ error: 'Document not found!' }); + } else { + const Document = Parse.Object.extend('contracts_Document'); + const deleteQuery = new Document(); + deleteQuery.id = request.params.document_id; + deleteQuery.set('IsArchive', true); + const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); + if (deleteRes) { + return response.json({ + objectId: request.params.document_id, + deletedAt: deleteRes.get('updatedAt'), + }); + } + } + } else { + return response.status(404).json({ error: 'Document not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index 953f8c6e1..f8e1c5ade 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -26,7 +26,10 @@ export default async function deletedTemplate(request, response) { deleteQuery.set('IsArchive', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { - return response.json({ message: 'Template deleted successfully!' }); + return response.json({ + objectId: request.params.template_id, + deletedAt: deleteRes.get('updatedAt'), + }); } } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index d57d8dae2..e0438036a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -21,7 +21,12 @@ export default async function getContact(request, response) { if (res) { const parseRes = JSON.parse(JSON.stringify(res)); return response.json({ - result: { objectId: parseRes.objectId, Name: parseRes.Name, Email: parseRes.Email }, + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, }); } else { return response.status(404).json({ error: 'Contact not found!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 707092da3..93a28b757 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -20,7 +20,16 @@ export default async function getContactList(request, response) { Contactbook.skip(skip); const res = await Contactbook.find({ useMasterKey: true }); if (res && res.length > 0) { - return response.json({ result: res }); + const parseRes = JSON.parse(JSON.stringify(res)); + const contactlist = parseRes.map(x => ({ + objectId: x.objectId, + Name: x.Name, + Email: x.Email, + Phone: x.Phone, + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); + return response.json({ result: contactlist }); } else { return response.json({ result: [] }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index 533454ef3..0417dd354 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -15,9 +15,23 @@ export default async function getDocument(request, response) { Document.equalTo('objectId', request.params.document_id); Document.equalTo('CreatedBy', userId); Document.notEqualTo('IsArchive', true); + Document.include('Signers'); + Document.include('Folder'); + Document.include('ExtUserPtr'); const res = await Document.first({ useMasterKey: true }); if (res) { - return response.json({ result: res }); + const document = JSON.parse(JSON.stringify(res)); + return response.json({ + objectId: document.objectId, + Title: document.Name, + Note: document.Note || '', + Folder: document?.Folder?.Name || 'OpenSign™ Drive', + File: document?.SignedUrl || document.URL, + Owner: document?.ExtUserPtr?.Name, + Signers: document?.Signers?.map(y => y?.Name) || '', + createdAt: document.createdAt, + updatedAt: document.updatedAt, + }); } else { return response.status(404).json({ error: 'Document not found!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 1ae887158..3ef4d338c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -56,19 +56,18 @@ export default async function getDocumentList(request, response) { }; const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results) { - const updateRes = - res.data.results.length > 0 - ? res.data.results.map(x => ({ - objectId: x.objectId, - Title: x.Name, - Note: x.Note || '', - Folder: x?.Folder?.Name || 'OpenSign™ Drive', - File: x?.SignedUrl || x.URL, - Owner: x?.ExtUserPtr?.Name, - Signers: x?.Signers?.map(y => y?.Name) || '', - })) - : []; + if (res.data && res.data.results.length > 0) { + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + title: x.Name, + note: x.Note || '', + folder: x?.Folder?.Name || 'OpenSign™ Drive', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: x?.Signers?.map(y => y?.Name) || '', + created_at: x.createdAt, + updated_at: x.updatedAt, + })); return response.json({ result: updateRes }); } else { return response.json({ result: [] }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index 9e7457d82..8a7b4ec79 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -11,13 +11,27 @@ export default async function getTemplate(request, response) { // Valid Token then proceed request const id = token.get('Id'); const userId = { __type: 'Pointer', className: '_User', objectId: id }; - const Document = new Parse.Query('contracts_Template'); - Document.equalTo('objectId', request.params.template_id); - Document.equalTo('CreatedBy', userId); - Document.notEqualTo('IsArchive', true); - const res = await Document.first({ useMasterKey: true }); + const Template = new Parse.Query('contracts_Template'); + Template.equalTo('objectId', request.params.template_id); + Template.equalTo('CreatedBy', userId); + Template.notEqualTo('IsArchive', true); + Template.include('Signers'); + Template.include('Folder'); + Template.include('ExtUserPtr'); + const res = await Template.first({ useMasterKey: true }); if (res) { - return response.json({ result: res }); + const template = JSON.parse(JSON.stringify(res)); + return response.json({ + objectId: template.objectId, + Title: template.Name, + Note: template.Note || '', + Folder: template?.Folder?.Name || 'OpenSign™ Drive', + File: template?.SignedUrl || x.URL, + Owner: template?.ExtUserPtr?.Name, + Signers: template?.Signers?.map(y => y?.Name) || '', + createdAt: template.createdAt, + updatedAt: template.updatedAt, + }); } else { return response.status(404).json({ error: 'Template not found!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 2cbc319d9..d8e046853 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -48,19 +48,19 @@ export default async function getTemplatetList(request, response) { }; const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results) { - const updateRes = - res.data.results.length > 0 - ? res.data.results.map(x => ({ - objectId: x.objectId, - Title: x.Name, - Note: x.Note || '', - Folder: x?.Folder?.Name || 'OpenSign™ Drive', - File: x?.SignedUrl || x.URL, - Owner: x?.ExtUserPtr?.Name, - Signers: x?.Signers?.map(y => y?.Name) || '', - })) - : []; + if (res.data && res.data.results.length > 0) { + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + Title: x.Name, + Note: x.Note || '', + Folder: x?.Folder?.Name || 'OpenSign™ Drive', + File: x?.SignedUrl || x.URL, + Owner: x?.ExtUserPtr?.Name, + Signers: x?.Signers?.map(y => y?.Name) || '', + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); + return response.json({ result: updateRes }); } else { return response.json({ result: [] }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index 725a31109..20015f0b9 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -15,10 +15,19 @@ export default async function getUser(request, response) { const query = new Parse.Query('contracts_Users'); query.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); - let user = await query.first({ useMasterKey: true }); - const result = user; - if (result) { - return response.json({ result: result }); + const user = await query.first({ useMasterKey: true }); + if (user) { + const parseRes = JSON.parse(JSON.stringify(user)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + JobTitle: parseRes.JobTitle, + Company: parseRes.Company, + createdAt: parseRes.createdAt, + updateAt: parseRes.updateAt, + }); } else { return response.status(404).json({ error: 'User not found!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index cd475be77..c4dcf6279 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -1,68 +1,67 @@ export default async function updateDocument(request, response) { - try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const id = token.get('Id'); - const allowedKeys = ['Name', 'Note', 'Description']; - const objectKeys = Object.keys(request.body); - const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; - if (isValid) { - const userId = { __type: 'Pointer', className: '_User', objectId: id }; - const document = new Parse.Query('contracts_Document'); - document.equalTo('objectId', request.params.document_id); - document.equalTo('CreatedBy', userId); - const res = await document.first({ useMasterKey: true }); - if (res) { - const isArchive = res.get('IsArchive'); - if (isArchive && isArchive) { - return response.status(404).json({ message: 'Document not found!' }); - } else { - const document = Parse.Object.extend('contracts_Document'); - const updateQuery = new document(); - updateQuery.id = request.params.document_id; - if (request?.body?.Name) { - updateQuery.set('Name', request?.body?.Name); - } - if (request?.body?.Note) { - updateQuery.set('Note', request?.body?.Note); - } - if (request?.body?.Description) { - updateQuery.set('Name', request?.body?.Description); - } - if (request?.body?.FolderId) { - updateQuery.set('Folder', { - __type: 'Pointer', - className: 'contracts_Document', - objectId: request?.body?.FolderId, - }); - } - const updatedRes = await updateQuery.save(null, { useMasterKey: true }); - if (updatedRes) { - return response.json({ - message: 'Document updated successfully!', - result: { objectId: updatedRes.id }, - }); - } - } + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const allowedKeys = ['Name', 'Note', 'Description']; + const objectKeys = Object.keys(request.body); + const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + if (isValid) { + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const document = new Parse.Query('contracts_Document'); + document.equalTo('objectId', request.params.document_id); + document.equalTo('CreatedBy', userId); + const res = await document.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ message: 'Document not found!' }); } else { - return response.status(404).json({ error: 'Document not found!' }); + const document = Parse.Object.extend('contracts_Document'); + const updateQuery = new document(); + updateQuery.id = request.params.document_id; + if (request?.body?.Name) { + updateQuery.set('Name', request?.body?.Name); + } + if (request?.body?.Note) { + updateQuery.set('Note', request?.body?.Note); + } + if (request?.body?.Description) { + updateQuery.set('Name', request?.body?.Description); + } + if (request?.body?.FolderId) { + updateQuery.set('Folder', { + __type: 'Pointer', + className: 'contracts_Document', + objectId: request?.body?.FolderId, + }); + } + const updatedRes = await updateQuery.save(null, { useMasterKey: true }); + if (updatedRes) { + return response.json({ + objectId: updatedRes.id, + updatedAt: updatedRes.get('updatedAt'), + }); + } } } else { - return response.status(400).json({ error: 'Please provide valid field names!' }); + return response.status(404).json({ error: 'Document not found!' }); } } else { - return response.status(405).json({ error: 'Invalid API Token!' }); + return response.status(400).json({ error: 'Please provide valid field names!' }); } - } catch (err) { - console.log('err ', err); - return response.json(err); + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); } + } catch (err) { + console.log('err ', err); + return response.json(err); } - \ No newline at end of file +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index bc654bcbc..072e07e12 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -46,8 +46,8 @@ export default async function updateTemplate(request, response) { const updatedRes = await updateQuery.save(null, { useMasterKey: true }); if (updatedRes) { return response.json({ - message: 'Template updated successfully!', - result: { objectId: updatedRes.id }, + objectId: updatedRes.id, + updatedAt: updatedRes.get('updatedAt'), }); } } From eefaf5fe50653fa534de1fa4e8889cac44c81834 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Tue, 16 Jan 2024 17:43:42 +0530 Subject: [PATCH 14/73] feat: add migration script for generate token route --- apps/OpenSign/src/routes/GenerateToken.js | 27 +- .../cloud/customRoute/v1/apiV1.js | 44 +- .../customRoute/v1/routes/createDocument.js | 40 +- .../customRoute/v1/routes/createTemplate.js | 37 +- .../cloud/parsefunction/DocumentAftersave.js | 8 +- ...40116170302-add_generatetoken_menu_cjs.cjs | 652 ++++++++++++++++++ 6 files changed, 740 insertions(+), 68 deletions(-) create mode 100644 apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs diff --git a/apps/OpenSign/src/routes/GenerateToken.js b/apps/OpenSign/src/routes/GenerateToken.js index a507d29aa..ce74313d4 100644 --- a/apps/OpenSign/src/routes/GenerateToken.js +++ b/apps/OpenSign/src/routes/GenerateToken.js @@ -1,6 +1,7 @@ import React, { useEffect, useState } from "react"; import Title from "../components/Title"; import axios from "axios"; +import Alert from "../primitives/Alert"; function GenerateToken() { const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); @@ -8,6 +9,8 @@ function GenerateToken() { const [apiToken, SetApiToken] = useState(""); const [isLoader, setIsLoader] = useState(true); const [copied, setCopied] = useState(false); + const [isGenerate, setIsGenerate] = useState(false); + const [isErr, setIsErr] = useState(false); useEffect(() => { fetchToken(); @@ -47,17 +50,27 @@ function GenerateToken() { if (res) { SetApiToken(res.data.result.token); // localStorage.setItem("apiToken", res.data.result.token); - alert("Token generated successfully!"); + setIsGenerate(true); + setTimeout(() => { + setIsGenerate(false); + }, 1500); setIsLoader(false); } else { - alert("Something went wrong!"); console.error("Error while generating Token"); setIsLoader(false); + setIsErr(true); + setTimeout(() => { + setIsErr(false); + }, 1500); } }); } catch (error) { setIsLoader(false); - alert("Something went wrong!"); + setIsErr(true); + setTimeout(() => { + setIsErr(false); + }, 1500); + console.log("err", error); } }; @@ -72,11 +85,11 @@ function GenerateToken() { return ( <React.Fragment> <Title title={"token"} /> - {copied && ( - <div className={`alert alert-success alertBox`} role="alert"> - Copied - </div> + {isGenerate && ( + <Alert type="success">Token generated successfully!</Alert> )} + {copied && <Alert type="success">Copied</Alert>} + {isErr && <Alert type="danger">Something went wrong!</Alert>} {isLoader ? ( <div style={{ diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index ba6340f9b..84418f549 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -45,7 +45,7 @@ app.delete('/contact/:contact_id', deleteContact); app.get('/contactlist', getContactList); // create Document -app.post('/createdocument', createDocument); +app.post('/createdocument', upload.array('file', 1), createDocument); // get Document on the basis of id app.get('/document/:document_id', getDocument); @@ -60,7 +60,7 @@ app.delete('/document/:document_id', deleteDocument); app.get('/documentlist/:doctype', getDocumentList); // create Template -app.post('/createtemplate', createTemplate); +app.post('/createtemplate',upload.array('file', 1), createTemplate); // get template on the basis of id app.get('/template/:template_id', getTemplate); @@ -74,43 +74,3 @@ app.delete('/template/:template_id', deletedTemplate); // get all types of documents on the basis of doctype app.get('/templatelist', getTemplatetList); -app.post('/tempupload', upload.single('file'), async (req, res) => { - const name = req.body.name; - const note = req.body.note; - const description = req.body.description; - const fileFormat = req.body.fileFormat; // 'binary' or 'base64' - const filePath = req.body.filePath; // Path to the file - - let fileData; - - if (fileFormat === 'binary') { - // Read file content if the file is in binary format - fileData = fs.readFileSync(filePath); - } else if (fileFormat === 'base64') { - // Convert base64 data to binary - fileData = req.file ? req.file.buffer : null; - } else { - return res.status(400).json({ error: 'Invalid file format' }); - } - - // Create a Parse.File object - const file = new Parse.File('myfile', { base64: fileData.toString('base64') }); - - // Save the file to Parse Server - try { - await file.save(); - } catch (error) { - console.error('Error saving file to Parse Server:', error); - return res.status(500).json({ error: 'Internal Server Error' }); - } - - // Perform any desired processing with the received data - - // Respond to the client with the file URL - res.json({ - name: name, - note: note, - description: description, - fileUrl: file.url(), - }); -}); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index af2deae8b..0c7b190c8 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -1,13 +1,20 @@ +const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocument(request, response) { - const name = request.body.name; - const note = request.body.note; - const description = request.body.description; - const signers = request.body.signer; - const folderId = request.body.folderId; - const file = request.body.file; + const name = request.body.Title; + const note = request.body.Note; + const description = request.body.Description; + const signers = request.body.Signers; + const folderId = request.body.FolderId; + // const file = request.body.file; const url = process.env.SERVER_URL; - + const fileData = request.files[0] ? request.files[0].buffer : null; try { + const file = new Parse.File(request.files[0].originalname, { + base64: fileData.toString('base64'), + }); + await file.save({ useMasterKey: true }); + const fileUrl = file.url(); + const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -35,15 +42,30 @@ export default async function createDocument(request, response) { if (description) { object.set('Description', description); } - object.set('URL', file); + object.set('URL', fileUrl); object.set('CreatedBy', userId); object.set('ExtUserPtr', extUserPtr); if (signers) { - object.set('Signers', signers); + const placeholders = signers.map(x => ({ + email: x, + Id: randomId(), + Role: '', + blockColor: '', + signerObjId: '', + signerPtr: {}, + placeHolder: [], + })); + object.set('Placeholders', placeholders); } if (folderId) { object.set('Folder', folderPtr); } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(id, true); + newACL.setWriteAccess(id, true); + object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, url: url }); } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 381e85489..ab8b70596 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -1,12 +1,18 @@ export default async function createTemplate(request, response) { - const name = request.body.name; - const note = request.body.note; - const description = request.body.description; - const signers = request.body.signer; - const folderId = request.body.folderId; - const file = request.body.file; + const name = request.body.Title; + const note = request.body.Note; + const description = request.body.Description; + const signers = request.body.Signers; + const folderId = request.body.FolderId; + // const file = request.body.file; const url = process.env.SERVER_URL; + const fileData = request.files[0] ? request.files[0].buffer : null; try { + const file = new Parse.File(request.files[0].originalname, { + base64: fileData.toString('base64'), + }); + await file.save({ useMasterKey: true }); + const fileUrl = file.url(); const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -34,15 +40,30 @@ export default async function createTemplate(request, response) { if (description) { object.set('Description', description); } - object.set('URL', file); + object.set('URL', fileUrl); object.set('CreatedBy', userId); object.set('ExtUserPtr', extUserPtr); if (signers) { - object.set('Signers', signers); + const placeholders = signers.map(x => ({ + email: x, + Id: randomId(), + Role: '', + blockColor: '', + signerObjId: '', + signerPtr: {}, + placeHolder: [], + })); + object.set('Placeholders', placeholders); } if (folderId) { object.set('Folder', folderPtr); } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(id, true); + newACL.setWriteAccess(id, true); + object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, url: url }); } else { diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js index 3fd3ad125..cd9964640 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js @@ -43,7 +43,9 @@ async function DocumentAftersave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id) { + await updateSelfDoc(request.object.id); + } } } else { if (request.user) { @@ -51,7 +53,9 @@ async function DocumentAftersave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id) { + await updateSelfDoc(request.object.id); + } } } } diff --git a/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs new file mode 100644 index 000000000..0059b0a6a --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs @@ -0,0 +1,652 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const updateUserMenu = await userMenu.get('H9vRfEYKhT'); + updateUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'fa-solid fa-key', + title: 'Generate token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + ], + }, + ]); + + const AdminMenu = new Parse.Query(className); + const updateAdminMenu = await AdminMenu.get('VPh91h0ZHk'); + updateAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + { + icon: 'fa-solid fa-key', + title: 'Generate token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [updateUserMenu, updateAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + // TODO: set className here + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const revertUserMenu = await userMenu.get('H9vRfEYKhT'); + revertUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + ], + }, + ]); + + const adminMenu = new Parse.Query(className); + const revertAdminMenu = await adminMenu.get('VPh91h0ZHk'); + revertAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [revertUserMenu, revertAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; From a1a84b692834c75ce4bd7b906331b87677012e76 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Tue, 16 Jan 2024 18:09:10 +0530 Subject: [PATCH 15/73] fix: userId missing in aftersave of doucment and template cls --- .../cloud/customRoute/v1/routes/createTemplate.js | 5 +++-- .../cloud/parsefunction/DocumentAftersave.js | 2 +- .../cloud/parsefunction/TemplateAfterSave.js | 10 +++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index ab8b70596..c477cdf9d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -1,3 +1,4 @@ +const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createTemplate(request, response) { const name = request.body.Title; const note = request.body.Note; @@ -44,10 +45,10 @@ export default async function createTemplate(request, response) { object.set('CreatedBy', userId); object.set('ExtUserPtr', extUserPtr); if (signers) { - const placeholders = signers.map(x => ({ + const placeholders = signers.map((x, i) => ({ email: x, Id: randomId(), - Role: '', + Role: 'User ' + (i + 1), blockColor: '', signerObjId: '', signerPtr: {}, diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js index cd9964640..701ebd608 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js @@ -43,7 +43,7 @@ async function DocumentAftersave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - if (request?.object?.id) { + if (request?.object?.id && request.user) { await updateSelfDoc(request.object.id); } } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index 7d22ccb86..d5bcc168a 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -8,7 +8,9 @@ export default async function TemplateAfterSave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id && request.user) { + await updateSelfDoc(request.object.id); + } } } else { if (request.user) { @@ -16,7 +18,9 @@ export default async function TemplateAfterSave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id) { + await updateSelfDoc(request.object.id); + } } } } @@ -66,7 +70,7 @@ export default async function TemplateAfterSave(request) { async function updateSelfDoc(objId) { // console.log("Inside updateSelfDoc func") - + const Query = new Parse.Query('contracts_Template'); const updateACL = await Query.get(objId, { useMasterKey: true }); // const res = JSON.parse(JSON.stringify(updateACL)); From 4070409a59da8b2cfc20bde1fff639dd58049ce1 Mon Sep 17 00:00:00 2001 From: Andrew <148278535+andrew-opensignlabs@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:20:54 +0530 Subject: [PATCH 16/73] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c5d5b378..7a3ad6656 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,11 @@ 7. [Acknowledgments](#acknowledgments) --- +Please star ⭐ the repo to support us! 😀 ### Introduction -Welcome to OpenSign, an open-source document e-signing solution designed to provide a secure, reliable, and free alternative to commercial platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Developed under the OpenSignLabs organization, our mission is to democratize the e-signing process, making it accessible and straightforward for everyone. +Welcome to OpenSign, the premier open-source docusign alternative - document e-signing solution designed to provide a secure, reliable, and free alternative to commercial platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Developed under the OpenSignLabs organization, our mission is to democratize the e-signing process, making it accessible and straightforward for everyone. --- From 83df89c115cfba75657c833e98f3ff224756d4b6 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 17 Jan 2024 16:33:59 +0530 Subject: [PATCH 17/73] fix: create contact not working and handle err --- .../customRoute/v1/routes/createContact.js | 55 ++++++++++--------- .../customRoute/v1/routes/createDocument.js | 2 +- .../customRoute/v1/routes/createTemplate.js | 2 +- .../customRoute/v1/routes/deleteContact.js | 2 +- .../customRoute/v1/routes/deleteDocument.js | 2 +- .../customRoute/v1/routes/deleteTemplate.js | 2 +- .../cloud/customRoute/v1/routes/getContact.js | 2 +- .../customRoute/v1/routes/getContactList.js | 2 +- .../customRoute/v1/routes/getDocument.js | 2 +- .../customRoute/v1/routes/getTemplate.js | 2 +- .../customRoute/v1/routes/updateDocument.js | 2 +- .../customRoute/v1/routes/updateTemplate.js | 2 +- .../parsefunction/ContactBookAftersave.js | 8 +-- 13 files changed, 44 insertions(+), 41 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index b335f4889..c95691066 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -2,10 +2,9 @@ import axios from 'axios'; export default async function createContact(request, response) { const serverUrl = process.env.SERVER_URL; const appId = process.env.APP_ID; - const name = request.body.name; - const phone = request.body.phone; - const email = request.body.email; - + const name = request.body.Name; + const phone = request.body.Phone; + const email = request.body.Email; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -20,15 +19,14 @@ export default async function createContact(request, response) { try { const Tenant = new Parse.Query('partners_Tenant'); Tenant.equalTo('UserId', userId); - const tenantRes = Tenant.first({ useMasterKey: true }); + const tenantRes = await Tenant.first({ useMasterKey: true }); const contactQuery = new Parse.Object('contracts_Contactbook'); contactQuery.set('Name', name); contactQuery.set('Phone', phone); contactQuery.set('Email', email); contactQuery.set('UserRole', 'contracts_Guest'); - - if (tenantRes) { + if (tenantRes && tenantRes.id) { contactQuery.set('TenantId', { __type: 'Pointer', className: 'partners_Tenant', @@ -58,23 +56,26 @@ export default async function createContact(request, response) { userId: user.id, }; await axios.post(roleurl, body, { headers: headers }); - const currentUser = Parse.User.current(); - contactQuery.set('CreatedBy', Parse.User.createWithoutData(currentUser.id)); - + const currentUser = userId; + contactQuery.set('CreatedBy', currentUser); contactQuery.set('UserId', user); + const acl = new Parse.ACL(); - acl.setReadAccess(currentUser.id, true); - acl.setWriteAccess(currentUser.id, true); + acl.setReadAccess(id, true); + acl.setWriteAccess(id, true); acl.setReadAccess(user.id, true); acl.setWriteAccess(user.id, true); - contactQuery.setACL(acl); const contactRes = await contactQuery.save(); - // const parseData = JSON.parse(JSON.stringify(res)); + const parseRes = JSON.parse(JSON.stringify(contactRes)); return response.json({ - message: 'Contact created sucessfully!', - result: { objectId: contactRes.id }, + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, }); } } catch (err) { @@ -82,10 +83,10 @@ export default async function createContact(request, response) { if (err.code === 202) { const params = { email: email }; const userRes = await Parse.Cloud.run('getUserId', params); - const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const roleurl = `${serverUrl}/functions/AddUserToRole`; const headers = { 'Content-Type': 'application/json', - 'X-Parse-Application-Id': parseAppId, + 'X-Parse-Application-Id': appId, // sessionToken: localStorage.getItem('accesstoken'), }; const body = { @@ -94,17 +95,15 @@ export default async function createContact(request, response) { userId: userRes.id, }; await axios.post(roleurl, body, { headers: headers }); - const currentUser = Parse.User.current(); - contactQuery.set('CreatedBy', Parse.User.createWithoutData(currentUser.id)); - + contactQuery.set('CreatedBy', userId); contactQuery.set('UserId', { __type: 'Pointer', className: '_User', objectId: userRes.id, }); const acl = new Parse.ACL(); - acl.setReadAccess(currentUser.id, true); - acl.setWriteAccess(currentUser.id, true); + acl.setReadAccess(id, true); + acl.setWriteAccess(id, true); acl.setReadAccess(userRes.id, true); acl.setWriteAccess(userRes.id, true); @@ -118,14 +117,18 @@ export default async function createContact(request, response) { Email: parseRes.Email, Phone: parseRes.Phone, createdAt: parseRes.createdAt, - updateAt: parseRes.updateAt, + updatedAt: parseRes.updatedAt, }); } - // const parseData = JSON.parse(JSON.stringify(res)); + } else { + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } } } catch (err) { - return response.status(404).json({ error: 'Something went wrong, please try again later!' }); + console.log('err ', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 0c7b190c8..2724e3fc6 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -73,6 +73,6 @@ export default async function createDocument(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index c477cdf9d..a2728bbcd 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -72,6 +72,6 @@ export default async function createTemplate(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index e0997f160..1dadb0e0f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -40,6 +40,6 @@ export default async function deleteContact(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js index d3faa0c9d..71259085f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js @@ -40,6 +40,6 @@ export default async function deleteDocument(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index f8e1c5ade..de3586195 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -40,6 +40,6 @@ export default async function deletedTemplate(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index e0438036a..ad5eea4d5 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -36,6 +36,6 @@ export default async function getContact(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 93a28b757..02c6dd620 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -38,6 +38,6 @@ export default async function getContactList(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index 0417dd354..d59ba86b2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -40,6 +40,6 @@ export default async function getDocument(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index 8a7b4ec79..2621707fc 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -40,6 +40,6 @@ export default async function getTemplate(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index c4dcf6279..f30b07389 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -62,6 +62,6 @@ export default async function updateDocument(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 072e07e12..c2cdbbeee 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -62,6 +62,6 @@ export default async function updateTemplate(request, response) { } } catch (err) { console.log('err ', err); - return response.json(err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js b/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js index 644a2a763..fa476e60f 100644 --- a/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js @@ -3,13 +3,13 @@ async function ContactbookAftersave(request) { you can check as follows */ if (!request.original) { const user = request.user; - const object = request.object; - + // Retrieve the current ACL const acl = new Parse.ACL(); - + // Ensure the current user has read access - if (acl) { + if (acl && request?.user) { + const object = request.object; acl.setReadAccess(user, true); acl.setWriteAccess(user, true); acl.setReadAccess(object.get('UserId'), true); From 39f3f7389631440b2d545831964d396fe07563e8 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 18 Jan 2024 12:15:46 +0530 Subject: [PATCH 18/73] feat: add docs tab in profile menu --- apps/OpenSign/src/components/Header.js | 7 +++++++ apps/OpenSign/src/constant/Utils.js | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 apps/OpenSign/src/constant/Utils.js diff --git a/apps/OpenSign/src/components/Header.js b/apps/OpenSign/src/components/Header.js index f15af8a65..2ed4af269 100644 --- a/apps/OpenSign/src/components/Header.js +++ b/apps/OpenSign/src/components/Header.js @@ -4,6 +4,7 @@ import FullScreenButton from "./FullScreenButton"; import { useNavigate } from "react-router-dom"; import Parse from "parse"; import { useWindowSize } from "../hook/useWindowSize"; +import { openInNewTab } from "../constant/Utils"; const Header = ({ showSidebar }) => { const navigation = useNavigate(); const { width } = useWindowSize(); @@ -118,6 +119,12 @@ const Header = ({ showSidebar }) => { <ul> <li className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal" + onClick={() => openInNewTab("https://docs.opensignlabs.com")} + > + <i className="fa-solid fa-book"></i> Docs + </li> + <li + className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal" onClick={() => { setIsOpen(false); navigation("/profile"); diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js new file mode 100644 index 000000000..aa44a9b13 --- /dev/null +++ b/apps/OpenSign/src/constant/Utils.js @@ -0,0 +1,3 @@ +export const openInNewTab = (url) => { + window.open(url, "_blank", "noopener,noreferrer"); +}; From 2a8cedca589033bd308b3f33f049c01e72959258 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 19 Jan 2024 00:33:08 +0530 Subject: [PATCH 19/73] change userId type from string to pointer in appToken class and handle stringify array --- apps/OpenSign/src/json/plansArr.json | 2 +- .../src/primitives/GetReportDisplay.js | 2 +- .../cloud/customRoute/v1/apiV1.js | 8 +++-- .../customRoute/v1/routes/createContact.js | 30 ++++++++++++------- .../customRoute/v1/routes/createDocument.js | 25 ++++++++-------- .../customRoute/v1/routes/createTemplate.js | 23 +++++++------- .../customRoute/v1/routes/deleteContact.js | 5 ++-- .../customRoute/v1/routes/deleteDocument.js | 5 ++-- .../customRoute/v1/routes/deleteTemplate.js | 5 ++-- .../cloud/customRoute/v1/routes/getContact.js | 5 ++-- .../customRoute/v1/routes/getContactList.js | 6 ++-- .../customRoute/v1/routes/getDocument.js | 5 ++-- .../customRoute/v1/routes/getDocumentList.js | 20 ++++++------- .../customRoute/v1/routes/getTemplate.js | 5 ++-- .../customRoute/v1/routes/getTemplateList.js | 8 ++--- .../cloud/customRoute/v1/routes/getUser.js | 6 ++-- .../customRoute/v1/routes/updateDocument.js | 7 ++--- .../customRoute/v1/routes/updateTemplate.js | 5 ++-- .../cloud/parsefunction/generateApiToken.js | 4 +-- .../cloud/parsefunction/getapitoken.js | 9 ++++-- apps/OpenSignServer/index.js | 1 + 21 files changed, 94 insertions(+), 92 deletions(-) diff --git a/apps/OpenSign/src/json/plansArr.json b/apps/OpenSign/src/json/plansArr.json index d4ae65baa..8d337fdb0 100644 --- a/apps/OpenSign/src/json/plansArr.json +++ b/apps/OpenSign/src/json/plansArr.json @@ -33,7 +33,7 @@ "target": "_self", "benefits": [ "Sign Unlimited Documents", - "Unlimited Secure Doc Storage with OpenSignDrive", + "Unlimited Secure Doc Storage with OpenSign™ Drive", "Unlimited Guest Signers", "Unlimited completion certificates", "Unique Code(OTP) verification for guest signers", diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js index b9786d55d..8e50fb667 100644 --- a/apps/OpenSign/src/primitives/GetReportDisplay.js +++ b/apps/OpenSign/src/primitives/GetReportDisplay.js @@ -371,7 +371,7 @@ const ReportTable = ({ )} {heading.includes("Folder") && ( <td className="px-4 py-2"> - {item?.Folder?.Name || "OpenSignDrive"} + {item?.Folder?.Name || "OpenSign™ Drive"} </td> )} <td className="px-4 py-2"> diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 84418f549..2d6d391c0 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -17,9 +17,10 @@ import getTemplatetList from './routes/getTemplateList.js'; import updateTemplate from './routes/updateTemplate.js'; import createContact from './routes/createContact.js'; import multer from 'multer'; -import fs from 'node:fs'; +// import fs from 'node:fs'; import updateDocument from './routes/updateDocument.js'; import deleteDocument from './routes/deleteDocument.js'; +// import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; dotenv.config(); const storage = multer.memoryStorage(); @@ -47,6 +48,8 @@ app.get('/contactlist', getContactList); // create Document app.post('/createdocument', upload.array('file', 1), createDocument); +// create Document with templateId +// app.post('/createdocument/:template_id', createDocumentWithTemplate); // get Document on the basis of id app.get('/document/:document_id', getDocument); @@ -60,7 +63,7 @@ app.delete('/document/:document_id', deleteDocument); app.get('/documentlist/:doctype', getDocumentList); // create Template -app.post('/createtemplate',upload.array('file', 1), createTemplate); +app.post('/createtemplate', upload.array('file', 1), createTemplate); // get template on the basis of id app.get('/template/:template_id', getTemplate); @@ -73,4 +76,3 @@ app.delete('/template/:template_id', deletedTemplate); // get all types of documents on the basis of doctype app.get('/templatelist', getTemplatetList); - diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index c95691066..2079f059a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -14,11 +14,10 @@ export default async function createContact(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); try { const Tenant = new Parse.Query('partners_Tenant'); - Tenant.equalTo('UserId', userId); + Tenant.equalTo('UserId', userPtr); const tenantRes = await Tenant.first({ useMasterKey: true }); const contactQuery = new Parse.Object('contracts_Contactbook'); @@ -56,13 +55,13 @@ export default async function createContact(request, response) { userId: user.id, }; await axios.post(roleurl, body, { headers: headers }); - const currentUser = userId; + const currentUser = userPtr; contactQuery.set('CreatedBy', currentUser); contactQuery.set('UserId', user); const acl = new Parse.ACL(); - acl.setReadAccess(id, true); - acl.setWriteAccess(id, true); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); acl.setReadAccess(user.id, true); acl.setWriteAccess(user.id, true); contactQuery.setACL(acl); @@ -79,7 +78,7 @@ export default async function createContact(request, response) { }); } } catch (err) { - console.log('err ', err); + console.log('err in', err); if (err.code === 202) { const params = { email: email }; const userRes = await Parse.Cloud.run('getUserId', params); @@ -95,15 +94,15 @@ export default async function createContact(request, response) { userId: userRes.id, }; await axios.post(roleurl, body, { headers: headers }); - contactQuery.set('CreatedBy', userId); + contactQuery.set('CreatedBy', userPtr); contactQuery.set('UserId', { __type: 'Pointer', className: '_User', objectId: userRes.id, }); const acl = new Parse.ACL(); - acl.setReadAccess(id, true); - acl.setWriteAccess(id, true); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); acl.setReadAccess(userRes.id, true); acl.setWriteAccess(userRes.id, true); @@ -121,6 +120,9 @@ export default async function createContact(request, response) { }); } } else { + if (err.code === 137) { + return response.status(401).json({ error: 'Contact already exists!' }); + } return response .status(400) .json({ error: 'Something went wrong, please try again later!' }); @@ -128,7 +130,13 @@ export default async function createContact(request, response) { } } catch (err) { console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); + if (err.code === 137) { + return response.status(137).json({ error: 'Contact already exists!' }); + } else { + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); + } } } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 2724e3fc6..05c99ccde 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -9,12 +9,6 @@ export default async function createDocument(request, response) { const url = process.env.SERVER_URL; const fileData = request.files[0] ? request.files[0].buffer : null; try { - const file = new Parse.File(request.files[0].originalname, { - base64: fileData.toString('base64'), - }); - await file.save({ useMasterKey: true }); - const fileUrl = file.url(); - const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -24,11 +18,15 @@ export default async function createDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); + const file = new Parse.File(request.files?.[0]?.originalname, { + base64: fileData.toString('base64'), + }); + await file.save({ useMasterKey: true }); + const fileUrl = file.url(); const contractsUser = new Parse.Query('contracts_Users'); - contractsUser.equalTo('UserId', userId); + contractsUser.equalTo('UserId', userPtr); const extUser = await contractsUser.first({ useMasterKey: true }); const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; @@ -43,10 +41,11 @@ export default async function createDocument(request, response) { object.set('Description', description); } object.set('URL', fileUrl); - object.set('CreatedBy', userId); + object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); if (signers) { - const placeholders = signers.map(x => ({ + const parseSigners = JSON.parse(signers); + const placeholders = parseSigners.map(x => ({ email: x, Id: randomId(), Role: '', @@ -63,8 +62,8 @@ export default async function createDocument(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(id, true); - newACL.setWriteAccess(id, true); + newACL.setReadAccess(userPtr.id, true); + newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, url: url }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index a2728bbcd..83580707f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -9,11 +9,6 @@ export default async function createTemplate(request, response) { const url = process.env.SERVER_URL; const fileData = request.files[0] ? request.files[0].buffer : null; try { - const file = new Parse.File(request.files[0].originalname, { - base64: fileData.toString('base64'), - }); - await file.save({ useMasterKey: true }); - const fileUrl = file.url(); const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -23,9 +18,12 @@ export default async function createTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; - + const userPtr = token.get('userId'); + const file = new Parse.File(request.files?.[0]?.originalname, { + base64: fileData.toString('base64'), + }); + await file.save({ useMasterKey: true }); + const fileUrl = file.url(); const contractsUser = new Parse.Query('contracts_Users'); contractsUser.equalTo('UserId', userId); const extUser = await contractsUser.first({ useMasterKey: true }); @@ -42,10 +40,11 @@ export default async function createTemplate(request, response) { object.set('Description', description); } object.set('URL', fileUrl); - object.set('CreatedBy', userId); + object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); if (signers) { - const placeholders = signers.map((x, i) => ({ + const parseSigners = JSON.parse(signers); + const placeholders = parseSigners.map((x, i) => ({ email: x, Id: randomId(), Role: 'User ' + (i + 1), @@ -62,8 +61,8 @@ export default async function createTemplate(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(id, true); - newACL.setWriteAccess(id, true); + newACL.setReadAccess(userPtr.id, true); + newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, url: url }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index 1dadb0e0f..b9e57012a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -9,11 +9,10 @@ export default async function deleteContact(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('objectId', request.params.contact_id); - Contactbook.equalTo('CreatedBy', userId); + Contactbook.equalTo('CreatedBy', userPtr); const res = await Contactbook.first({ useMasterKey: true }); if (res) { const isDeleted = res.get('IsDeleted'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js index 71259085f..543dd73ba 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js @@ -9,11 +9,10 @@ export default async function deleteDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const Document = new Parse.Query('contracts_Document'); Document.equalTo('objectId', request.params.document_id); - Document.equalTo('CreatedBy', userId); + Document.equalTo('CreatedBy', userPtr); const res = await Document.first({ useMasterKey: true }); if (res) { const isArchive = res.get('IsArchive'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index de3586195..9967f9001 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -9,11 +9,10 @@ export default async function deletedTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const template = new Parse.Query('contracts_Template'); template.equalTo('objectId', request.params.template_id); - template.equalTo('CreatedBy', userId); + template.equalTo('CreatedBy', userPtr); const res = await template.first({ useMasterKey: true }); if (res) { const isArchive = res.get('IsArchive'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index ad5eea4d5..0a68b31bc 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -9,11 +9,10 @@ export default async function getContact(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('objectId', request.params.contact_id); - Contactbook.equalTo('CreatedBy', userId); + Contactbook.equalTo('CreatedBy', userPtr); Contactbook.notEqualTo('IsDeleted', true); Contactbook.select('Name,Email,Phone'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 02c6dd620..a6b74a819 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -9,12 +9,12 @@ export default async function getContactList(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); + const limit = request?.query?.limit ? request.query.limit : 100; const skip = request?.query?.skip ? request.query.skip : 0; const Contactbook = new Parse.Query('contracts_Contactbook'); - Contactbook.equalTo('CreatedBy', userId); + Contactbook.equalTo('CreatedBy', userPtr); Contactbook.notEqualTo('IsDeleted', true); Contactbook.limit(limit); Contactbook.skip(skip); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index d59ba86b2..76046aa5e 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -9,11 +9,10 @@ export default async function getDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const Document = new Parse.Query('contracts_Document'); Document.equalTo('objectId', request.params.document_id); - Document.equalTo('CreatedBy', userId); + Document.equalTo('CreatedBy', userPtr); Document.notEqualTo('IsArchive', true); Document.include('Signers'); Document.include('Folder'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 3ef4d338c..f586cc2c6 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -15,7 +15,7 @@ export default async function getDocumentList(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userId = token.get('Id'); + const userPtr = token.get('userId'); const docType = request.params.doctype; const limit = request?.query?.limit ? request.query.limit : 100; const skip = request?.query?.skip ? request.query.skip : 0; @@ -42,7 +42,7 @@ export default async function getDocumentList(request, response) { default: reportId = ''; } - const json = reportId && reportJson(reportId, userId); + const json = reportId && reportJson(reportId, userPtr.id); const clsName = 'contracts_Document'; if (reportId && json) { const { params, keys } = json; @@ -59,14 +59,14 @@ export default async function getDocumentList(request, response) { if (res.data && res.data.results.length > 0) { const updateRes = res.data.results.map(x => ({ objectId: x.objectId, - title: x.Name, - note: x.Note || '', - folder: x?.Folder?.Name || 'OpenSign™ Drive', - file: x?.SignedUrl || x.URL, - owner: x?.ExtUserPtr?.Name, - signers: x?.Signers?.map(y => y?.Name) || '', - created_at: x.createdAt, - updated_at: x.updatedAt, + Title: x.Name, + Note: x.Note || '', + Folder: x?.Folder?.Name || 'OpenSign™ Drive', + File: x?.SignedUrl || x.URL, + Owner: x?.ExtUserPtr?.Name, + Signers: x?.Signers?.map(y => y?.Name) || '', + createdAt: x.createdAt, + updatedAt: x.updatedAt, })); return response.json({ result: updateRes }); } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index 2621707fc..f69bd896a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -9,11 +9,10 @@ export default async function getTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const Template = new Parse.Query('contracts_Template'); Template.equalTo('objectId', request.params.template_id); - Template.equalTo('CreatedBy', userId); + Template.equalTo('CreatedBy', userPtr); Template.notEqualTo('IsArchive', true); Template.include('Signers'); Template.include('Folder'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index d8e046853..0e641e20a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -14,18 +14,14 @@ export default async function getTemplatetList(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userId = token.get('Id'); + const userPtr = token.get('userId'); const limit = request?.query?.limit ? request.query.limit : 100; const skip = request?.query?.skip ? request.query.skip : 0; const clsName = 'contracts_Template'; const params = { Type: { $ne: 'Folder' }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: userId, - }, + CreatedBy: userPtr, IsArchive: { $ne: true }, }; const keys = [ diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index 20015f0b9..54f92ef52 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -11,9 +11,9 @@ export default async function getUser(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userId = token.get('Id'); + const userPtr = token.get('userId'); const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); + query.equalTo('UserId', userPtr); query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); const user = await query.first({ useMasterKey: true }); if (user) { @@ -26,7 +26,7 @@ export default async function getUser(request, response) { JobTitle: parseRes.JobTitle, Company: parseRes.Company, createdAt: parseRes.createdAt, - updateAt: parseRes.updateAt, + updatedAt: parseRes.updatedAt, }); } else { return response.status(404).json({ error: 'User not found!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index f30b07389..2f0b76c53 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -8,16 +8,15 @@ export default async function updateDocument(request, response) { tokenQuery.equalTo('token', reqToken); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { - // Valid Token then proceed request - const id = token.get('Id'); + // Valid Token then proceed request const allowedKeys = ['Name', 'Note', 'Description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const document = new Parse.Query('contracts_Document'); document.equalTo('objectId', request.params.document_id); - document.equalTo('CreatedBy', userId); + document.equalTo('CreatedBy', userPtr); const res = await document.first({ useMasterKey: true }); if (res) { const isArchive = res.get('IsArchive'); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index c2cdbbeee..d3445bcf5 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -9,15 +9,14 @@ export default async function updateTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const id = token.get('Id'); const allowedKeys = ['Name', 'Note', 'Description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { - const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const userPtr = token.get('userId'); const template = new Parse.Query('contracts_Template'); template.equalTo('objectId', request.params.template_id); - template.equalTo('CreatedBy', userId); + template.equalTo('CreatedBy', userPtr); const res = await template.first({ useMasterKey: true }); if (res) { const isArchive = res.get('IsArchive'); diff --git a/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js index bdf7842cc..8f39ccfdb 100644 --- a/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js +++ b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js @@ -12,7 +12,7 @@ export default async function generateApiToken(request) { const userId = userRes.data && userRes.data.objectId; if (userId) { const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('Id', userId); + tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId }); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // return exsiting Token @@ -31,7 +31,7 @@ export default async function generateApiToken(request) { const appTokenQuery = new appToken(); const token = generateApiKey({ method: 'base62', prefix: 'opensign' }); appTokenQuery.set('token', token); - appTokenQuery.set('Id', userId); + appTokenQuery.set('userId', { __type: 'Pointer', className: '_User', objectId: userId }); const newRes = await appTokenQuery.save(null, { useMasterKey: true }); return newRes; } diff --git a/apps/OpenSignServer/cloud/parsefunction/getapitoken.js b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js index 5e12d6a39..570679f57 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getapitoken.js +++ b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js @@ -11,7 +11,7 @@ export default async function getapitoken(request) { const userId = userRes.data && userRes.data.objectId; if (userId) { const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('Id', userId); + 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') }; @@ -19,6 +19,11 @@ export default async function getapitoken(request) { } } catch (err) { console.log('Err', err); - return { status: 'error', result: err }; + console.log('err', err); + if (err.code == 209) { + return { error: 'Invalid session token' }; + } else { + return { error: "You don't have access!" }; + } } } diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index b69429e59..92deb1572 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -74,6 +74,7 @@ export const config = { import('./cloud/main.js'); }, appId: process.env.APP_ID || 'myAppId', + maxLimit: 500, masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret! masterKeyIps: ['0.0.0.0/0', '::1'], // '::1' serverURL: process.env.SERVER_URL || 'http://localhost:8080/app', // Don't forget to change to https if needed From 34fc3afb1e989df3e12e9e8686fbb0af11912c43 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 19 Jan 2024 18:08:35 +0530 Subject: [PATCH 20/73] enable automatic redirect to rememberd url after login --- apps/OpenSign/src/App.js | 116 +++--------------- apps/OpenSign/src/layout/HomeLayout.js | 69 +++++++---- apps/OpenSign/src/primitives/ValidateRoute.js | 6 +- apps/OpenSign/src/routes/Dashboard.js | 2 +- apps/OpenSign/src/routes/Login.js | 41 +++---- apps/OpenSign/src/routes/Pgsignup.js | 23 ++-- apps/OpenSign/src/routes/PlanSubscriptions.js | 27 +--- 7 files changed, 103 insertions(+), 181 deletions(-) diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index 3e0119d85..deb9b19f6 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -7,7 +7,7 @@ import Signup from "./routes/Signup"; import Form from "./routes/Form"; import Report from "./routes/Report"; import Dashboard from "./routes/Dashboard"; -import PlanSubscriptions from "./routes/PlanSubscriptions"; +import Subscriptions from "./routes/PlanSubscriptions"; import HomeLayout from "./layout/HomeLayout"; import UserProfile from "./routes/UserProfile"; import PageNotFound from "./routes/PageNotFound"; @@ -60,112 +60,30 @@ function App() { ) : ( <BrowserRouter> <Routes> - <Route - exact - path="/" - element={ - <ValidateRoute> - <Login /> - </ValidateRoute> - } - /> - <Route - exact - path="/signup" - element={ - <ValidateRoute> - <Signup /> - </ValidateRoute> - } - /> + <Route element={<ValidateRoute />}> + <Route exact path="/" element={<Login />} /> + <Route exact path="/signup" element={<Signup />} /> + </Route> <Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} /> <Route exact path="/forgetpassword" element={<ForgetPassword />} /> {process.env.REACT_APP_ENABLE_SUBSCRIPTION && ( <> <Route exact path="/pgsignup" element={<Pgsignup />} /> - <Route - exact - path="/subscription" - element={<PlanSubscriptions />} - /> + <Route exact path="/subscription" element={<Subscriptions />} /> </> )} - <Route - exact - path="/changepassword" - element={ - <HomeLayout> - <ChangePassword /> - </HomeLayout> - } - /> - <Route - path="/mf/:remoteApp/*" - element={ - <HomeLayout> - <Microapp /> - </HomeLayout> - } - /> - <Route - path="/asmf/:remoteApp/*" - element={ - <HomeLayout> - <Microapp /> - </HomeLayout> - } - /> - <Route - path="/rpmf/:remoteApp/*" - element={ - <HomeLayout> - <ReportMicroapp /> - </HomeLayout> - } - /> - <Route - path="/form/:id" - element={ - <HomeLayout> - <Form /> - </HomeLayout> - } - /> - <Route - path="/report/:id" - element={ - <HomeLayout> - <Report /> - </HomeLayout> - } - /> - <Route - path="/dashboard/:id" - element={ - <HomeLayout> - <Dashboard /> - </HomeLayout> - } - /> - - <Route - path="/profile" - element={ - <HomeLayout> - <UserProfile /> - </HomeLayout> - } - /> - <Route - path="/generatetoken" - element={ - <HomeLayout> - <GenerateToken /> - </HomeLayout> - } - /> + <Route element={<HomeLayout />}> + <Route path="/changepassword" element={<ChangePassword />} /> + <Route path="/mf/:remoteApp/*" element={<Microapp />} /> + <Route path="/asmf/:remoteApp/*" element={<Microapp />} /> + <Route path="/rpmf/:remoteApp/*" element={<ReportMicroapp />} /> + <Route path="/form/:id" element={<Form />} /> + <Route path="/report/:id" element={<Report />} /> + <Route path="/dashboard/:id" element={<Dashboard />} /> + <Route path="/profile" element={<UserProfile />} /> + <Route path="/generatetoken" element={<GenerateToken />} /> + </Route> <Route path="*" element={<PageNotFound />} /> - {/* <Route exact path="/ForgotPassword" element={<ForgotPassword />} /> */} </Routes> </BrowserRouter> )} diff --git a/apps/OpenSign/src/layout/HomeLayout.js b/apps/OpenSign/src/layout/HomeLayout.js index a0ca72170..5fbf2f84f 100644 --- a/apps/OpenSign/src/layout/HomeLayout.js +++ b/apps/OpenSign/src/layout/HomeLayout.js @@ -8,15 +8,16 @@ import axios from "axios"; import { useSelector } from "react-redux"; import Parse from "parse"; import ModalUi from "../primitives/ModalUi"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useLocation, Outlet } from "react-router-dom"; -const HomeLayout = ({ children }) => { +const HomeLayout = () => { const navigate = useNavigate(); + const location = useLocation(); const { width } = useWindowSize(); const [isOpen, setIsOpen] = useState(true); const arr = useSelector((state) => state.TourSteps); const [isUserValid, setIsUserValid] = useState(true); - + const [isLoader, setIsLoader] = useState(true); useEffect(() => { (async () => { try { @@ -27,6 +28,7 @@ const HomeLayout = ({ children }) => { }); if (user) { setIsUserValid(true); + setIsLoader(false); } else { setIsUserValid(false); } @@ -184,7 +186,7 @@ const HomeLayout = ({ children }) => { console.log("err ", err); } finally { localStorage.removeItem("accesstoken"); - navigate("/", { replace: true }); + navigate("/", { replace: true, state: { from: location } }); } }; return ( @@ -194,27 +196,48 @@ const HomeLayout = ({ children }) => { </div> {isUserValid ? ( <> - <div className="flex md:flex-row flex-col z-50"> - <Sidebar isOpen={isOpen} closeSidebar={closeSidebar} /> + {isLoader ? ( + <div + style={{ + height: "100vh", + display: "flex", + alignItems: "center", + justifyContent: "center" + }} + > + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + ) : ( + <> + <div className="flex md:flex-row flex-col z-50"> + <Sidebar isOpen={isOpen} closeSidebar={closeSidebar} /> - <div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"> - <div className="bg-[#eef1f5] p-3">{children}</div> - <div className="z-30"> - <Footer /> + <div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"> + <div className="bg-[#eef1f5] p-3">{<Outlet />}</div> + <div className="z-30"> + <Footer /> + </div> + </div> </div> - </div> - </div> - <Tour - onRequestClose={closeTour} - steps={tourConfigs} - isOpen={isTour} - closeWithMask={false} - disableKeyboardNavigation={["esc"]} - // disableInteraction={true} - scrollOffset={-100} - rounded={5} - showCloseButton={isCloseBtn} - /> + <Tour + onRequestClose={closeTour} + steps={tourConfigs} + isOpen={isTour} + closeWithMask={false} + disableKeyboardNavigation={["esc"]} + // disableInteraction={true} + scrollOffset={-100} + rounded={5} + showCloseButton={isCloseBtn} + /> + </> + )} </> ) : ( <ModalUi title={"Session Expired"} isOpen={true} showClose={false}> diff --git a/apps/OpenSign/src/primitives/ValidateRoute.js b/apps/OpenSign/src/primitives/ValidateRoute.js index 62202dfe6..9c4f01e07 100644 --- a/apps/OpenSign/src/primitives/ValidateRoute.js +++ b/apps/OpenSign/src/primitives/ValidateRoute.js @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import Parse from "parse"; - -const ValidateRoute = ({ children }) => { +import { Outlet } from "react-router-dom"; +const ValidateRoute = () => { useEffect(() => { (async () => { try { @@ -28,7 +28,7 @@ const ValidateRoute = ({ children }) => { localStorage.removeItem("accesstoken"); } }; - return <div>{children}</div>; + return <div>{<Outlet />}</div>; }; export default ValidateRoute; diff --git a/apps/OpenSign/src/routes/Dashboard.js b/apps/OpenSign/src/routes/Dashboard.js index 2bc3d9bc7..e381cf364 100644 --- a/apps/OpenSign/src/routes/Dashboard.js +++ b/apps/OpenSign/src/routes/Dashboard.js @@ -24,7 +24,7 @@ const Dashboard = (props) => { getDashboard(localStorage.getItem("PageLanding")); } } else { - navigate("/", { replace: true }); + navigate("/", { replace: true, state: { from: location } }); } // eslint-disable-next-line }, [id]); diff --git a/apps/OpenSign/src/routes/Login.js b/apps/OpenSign/src/routes/Login.js index b9584b243..53d349211 100644 --- a/apps/OpenSign/src/routes/Login.js +++ b/apps/OpenSign/src/routes/Login.js @@ -8,12 +8,13 @@ import axios from "axios"; import Title from "../components/Title"; import GoogleSignInBtn from "../components/LoginGoogle"; // import LoginFacebook from "../components/LoginFacebook"; -import { NavLink, useNavigate } from "react-router-dom"; +import { NavLink, useNavigate, useLocation } from "react-router-dom"; import login_img from "../assets/images/login_img.svg"; import { useWindowSize } from "../hook/useWindowSize"; function Login(props) { const navigate = useNavigate(); + const location = useLocation(); const { width } = useWindowSize(); const [state, setState] = useState({ email: "", @@ -132,6 +133,9 @@ function Login(props) { `${localStorage.getItem("_appName")}_appeditor` ) { userSettings.forEach(async (element) => { + const redirectUrl = + location?.state?.from || + `/${element.pageType}/${element.pageId}`; if (element.role === _currentRole) { let _role = _currentRole.replace( `${localStorage.getItem("_appName")}_`, @@ -260,9 +264,8 @@ function Login(props) { localStorage.removeItem( "userDetails" ); - navigate( - `/${element.pageType}/${element.pageId}` - ); + // Redirect to the appropriate URL after successful login + navigate(redirectUrl); } else { navigate(`/subscription`, { replace: true @@ -274,9 +277,8 @@ function Login(props) { }); } } else { - navigate( - `/${element.pageType}/${element.pageId}` - ); + // Redirect to the appropriate URL after successful login + navigate(redirectUrl); } } } else { @@ -313,9 +315,8 @@ function Login(props) { }); } } else { - navigate( - `/${element.pageType}/${element.pageId}` - ); + // Redirect to the appropriate URL after successful login + navigate(redirectUrl); } } }, @@ -462,6 +463,9 @@ function Login(props) { `${localStorage.getItem("_appName")}_appeditor` ) { userSettings.forEach(async (element) => { + const redirectUrl = + location?.state?.from || + `/${element.pageType}/${element.pageId}`; if (element.role === _currentRole) { let _role = _currentRole.replace( `${localStorage.getItem("_appName")}_`, @@ -569,9 +573,7 @@ function Login(props) { if (billingDate) { if (billingDate > new Date()) { localStorage.removeItem("userDetails"); - navigate( - `/${element.pageType}/${element.pageId}` - ); + navigate(redirectUrl); } else { navigate(`/subscription`, { replace: true @@ -581,9 +583,7 @@ function Login(props) { navigate(`/subscription`, { replace: true }); } } else { - navigate( - `/${element.pageType}/${element.pageId}` - ); + navigate(redirectUrl); } } } else { @@ -599,9 +599,8 @@ function Login(props) { if (billingDate) { if (billingDate > new Date()) { localStorage.removeItem("userDetails"); - navigate( - `/${element.pageType}/${element.pageId}` - ); + // Redirect to the appropriate URL after successful login + navigate(redirectUrl); } else { navigate(`/subscription`, { replace: true }); } @@ -609,9 +608,7 @@ function Login(props) { navigate(`/subscription`, { replace: true }); } } else { - navigate( - `/${element.pageType}/${element.pageId}` - ); + navigate(redirectUrl); } } }, diff --git a/apps/OpenSign/src/routes/Pgsignup.js b/apps/OpenSign/src/routes/Pgsignup.js index af4cc0108..f3d12437d 100644 --- a/apps/OpenSign/src/routes/Pgsignup.js +++ b/apps/OpenSign/src/routes/Pgsignup.js @@ -5,7 +5,7 @@ import axios from "axios"; import { fetchAppInfo, showTenantName } from "../redux/actions/index"; import { connect } from "react-redux"; import Title from "../components/Title"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useLocation } from "react-router-dom"; const appId = localStorage.getItem("AppID12"); const server = localStorage.getItem("BaseUrl12"); @@ -13,6 +13,7 @@ Parse.serverURL = server; Parse.initialize(appId); const PgSignUp = (props) => { const navigate = useNavigate(); + const location = useLocation(); const [parseBaseUrl] = useState(localStorage.getItem("BaseUrl12")); const [parseAppId] = useState(localStorage.getItem("AppID12")); const [formData, setFormData] = useState({ @@ -187,7 +188,7 @@ const PgSignUp = (props) => { console.log("err ", error); if (error.message === "Account already exists for this username.") { alert("Account already exists!"); - navigate("/"); + navigate("/", { replace: true }); } else { setIsLoader(false); alert("Something went wrong, please try again later!"); @@ -351,7 +352,7 @@ const PgSignUp = (props) => { element.pageType ); setIsLoader(false); - navigate("/"); + navigate("/", { replace: true }); } else { extendedInfo.forEach((x) => { if (x.TenantId) { @@ -389,9 +390,12 @@ const PgSignUp = (props) => { ); setIsLoader(false); alert("Registered user successfully"); - navigate( - `/${element.pageType}/${element.pageId}` - ); + const redirectUrl = + location?.state?.from || + `/${element.pageType}/${element.pageId}`; + + // Redirect to the appropriate URL after successful login + navigate(redirectUrl); } } else { alert("Registered user successfully"); @@ -402,7 +406,12 @@ const PgSignUp = (props) => { ); localStorage.setItem("pageType", element.pageType); setIsLoader(false); - navigate(`/${element.pageType}/${element.pageId}`); + const redirectUrl = + location?.state?.from || + `/${element.pageType}/${element.pageId}`; + + // Redirect to the appropriate URL after successful login + navigate(redirectUrl); } }, (error) => { diff --git a/apps/OpenSign/src/routes/PlanSubscriptions.js b/apps/OpenSign/src/routes/PlanSubscriptions.js index 00ad2fa62..ceb764a3f 100644 --- a/apps/OpenSign/src/routes/PlanSubscriptions.js +++ b/apps/OpenSign/src/routes/PlanSubscriptions.js @@ -39,7 +39,7 @@ const PlanSubscriptions = () => { setIsLoader(false); setYearlyVisible(false); } else { - navigate("/"); + navigate("/", { replace: true }); } // eslint-disable-next-line }, []); @@ -78,31 +78,6 @@ const PlanSubscriptions = () => { id="monthlyPlans" className={`${yearlyVisible ? "none" : "block my-2"}`} > - {/* <div className=" my-2 w-full flex justify-center"> - <ul - className="navs" - style={{ - listStyle: "none", - display: "flex", - alignItems: "baseline" - }} - > - <li className="nav-item"> - <button className="nav-link frequency active" name="1_months"> - Monthly - </button> - </li> - <li className="nav-item"> - <button - className="nav-link frequency " - onClick={toggleFrequency} - name="1_years" - > - Yearly - </button> - </li> - </ul> - </div> */} <div className="flex justify-center w-full my-2"> <ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300"> {plansArr.map((item) => ( From a49c76c1889d24c679931e79c33055eec45e7e38 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 22 Jan 2024 09:48:29 +0530 Subject: [PATCH 21/73] replace menu name generate token to API Token --- .../migrations/20240116170302-add_generatetoken_menu_cjs.cjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs index 0059b0a6a..555dd4e77 100644 --- a/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs +++ b/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs @@ -151,7 +151,7 @@ exports.up = async Parse => { }, { icon: 'fa-solid fa-key', - title: 'Generate token', + title: 'API Token', target: '_self', pageType: 'generatetoken', description: '', @@ -316,7 +316,7 @@ exports.up = async Parse => { }, { icon: 'fa-solid fa-key', - title: 'Generate token', + title: 'API Token', target: '_self', pageType: 'generatetoken', description: '', From 7c8a5e02f2d0b98520391feda2a09e0580fc4e71 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 22 Jan 2024 09:52:44 +0530 Subject: [PATCH 22/73] add createdocument with template Id --- apps/OpenSign/public/version.txt | 1 + .../cloud/customRoute/v1/apiV1.js | 5 +- .../v1/routes/CreateDocumentWithTemplate.js | 98 ++ microfrontends/SignDocuments/src/Routes.js | 3 + .../src/premitives/GuestLogin.js | 294 +++++ .../SignDocuments/src/premitives/GuestSign.js | 1002 +++++++++++++++++ 6 files changed, 1401 insertions(+), 2 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js create mode 100644 microfrontends/SignDocuments/src/premitives/GuestLogin.js create mode 100644 microfrontends/SignDocuments/src/premitives/GuestSign.js diff --git a/apps/OpenSign/public/version.txt b/apps/OpenSign/public/version.txt index e69de29bb..3c61df3f2 100644 --- a/apps/OpenSign/public/version.txt +++ b/apps/OpenSign/public/version.txt @@ -0,0 +1 @@ +v1.1.1-beta diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 2d6d391c0..b9585b119 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -20,7 +20,7 @@ import multer from 'multer'; // import fs from 'node:fs'; import updateDocument from './routes/updateDocument.js'; import deleteDocument from './routes/deleteDocument.js'; -// import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; +import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; dotenv.config(); const storage = multer.memoryStorage(); @@ -49,7 +49,8 @@ app.get('/contactlist', getContactList); app.post('/createdocument', upload.array('file', 1), createDocument); // create Document with templateId -// app.post('/createdocument/:template_id', createDocumentWithTemplate); +app.post('/createdocument/:template_id', createDocumentWithTemplate); + // get Document on the basis of id app.get('/document/:document_id', getDocument); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js new file mode 100644 index 000000000..3ae07bac3 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -0,0 +1,98 @@ +const randomId = () => Math.floor(1000 + Math.random() * 9000); +export default async function createDocumentWithTemplate(request, response) { + const signers = request.body.Signers; + const folderId = request.body.FolderId; + const templateId = request.params.template_id; + const url = process.env.SERVER_URL; + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userPtr = token.get('userId'); + + const templateQyuery = new Parse.Query('contracts_Template'); + const templateRes = await templateQyuery.get(templateId, { useMasterKey: true }); + if (templateRes) { + const template = JSON.parse(JSON.stringify(templateRes)); + if (template?.Placeholders?.length > 0) { + let isValid = template?.Placeholders?.length <= signers?.length; + let updateSigners = template?.Placeholders?.every(y => + signers?.some(x => x.Role === y.Role) + ); + if (isValid && updateSigners) { + const folderPtr = { + __type: 'Pointer', + className: 'contracts_Document', + objectId: folderId, + }; + const template = JSON.parse(JSON.stringify(templateRes)); + const object = new Parse.Object('contracts_Document'); + object.set('Name', template.Name); + if (template?.Note) { + object.set('Note', template.Note); + } + if (template?.Description) { + object.set('Description', template.Description); + } + if (template?.Signers) { + object.set('Signers', template?.Signers); + } + object.set('URL', template.URL); + object.set('CreatedBy', template.CreatedBy); + object.set('ExtUserPtr', template.ExtUserPtr); + if (signers) { + const placeholders = template?.Placeholders?.map(placeholder => { + let matchingSigner = signers.find(y => y.Role === placeholder.Role); + if (matchingSigner) { + return { + ...placeholder, + email: matchingSigner.Email, + signerObjId: '', + signerPtr: {}, + }; + } else { + return { + ...placeholder, + }; + } + }); + console.log('placeholders ', placeholders); + object.set('Placeholders', placeholders); + } + if (folderId) { + object.set('Folder', folderPtr); + } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(userPtr.id, true); + newACL.setWriteAccess(userPtr.id, true); + object.setACL(newACL); + const res = await object.save(null, { useMasterKey: true }); + return response.json({ objectId: res.id, url: url }); + } else { + return response.status(400).json({ error: 'Please provide signers properly!' }); + } + } else { + return response.status(400).json({ error: 'Please setup template properly!' }); + } + } else { + return response.status(404).json({ error: 'Invalid template id!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + if (err.code === 101) { + return response.status(404).json({ error: 'Invalid template id!' }); + } + return response.status(400).json({ error: 'Something went wrong!' }); + } +} diff --git a/microfrontends/SignDocuments/src/Routes.js b/microfrontends/SignDocuments/src/Routes.js index 1b1cba4d5..58039a599 100644 --- a/microfrontends/SignDocuments/src/Routes.js +++ b/microfrontends/SignDocuments/src/Routes.js @@ -10,6 +10,7 @@ import LegaDrive from "./Component/LegaDrive/LegaDrive"; import PageNotFound from "./Component/PageNotFound"; import TemplatePlaceHolder from "./Component/TemplatePlaceholder"; import Parse from "parse"; +import GuestLogin from "./premitives/GuestLogin"; Parse.serverURL = localStorage.getItem("baseUrl"); Parse.initialize(localStorage.getItem("parseAppId")); // `AppRoutes` is used to define route path of app and @@ -50,6 +51,8 @@ function AppRoutes() { <Route path="/legadrive" element={<LegaDrive />} /> {/* Page Not Found */} <Route path="/template/:templateId" element={<TemplatePlaceHolder />} /> + <Route path="/guestlogin" element={<GuestLogin />} /> + <Route path="*" element={<PageNotFound />} /> </Routes> </div> diff --git a/microfrontends/SignDocuments/src/premitives/GuestLogin.js b/microfrontends/SignDocuments/src/premitives/GuestLogin.js new file mode 100644 index 000000000..4df8a9960 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/GuestLogin.js @@ -0,0 +1,294 @@ +import React, { useState } from "react"; +import ModalUi from './ModalUi' +import "../css/LoginPage.css"; +import loader from "../assests/loader2.gif"; +import axios from "axios"; +import { useParams } from "react-router-dom"; +import { themeColor } from "../utils/ThemeColor/backColor"; +import { useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import GuestSign from "./GuestSign"; + +function GuestLogin({children, userdetails}) { + const { id, userMail, contactBookId, serverUrl } = useParams(); + let navigate = useNavigate(); + const [email, setEmail] = useState(userMail || "prafull.navkar@nxglabs.com"); + const [OTP, setOTP] = useState(""); + const [EnterOTP, setEnterOtp] = useState(false); + const [loading, setLoading] = useState(false); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + handleServerUrl(); + }, []); + + //function generate serverUrl and parseAppId from url and save it in local storage + const handleServerUrl = () => { + //split url in array from '&' + localStorage.clear(); + // const checkSplit = serverUrl?.split("&"); + // const server = checkSplit?.[0]; + // const parseId = checkSplit?.[1]; + // const appName = checkSplit?.[2]; + + // const newServer = server.replaceAll("%2F", "/"); + // localStorage.setItem("baseUrl", newServer); + // localStorage.setItem("parseAppId", parseId); + // localStorage.setItem("_appName", appName); + + localStorage.setItem("baseUrl", "https://staging-app.opensignlabs.com/api/app/"); + localStorage.setItem("parseAppId", "opensignstgn"); + localStorage.setItem("_appName", "contracts"); + setIsLoading(false); + }; + + const handleChange = (event) => { + const { value } = event.target; + setOTP(value); + }; + + //send email OTP function + const SendOtp = async (e) => { + const serverUrl = + localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); + const parseId = + localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); + if (serverUrl && localStorage) { + setLoading(true); + e.preventDefault(); + setEmail(email); + + try { + let url = `${serverUrl}functions/SendOTPMailV1/`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseId + }; + let body = { + email: email.toString() + }; + let Otp = await axios.post(url, body, { headers: headers }); + + if (Otp) { + setLoading(false); + setEnterOtp(true); + } + } catch (error) { + alert("something went wrong!"); + } + } else { + alert("something went wrong!"); + } + }; + + //verify OTP send on via email + const VerifyOTP = async (e) => { + e.preventDefault(); + const serverUrl = + localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); + const parseId = + localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); + if (OTP) { + setLoading(true); + try { + let url = `${serverUrl}functions/AuthLoginAsMail/`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseId + }; + let body = { + email: email, + otp: OTP + }; + let user = await axios.post(url, body, { headers: headers }); + if (user.data.result === "Invalid Otp") { + alert("Invalid Otp"); + setLoading(false); + } else if (user.data.result === "user not found!") { + alert("User not found!"); + setLoading(false); + } else { + let _user = user.data.result; + const parseId = localStorage.getItem("parseAppId"); + localStorage.setItem("UserInformation", JSON.stringify(_user)); + localStorage.setItem( + `Parse/${parseId}/currentUser`, + JSON.stringify(_user) + ); + localStorage.setItem("username", _user.name); + localStorage.setItem("accesstoken", _user.sessionToken); + //save isGuestSigner true in local to handle login flow header in mobile view + localStorage.setItem("isGuestSigner", true); + setLoading(false); + // uKymQWaYL6 + navigate( + `/loadmf/signmicroapp/recipientSignPdf/${id}/${contactBookId}` + ); + } + } catch (error) {} + } else { + alert("Please Enter OTP!"); + } + }; + + return ( + <div style={{ padding: "2rem" }}> + <ModalUi isOpen> +<> + {isLoading ? ( + <div + style={{ + display: "flex", + justifyContent: "center", + alignItems: "center", + height: "100vh", + flexDirection: "column" + }} + > + <img + alt="no img" + src={loader} + style={{ width: "80px", height: "80px" }} + /> + <span style={{ fontSize: "13px", color: "gray" }}> + {isLoading.message} + </span> + </div> + ) : ( + <div + style={{ + margin: "10px", + border: "0.5px solid #c5c7c9", + padding: "30px", + boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px" + }} + > + <div className="main_head"> + <div className="main-logo"> + <img + alt="sign img" + src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png" + width="100%" + /> + </div> + </div> + + {!EnterOTP ? ( + <div > + <div > + <span className="welcomeText">Welcome Back !</span> + <br /> + <span className="KNLO"> + Verification code is sent to your email + </span> + <div className="card card-box" style={{ borderRadius: "0px" }}> + <div className="card-body"> + <input + type="email" + name="mobile" + value={email} + disabled + className="loginInput" + /> + <br /> + </div> + </div> + <div className="btnContainer"> + {loading ? ( + <button + type="button" + style={{ + background: themeColor(), + color: "white" + }} + className="verifyBtn" + disabled + > + <span + className="spinner-border spinner-border-sm " + role="status" + aria-hidden="true" + ></span> + Loading... + </button> + ) : ( + <button + className="verifyBtn" + style={{ + background: themeColor(), + color: "white", + marginLeft: "0px !important" + }} + onClick={(e) => SendOtp(e)} + > + Send OTP + </button> + )} + </div> + </div> + </div> + ) : ( + <div > + <div > + <span className="welcomeText">Welcome Back !</span> + <br /> + <span className="KNLO">You will get a OTP via Email</span> + <div className="card card-box"> + <div className="card-body"> + <label>Enter Verification Code</label> + <input + type="number" + className="loginInput" + name="OTP" + value={OTP} + onChange={handleChange} + /> + + <br /> + </div> + </div> + <div> + {loading ? ( + <button + style={{ + background: themeColor(), + color: "white" + }} + className="verifyBtn" + type="button" + disabled + > + <span + className="spinner-border spinner-border-sm " + role="status" + aria-hidden="true" + ></span> + Loading... + </button> + ) : ( + <button + type="button" + onClick={(e) => VerifyOTP(e)} + style={{ + background: themeColor(), + color: "white" + }} + className="verifyBtn" + > + Verify + </button> + )} + </div> + </div> + </div> + )} + </div> + )} + </> + </ModalUi> + <div><GuestSign /></div> + </div> + ); +} + +export default GuestLogin; diff --git a/microfrontends/SignDocuments/src/premitives/GuestSign.js b/microfrontends/SignDocuments/src/premitives/GuestSign.js new file mode 100644 index 000000000..99bc0e11f --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/GuestSign.js @@ -0,0 +1,1002 @@ +import React, { useState, useRef, useEffect } from "react"; +import { themeColor } from "../utils/ThemeColor/backColor"; +import { PDFDocument } from "pdf-lib"; +import "../css/signature.css"; +import axios from "axios"; +import loader from "../assests/loader2.gif"; +import { DndProvider } from "react-dnd"; +import { HTML5Backend } from "react-dnd-html5-backend"; +import { useParams } from "react-router-dom"; +import SignPad from "../Component/component/signPad"; +import RenderAllPdfPage from "../Component/component/renderAllPdfPage"; +import { + contractDocument, + multiSignEmbed, + embedDocId, + pdfNewWidthFun, + signPdfFun, + onImageSelect, + onSaveSign, + onSaveImage, + addDefaultSignatureImg +} from "../utils/Utils"; +import Loader from "../Component/component/loader"; +import HandleError from "../Component/component/HandleError"; +import Nodata from "../Component/component/Nodata"; +import Header from "../Component/component/header"; +import RenderPdf from "../Component/component/renderPdf"; +import CustomModal from "../Component/component/CustomModal"; +import Title from "../Component/component/Title"; +import DefaultSignature from "../Component/component/defaultSignature"; +import ModalUi from "./ModalUi"; + +function GuestSign() { + const { docId } = useParams(); + const [pdfDetails, setPdfDetails] = useState([]); + const [signedSigners, setSignedSigners] = useState([]); + const [unsignedSigners, setUnSignedSigners] = useState([]); + const [isSignPad, setIsSignPad] = useState(false); + const [pdfUrl, setPdfUrl] = useState(); + const [allPages, setAllPages] = useState(null); + const numPages = 1; + const [pageNumber, setPageNumber] = useState(1); + const [image, setImage] = useState(null); + const [isImageSelect, setIsImageSelect] = useState(false); + const [signature, setSignature] = useState(); + const [isStamp, setIsStamp] = useState(false); + const [signKey, setSignKey] = useState(); + const [imgWH, setImgWH] = useState({}); + const imageRef = useRef(null); + const [handleError, setHandleError] = useState(); + const [isLoading, setIsLoading] = useState({ + isLoad: true, + message: "This might take some time" + }); + const [defaultSignImg, setDefaultSignImg] = useState(); + const [isDocId, setIsDocId] = useState(false); + const [pdfNewWidth, setPdfNewWidth] = useState(); + const [pdfOriginalWidth, setPdfOriginalWidth] = useState(); + const [signerPos, setSignerPos] = useState([]); + const [noData, setNoData] = useState(false); + const [signerObjectId, setSignerObjectId] = useState(); + const [isUiLoading, setIsUiLoading] = useState(false); + const [isDecline, setIsDecline] = useState({ isDeclined: false }); + const [currentSigner, setCurrentSigner] = useState(false); + const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" }); + const [defaultSignAlert, setDefaultSignAlert] = useState({ + isShow: false, + alertMessage: "" + }); + const [isCompleted, setIsCompleted] = useState({ + isCertificate: false, + isModal: false + }); + const [pdfLoadFail, setPdfLoadFail] = useState({ + status: false, + type: "load" + }); + const [isSigned, setIsSigned] = useState(false); + const [isExpired, setIsExpired] = useState(false); + const [alreadySign, setAlreadySign] = useState(false); + const [containerWH, setContainerWH] = useState({}); + const divRef = useRef(null); + const isMobile = window.innerWidth < 767; + const rowLevel = + localStorage.getItem("rowlevel") && + JSON.parse(localStorage.getItem("rowlevel")); + + const objectId = + rowLevel && rowLevel.id + ? rowLevel.id + : rowLevel?.objectId && rowLevel.objectId; + const documentId = "uKymQWaYL6"//docId ? docId : objectId && objectId; + + const senderUser = + localStorage.getItem( + `Parse/${localStorage.getItem("parseAppId")}/currentUser` + ) && + localStorage.getItem( + `Parse/${localStorage.getItem("parseAppId")}/currentUser` + ); + const jsonSender = JSON.parse(senderUser); + + useEffect(() => { + if (documentId) { + getDocumentDetails(); + } + }, []); + useEffect(() => { + if (divRef.current) { + const pdfWidth = pdfNewWidthFun(divRef); + setPdfNewWidth(pdfWidth); + setContainerWH({ + width: divRef.current.offsetWidth, + height: divRef.current.offsetHeight + }); + } + }, [divRef.current]); + + //function for get document details for perticular signer with signer'object id + const getDocumentDetails = async () => { + //getting document details + const documentData = await contractDocument(documentId); + if (documentData && documentData.length > 0) { + const isCompleted = + documentData[0].IsCompleted && documentData[0].IsCompleted; + const expireDate = documentData[0].ExpiryDate.iso; + const declined = documentData[0].IsDeclined && documentData[0].IsDeclined; + const expireUpdateDate = new Date(expireDate).getTime(); + const currDate = new Date().getTime(); + const getSigners = documentData[0].Signers; + const getCurrentSigner = + getSigners && + getSigners.filter( + (data) => data.UserId.objectId === jsonSender.objectId + ); + + const currUserId = getCurrentSigner[0] + ? getCurrentSigner[0].objectId + : ""; + setSignerObjectId(currUserId); + if (documentData[0].SignedUrl) { + setPdfUrl(documentData[0].SignedUrl); + } else { + setPdfUrl(documentData[0].URL); + } + if (isCompleted) { + setIsSigned(true); + const data = { + isCertificate: true, + isModal: true + }; + setAlreadySign(true); + setIsCompleted(data); + } else if (declined) { + const currentDecline = { + currnt: "another", + isDeclined: true + }; + setIsDecline(currentDecline); + } else if (currDate > expireUpdateDate) { + setIsExpired(true); + } + + if (documentData.length > 0) { + const checkDocIdExist = + documentData[0].AuditTrail && + documentData[0].AuditTrail.length > 0 && + documentData[0].AuditTrail.filter( + (data) => data.Activity === "Signed" + ); + + const checkAlreadySign = + documentData[0].AuditTrail && + documentData[0].AuditTrail.length > 0 && + documentData[0].AuditTrail.filter( + (data) => + data.UserPtr.objectId === currUserId && data.Activity === "Signed" + ); + if ( + checkAlreadySign && + checkAlreadySign[0] && + checkAlreadySign.length > 0 + ) { + setAlreadySign(true); + } + + let signers = []; + let unSignedSigner = []; + + //check document is signed or not + if (checkDocIdExist && checkDocIdExist.length > 0) { + setIsDocId(true); + const signerRes = documentData[0].Signers; + //comparison auditTrail user details with signers user details + for (let i = 0; i < signerRes.length; i++) { + const signerId = signerRes[i].objectId; + + let isSignedSignature = false; + for (let j = 0; j < checkDocIdExist.length; j++) { + const signedExist = + checkDocIdExist[j] && checkDocIdExist[j].UserPtr.objectId; + //checking signerObjId and auditTrail User objId + // if match then add signed data in signer array and break loop + + if (signerId === signedExist) { + signers.push({ ...signerRes[i], ...signerRes[i] }); + isSignedSignature = true; + break; + } + // if does not match then add unsigned data in unSignedSigner array + } + if (!isSignedSignature) { + unSignedSigner.push({ ...signerRes[i], ...signerRes[i] }); + } + } + setSignedSigners(signers); + setUnSignedSigners(unSignedSigner); + + setSignerPos(documentData[0].Placeholders); + } else { + let unsigned = []; + for (let i = 0; i < documentData.length; i++) { + unsigned.push(documentData[i].Signers); + } + setUnSignedSigners(unsigned[0]); + setSignerPos(documentData[0].Placeholders); + } + setPdfDetails(documentData); + setIsUiLoading(false); + } else { + alert("No data found!"); + } + } else if ( + documentData === "Error: Something went wrong!" || + (documentData.result && documentData.result.error) + ) { + const loadObj = { + isLoad: false + }; + setHandleError("Error: Something went wrong!"); + setIsLoading(loadObj); + } else { + setNoData(true); + const loadObj = { + isLoad: false + }; + setIsLoading(loadObj); + setIsUiLoading(false); + } +if(jsonSender?.objectId){ await axios + .get( + `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( + "_appName" + )}_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${ + jsonSender?.objectId + }"}}`, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } + } + ) + .then((Listdata) => { + const json = Listdata.data; + const res = json.results; + + if (res[0] && res.length > 0) { + setDefaultSignImg(res[0].ImageURL); + } + const loadObj = { + isLoad: false + }; + setIsLoading(loadObj); + }) + .catch((err) => { + const loadObj = { + isLoad: false + }; + setHandleError("Error: Something went wrong!"); + setIsLoading(loadObj); + });} + }; + + //function for embed signature or image url in pdf + async function embedImages() { + const checkUser = signerPos.filter( + (data) => data.signerObjId === signerObjectId + ); + if (checkUser && checkUser.length > 0) { + let checkSignUrl = []; + const checkSign = checkUser[0].placeHolder.filter( + (data, ind) => data.pos + ); + for (let i = 0; i < checkSign.length; i++) { + const posData = checkSign[i].pos.filter((pos) => !pos.SignUrl); + if (posData && posData.length > 0) { + checkSignUrl.push(posData); + } + } + + if (checkSignUrl && checkSignUrl.length > 0) { + setIsAlert({ + isShow: true, + alertMessage: "Please complete your signature!" + }); + } else { + setIsUiLoading(true); + const pngUrl = checkUser[0].placeHolder; + // Load a PDFDocument from the existing PDF bytes + const existingPdfBytes = await fetch(pdfUrl).then((res) => + res.arrayBuffer() + ); + const pdfDoc = await PDFDocument.load(existingPdfBytes, { + ignoreEncryption: true + }); + // let pdfBase64; + // //else if signature is more than one then embed all sign with the use of pdf-lib + // else if (pngUrl.length > 0 && pngUrl[0].pos.length > 0) { + const flag = false; + //embed document's object id to all pages in pdf document + if (!isDocId) { + await embedDocId(pdfDoc, documentId, allPages); + } + //embed multi signature in pdf + const pdfBytes = await multiSignEmbed( + pngUrl, + pdfDoc, + pdfOriginalWidth, + flag, + containerWH + ); + //function for call to embed signature in pdf and get digital signature pdf + try { + const res = await signPdfFun( + pdfBytes, + documentId, + signerObjectId, + pdfOriginalWidth, + pngUrl, + containerWH, + setIsAlert + ); + if (res && res.status === "success") { + setPdfUrl(res.data); + setIsSigned(true); + setSignedSigners([]); + setUnSignedSigners([]); + getDocumentDetails(); + } else { + setIsAlert({ + isShow: true, + alertMessage: "something went wrong" + }); + } + } catch (err) { + setIsAlert({ + isShow: true, + alertMessage: "something went wrong" + }); + } + } + + setIsSignPad(false); + // } + } else { + setIsAlert({ + isShow: true, + alertMessage: "something went wrong" + }); + } + } + + //function for get pdf page details + const pageDetails = async (pdf) => { + const load = { + status: true + }; + setPdfLoadFail(load); + pdf.getPage(1).then((pdfPage) => { + const pageWidth = pdfPage.view[2]; + + setPdfOriginalWidth(pageWidth); + }); + }; + + //function for change page + function changePage(offset) { + setPageNumber((prevPageNumber) => prevPageNumber + offset); + } + + const getFirstLetter = (name) => { + const firstLetter = name.charAt(0); + return firstLetter; + }; + //function for image upload or update + const onImageChange = (event) => { + if (event.target.files && event.target.files[0]) { + onImageSelect(event, setImgWH, setImage); + } + }; + //function for upload stamp image + const saveImage = () => { + //get current signers placeholder position data + const currentSigner = signerPos.filter( + (data) => data.signerObjId === signerObjectId + ); + //get current pagenumber placeholder index + const getIndex = currentSigner[0].placeHolder.findIndex((object) => { + return object.pageNumber === pageNumber; + }); + //get current signer placeholder position data + const placeholderPosition = currentSigner[0].placeHolder; + //function of save image and get updated position with image url + const getUpdatePosition = onSaveImage( + placeholderPosition, + getIndex, + signKey, + imgWH, + image + ); + + //replace updated placeholder position with old data + placeholderPosition.splice( + 0, + placeholderPosition.length, + ...getUpdatePosition + ); + //get current signers placeholder position data index number in array + const indexofSigner = signerPos.findIndex((object) => { + return object.signerObjId === signerObjectId; + }); + //update current signers data with new placeholder position array data + setSignerPos((prevState) => { + const newState = [...prevState]; // Create a copy of the state + newState.splice(indexofSigner, 1, ...currentSigner); // Modify the copy + return newState; // Update the state with the modified copy + }); + }; + + //function for save button to save signature or image url + const saveSign = (isDefaultSign, width, height) => { + const isTypeText = width && height ? true : false; + const signatureImg = isDefaultSign ? defaultSignImg : signature; + let imgWH = { width: width ? width : "", height: height ? height : "" }; + setIsSignPad(false); + setIsImageSelect(false); + setImage(); + + //get current signers placeholder position data + const currentSigner = signerPos.filter( + (data) => data.signerObjId === signerObjectId + ); + //get current pagenumber placeholder index + const getIndex = currentSigner[0].placeHolder.findIndex((object) => { + return object.pageNumber === pageNumber; + }); + + //set default signature image width and height + if (isDefaultSign) { + const img = new Image(); + img.src = defaultSignImg; + if (img.complete) { + imgWH = { + width: img.width, + height: img.height + }; + } + } + //get current signer placeholder position data + const placeholderPosition = currentSigner[0].placeHolder; + //function of save signature image and get updated position with signature image url + const getUpdatePosition = onSaveSign( + placeholderPosition, + getIndex, + signKey, + signatureImg, + imgWH, + isDefaultSign, + isTypeText + ); + + const updateSignerData = currentSigner.map((obj, ind) => { + if (obj.signerObjId === signerObjectId) { + return { ...obj, placeHolder: getUpdatePosition }; + } + return obj; + }); + + const index = signerPos.findIndex( + (data) => data.signerObjId === signerObjectId + ); + setSignerPos((prevState) => { + const newState = [...prevState]; + newState.splice(index, 1, ...updateSignerData); + return newState; + }); + }; + + const checkSignerBackColor = (obj) => { + const data = signerPos.filter((data) => data.signerObjId === obj.objectId); + return data && data.length > 0 && data[0].blockColor; + }; + + //function for set decline true on press decline button + const declineDoc = async () => { + setIsDecline({ isDeclined: false }); + const data = { + IsDeclined: true + }; + setIsUiLoading(true); + + await axios + .put( + `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( + "_appName" + )}_Document/${documentId}`, + data, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } + } + ) + .then((result) => { + const res = result.data; + if (res) { + const currentDecline = { + currnt: "YouDeclined", + isDeclined: true + }; + setIsDecline(currentDecline); + setIsUiLoading(false); + } + }) + .catch((err) => { + console.log("error updating field is decline ", err); + }); + }; + //function to add default signature for all requested placeholder of sign + const addDefaultSignature = () => { + //get current signers placeholder position data + const currentSignerPosition = signerPos.filter( + (data) => data.signerObjId === signerObjectId + ); + //function for save default signature url for all placeholder position + const updatePlace = addDefaultSignatureImg( + currentSignerPosition[0].placeHolder, + defaultSignImg + ); + + const updatesignerPos = signerPos.map((x) => + x.signerObjId === signerObjectId ? { ...x, placeHolder: updatePlace } : x + ); + setSignerPos(updatesignerPos); + setDefaultSignAlert({ + isShow: false, + alertMessage: "" + }); + }; + + return ( + <DndProvider backend={HTML5Backend}> + <Title title={"Request Sign"} /> + {isLoading.isLoad ? ( + <Loader isLoading={isLoading} /> + ) : handleError ? ( + <HandleError handleError={handleError} /> + ) : noData ? ( + <Nodata /> + ) : ( + <div> + {isUiLoading && ( + <div + style={{ + position: "absolute", + height: "100vh", + width: "100%", + display: "flex", + justifyContent: "center", + flexDirection: "column", + alignItems: "center", + zIndex: "20", + backgroundColor: "#e6f2f2", + opacity: 0.8 + }} + > + <img + alt="no img" + src={loader} + style={{ width: "100px", height: "100px" }} + /> + <span style={{ fontSize: "13px", fontWeight: "bold" }}> + This might take some time + </span> + </div> + )} + + <div className="signatureContainer" ref={divRef}> + <ModalUi + headerColor={"#dc3545"} + isOpen={isAlert.isShow} + title={"Alert message"} + handleClose={() => { + setIsAlert({ + isShow: false, + alertMessage: "" + }); + }} + > + <div style={{ height: "100%", padding: 20 }}> + <p>{isAlert.alertMessage}</p> + + <div + style={{ + height: "1px", + backgroundColor: "#9f9f9f", + width: "100%", + marginTop: "15px", + marginBottom: "15px" + }} + ></div> + + <button + onClick={() => { + setIsAlert({ + isShow: false, + alertMessage: "" + }); + }} + type="button" + className="finishBtn cancelBtn" + > + Ok + </button> + </div> + </ModalUi> + {/* this modal is used to show decline alert */} + <CustomModal + containerWH={containerWH} + show={isDecline.isDeclined} + headMsg="Document Declined" + bodyMssg={ + isDecline.currnt === "Sure" ? ( + <p className="pTagBody"> + Are you sure want to decline this document ? + </p> + ) : isDecline.currnt === "YouDeclined" ? ( + <p className="pTagBody">You have declined this document!</p> + ) : ( + isDecline.currnt === "another" && ( + <p className="pTagBody"> + You cannot sign this document as it has been declined by + one or more person(s). + </p> + ) + ) + } + footerMessage={isDecline.currnt === "Sure"} + declineDoc={declineDoc} + setIsDecline={setIsDecline} + /> + {/* this modal is used for show expired alert */} + <CustomModal + containerWH={containerWH} + show={isExpired} + headMsg="Document Expired!" + bodyMssg="This Document is no longer available." + /> + <ModalUi + headerColor={defaultSignImg ? themeColor() : "#dc3545"} + isOpen={defaultSignAlert.isShow} + title={"Auto sign"} + handleClose={() => { + setDefaultSignAlert({ + isShow: false, + alertMessage: "" + }); + }} + > + <div style={{ height: "100%", padding: 20 }}> + <p>{defaultSignAlert.alertMessage}</p> + + <div + style={{ + height: "1px", + backgroundColor: "#9f9f9f", + width: "100%", + marginTop: "15px", + marginBottom: "15px" + }} + ></div> + {defaultSignImg ? ( + <> + <button + onClick={() => addDefaultSignature()} + style={{ + background: themeColor() + }} + type="button" + className="finishBtn" + > + Yes + </button> + <button + onClick={() => { + setDefaultSignAlert({ + isShow: false, + alertMessage: "" + }); + }} + type="button" + className="finishBtn cancelBtn" + > + Close + </button> + </> + ) : ( + <button + onClick={() => { + setIsAlert({ + isShow: false, + alertMessage: "" + }); + }} + type="button" + className="finishBtn cancelBtn" + > + Ok + </button> + )} + </div> + </ModalUi> + {/* this component used to render all pdf pages in left side */} + <RenderAllPdfPage + signPdfUrl={pdfDetails[0].URL || "https://api.printnode.com/static/test/pdf/multipage.pdf"} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + pageNumber={pageNumber} + /> + + {/* pdf render view */} + <div + style={{ + marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px", + marginRight: !isMobile && pdfOriginalWidth > 500 && "20px" + }} + > + {/* this modal is used show this document is already sign */} + <ModalUi + isOpen={isCompleted.isModal} + title={"Sign Documents"} + handleClose={() => { + setIsCompleted({ isModal: false, isCertificate: true }); + }} + > + <div style={{ height: "100%", padding: 20 }}> + <p>This document has been signed by all Signers.</p> + + <div + style={{ + height: "1px", + backgroundColor: "#9f9f9f", + width: "100%", + marginTop: "15px", + marginBottom: "15px" + }} + ></div> + <button + type="button" + className="finishBtn cancelBtn" + onClick={() => + setIsCompleted({ isModal: false, isCertificate: true }) + } + > + Close + </button> + </div> + </ModalUi> + + {/* this component is used for signature pad modal */} + <SignPad + isSignPad={isSignPad} + isStamp={isStamp} + setIsImageSelect={setIsImageSelect} + setIsSignPad={setIsSignPad} + setImage={setImage} + isImageSelect={isImageSelect} + imageRef={imageRef} + onImageChange={onImageChange} + setSignature={setSignature} + image={image} + onSaveImage={saveImage} + onSaveSign={saveSign} + defaultSign={defaultSignImg} + /> + {/* pdf header which contain funish back button */} + <Header + isPdfRequestFiles={true} + pageNumber={pageNumber} + allPages={allPages} + changePage={changePage} + pdfDetails={pdfDetails} + signerPos={signerPos} + isSigned={isSigned} + isCompleted={isCompleted} + embedImages={embedImages} + isShowHeader={true} + setIsDecline={setIsDecline} + decline={true} + currentSigner={currentSigner} + pdfUrl={pdfUrl} + alreadySign={alreadySign} + /> + {containerWH && ( + <RenderPdf + pageNumber={pageNumber} + pdfOriginalWidth={pdfOriginalWidth} + pdfNewWidth={pdfNewWidth} + setIsSignPad={setIsSignPad} + setIsStamp={setIsStamp} + setSignKey={setSignKey} + pdfDetails={pdfDetails} + signerPos={signerPos} + successEmail={false} + pdfUrl={pdfUrl} + numPages={numPages} + pageDetails={pageDetails} + pdfRequest={true} + signerObjectId={signerObjectId} + signedSigners={signedSigners} + setCurrentSigner={setCurrentSigner} + setPdfLoadFail={setPdfLoadFail} + pdfLoadFail={pdfLoadFail} + setSignerPos={setSignerPos} + containerWH={containerWH} + /> + )} + </div> + <div> + <div className="signerComponent"> + <div + style={{ maxHeight: window.innerHeight - 70 + "px" }} + className="autoSignScroll" + > + {signedSigners.length > 0 && ( + <> + <div + style={{ + background: themeColor() + }} + className="signedStyle" + > + Signed by + </div> + <div style={{ marginTop: "2px" }}> + {signedSigners.map((obj, ind) => { + return ( + <div + style={{ + display: "flex", + flexDirection: "row", + alignItems: "center", + padding: "10px 0", + background: checkSignerBackColor(obj) + }} + key={ind} + > + <div + className="signerStyle" + style={{ + background: "#abd1d0", + width: 30, + height: 30, + display: "flex", + borderRadius: 30 / 2, + justifyContent: "center", + alignItems: "center", + margin: "0 10px 0 5px" + }} + > + <span + style={{ + fontSize: "12px", + textAlign: "center", + fontWeight: "bold", + color: "black", + textTransform: "uppercase" + }} + > + {getFirstLetter(obj.Name)} + </span> + </div> + <div + style={{ + display: "flex", + flexDirection: "column" + }} + > + <span className="userName">{obj.Name}</span> + <span className="useEmail">{obj.Email}</span> + </div> + </div> + ); + })} + </div> + </> + )} + + {unsignedSigners.length > 0 && ( + <> + <div + style={{ + background: themeColor(), + color: "white", + padding: "5px", + fontFamily: "sans-serif", + marginTop: signedSigners.length > 0 && "20px" + }} + > + Yet to sign + </div> + <div style={{ marginTop: "5px" }}> + {unsignedSigners.map((obj, ind) => { + return ( + <div + style={{ + display: "flex", + flexDirection: "row", + alignItems: "center", + padding: "10px 0", + background: checkSignerBackColor(obj) + }} + key={ind} + > + <div + className="signerStyle" + style={{ + background: "#abd1d0", + width: 30, + height: 30, + display: "flex", + borderRadius: 30 / 2, + justifyContent: "center", + alignItems: "center", + margin: "0 10px 0 5px" + }} + > + <span + style={{ + fontSize: "12px", + textAlign: "center", + fontWeight: "bold", + color: "black", + textTransform: "uppercase" + }} + > + {getFirstLetter(obj.Name)} + </span> + </div> + <div + style={{ + display: "flex", + flexDirection: "column" + }} + > + <span className="userName">{obj.Name}</span> + <span className="useEmail">{obj.Email}</span> + </div> + <hr /> + </div> + ); + })} + </div> + </> + )} + {defaultSignImg && !alreadySign && ( + <DefaultSignature + themeColor={themeColor} + defaultSignImg={defaultSignImg} + setDefaultSignImg={setDefaultSignImg} + userObjectId={signerObjectId} + setIsLoading={setIsLoading} + xyPostion={signerPos} + setDefaultSignAlert={setDefaultSignAlert} + /> + )} + </div> + </div> + </div> + </div> + </div> + )} + </DndProvider> + ); +} + +export default GuestSign; From 52320e0cd9054fa9755e1ed9d3bf53aba1338c96 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 22 Jan 2024 15:35:38 +0530 Subject: [PATCH 23/73] fix: add regenerate confirmation modal in API token menu --- apps/OpenSign/src/constant/const.js | 4 +++ apps/OpenSign/src/routes/GenerateToken.js | 44 +++++++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/apps/OpenSign/src/constant/const.js b/apps/OpenSign/src/constant/const.js index 4f2ea585b..33e711591 100644 --- a/apps/OpenSign/src/constant/const.js +++ b/apps/OpenSign/src/constant/const.js @@ -1,2 +1,6 @@ export const contactCls = "contracts_Contactbook"; export const templateCls = "contracts_Template"; +export const rejectBtn = + "bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]"; +export const submitBtn = + "bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center"; diff --git a/apps/OpenSign/src/routes/GenerateToken.js b/apps/OpenSign/src/routes/GenerateToken.js index ce74313d4..1adc0f3e7 100644 --- a/apps/OpenSign/src/routes/GenerateToken.js +++ b/apps/OpenSign/src/routes/GenerateToken.js @@ -2,6 +2,9 @@ import React, { useEffect, useState } from "react"; import Title from "../components/Title"; import axios from "axios"; import Alert from "../primitives/Alert"; +import ModalUi from "../primitives/ModalUi"; +import { rejectBtn, submitBtn } from "../constant/const"; +import { openInNewTab } from "../constant/Utils"; function GenerateToken() { const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); @@ -11,6 +14,7 @@ function GenerateToken() { const [copied, setCopied] = useState(false); const [isGenerate, setIsGenerate] = useState(false); const [isErr, setIsErr] = useState(false); + const [isModal, setIsModal] = useState(false); useEffect(() => { fetchToken(); @@ -39,6 +43,7 @@ function GenerateToken() { const handleSubmit = async (e) => { e.preventDefault(); setIsLoader(true); + setIsModal(false); try { const url = parseBaseUrl + "functions/generateapitoken"; const headers = { @@ -82,6 +87,7 @@ function GenerateToken() { setCopied(false); }, 1500); // Reset copied state after 1.5 seconds }; + const handleModal = () => setIsModal(!isModal); return ( <React.Fragment> <Title title={"token"} /> @@ -134,15 +140,47 @@ function GenerateToken() { </span> </li> </ul> - <div className="flex justify-center pb-4"> + <div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4"> <button type="button" - onClick={handleSubmit} - className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base" + onClick={apiToken ? handleModal : handleSubmit} + className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none" > {apiToken ? "Regenerate Token" : "Generate Token"} </button> + <button + type="button" + onClick={() => openInNewTab("https://docs.opensignlabs.com")} + className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none" + > + View Docs + </button> </div> + + <ModalUi + isOpen={isModal} + title={"Regenerate Token"} + handleClose={handleModal} + > + <div className="m-[20px]"> + <div className="text-lg font-normal text-black"> + Are you sure you want to regenerate token it will expire old + token? + </div> + <hr className="bg-[#ccc] mt-4 " /> + <div className="flex items-center mt-3 gap-2 text-white"> + <button + onClick={handleSubmit} + className={submitBtn + "ml-[2px]"} + > + Yes + </button> + <button onClick={handleModal} className={rejectBtn}> + No + </button> + </div> + </div> + </ModalUi> </div> )} </React.Fragment> From af344c8ae22bb8747bd113e751d84e140a2cbbef Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Tue, 23 Jan 2024 12:54:28 +0530 Subject: [PATCH 24/73] feat: add webhook which will call on document completion event --- apps/OpenSign/src/App.js | 2 + apps/OpenSign/src/routes/Webhook.js | 186 +++++ apps/OpenSignServer/cloud/main.js | 2 + .../cloud/parsefunction/pdf/PDF.min.js | 130 ++-- .../cloud/parsefunction/saveWebhook.js | 29 + .../20240123122932-add_webhook_menu.cjs | 684 ++++++++++++++++++ 6 files changed, 991 insertions(+), 42 deletions(-) create mode 100644 apps/OpenSign/src/routes/Webhook.js create mode 100644 apps/OpenSignServer/cloud/parsefunction/saveWebhook.js create mode 100644 apps/OpenSignServer/databases/migrations/20240123122932-add_webhook_menu.cjs diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index deb9b19f6..e2cce85b5 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -17,6 +17,7 @@ import ReportMicroapp from "./components/ReportMicroapp"; import LoadMf from "./routes/LoadMf"; import GenerateToken from "./routes/GenerateToken"; import ValidateRoute from "./primitives/ValidateRoute"; +import Webhook from "./routes/Webhook"; function App() { const [isloading, setIsLoading] = useState(true); @@ -82,6 +83,7 @@ function App() { <Route path="/dashboard/:id" element={<Dashboard />} /> <Route path="/profile" element={<UserProfile />} /> <Route path="/generatetoken" element={<GenerateToken />} /> + <Route path="/webhook" element={<Webhook />} /> </Route> <Route path="*" element={<PageNotFound />} /> </Routes> diff --git a/apps/OpenSign/src/routes/Webhook.js b/apps/OpenSign/src/routes/Webhook.js new file mode 100644 index 000000000..2c1424ec5 --- /dev/null +++ b/apps/OpenSign/src/routes/Webhook.js @@ -0,0 +1,186 @@ +import React, { useEffect, useState } from "react"; +import Title from "../components/Title"; +import axios from "axios"; +import Alert from "../primitives/Alert"; +import ModalUi from "../primitives/ModalUi"; +import { rejectBtn, submitBtn } from "../constant/const"; +import { openInNewTab } from "../constant/Utils"; +import Parse from "parse"; + +function Webhook() { + const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); + const [parseAppId] = useState(localStorage.getItem("parseAppId")); + const [webhook, setWebhook] = useState(); + const [isLoader, setIsLoader] = useState(true); + const [copied, setCopied] = useState(false); + const [isGenerate, setIsGenerate] = useState(false); + const [isErr, setIsErr] = useState(false); + const [isModal, setIsModal] = useState(false); + + useEffect(() => { + fetchWebhook(); + // eslint-disable-next-line + }, []); + + const fetchWebhook = async () => { + const email = Parse.User.current().getEmail(); + const params = { email: email }; + try { + const extRes = await Parse.Cloud.run("getUserDetails", params); + if (extRes) { + setWebhook(extRes.get("Webhook")); + } + setIsLoader(false); + } catch (err) { + setWebhook(); + setIsLoader(false); + console.log("Err", err); + } + }; + const handleSubmit = async (e) => { + e.preventDefault(); + setIsLoader(true); + setIsModal(false); + try { + const params = { url: webhook }; + const url = parseBaseUrl + "functions/savewebhook"; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessiontoken: localStorage.getItem("accesstoken") + }; + await axios.post(url, params, { headers: headers }).then((res) => { + if (res.data && res.data.result && res.data.result.Webhook) { + setWebhook(res.data.result.Webhook); + setIsGenerate(true); + setTimeout(() => { + setIsGenerate(false); + }, 1500); + setIsLoader(false); + } else { + console.error("Error while generating webhook"); + setIsLoader(false); + setIsErr(true); + setTimeout(() => { + setIsErr(false); + }, 1500); + } + }); + } catch (error) { + setIsLoader(false); + setIsErr(true); + setTimeout(() => { + setIsErr(false); + }, 1500); + + console.log("err", error); + } + }; + + const copytoclipboard = (text) => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 1500); // Reset copied state after 1.5 seconds + }; + const handleModal = () => setIsModal(!isModal); + return ( + <React.Fragment> + <Title title={"Webhook"} /> + {isGenerate && <Alert type="success">Webhook added successfully!</Alert>} + {copied && <Alert type="success">Copied</Alert>} + {isErr && <Alert type="danger">Something went wrong!</Alert>} + {isLoader ? ( + <div + style={{ + height: "100vh", + display: "flex", + alignItems: "center", + justifyContent: "center" + }} + > + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + ) : ( + <div className="bg-white flex flex-col justify-center shadow rounded"> + <ul className="w-full flex flex-col p-2 text-sm"> + <li + className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all py-2`} + > + <span className="w-[40%]">Webhook:</span>{" "} + <span id="token" className="w-[60%] md:text-end cursor-pointer"> + {webhook && webhook} + </span> + </li> + <li + className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} + > + <span className="w-[40%]">Application Id:</span>{" "} + <span + className="w-[60%] md:text-end cursor-pointer" + onClick={() => copytoclipboard(localStorage.getItem("AppID12"))} + > + {localStorage.getItem("AppID12")} + </span> + </li> + </ul> + <div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4"> + <button + type="button" + onClick={handleModal} + className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none" + > + {webhook ? "Update Webhook" : "Add Webhook"} + </button> + <button + type="button" + onClick={() => openInNewTab("https://docs.opensignlabs.com")} + className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none" + > + View Docs + </button> + </div> + + <ModalUi + isOpen={isModal} + title={"Regenerate Token"} + handleClose={handleModal} + > + <div className="m-[20px]"> + <div className="text-lg font-normal text-black"> + <label className="text-sm ml-2">Webhook</label> + <input + value={webhook} + onChange={(e) => setWebhook(e.target.value)} + placeholder="Enter webhook url" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + /> + </div> + <hr className="bg-[#ccc] mt-4 " /> + <div className="flex items-center mt-3 gap-2 text-white"> + <button + onClick={handleSubmit} + className={submitBtn + "ml-[2px]"} + > + Yes + </button> + <button onClick={handleModal} className={rejectBtn}> + No + </button> + </div> + </div> + </ModalUi> + </div> + )} + </React.Fragment> + ); +} + +export default Webhook; diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index b6ff1ed7a..b02ac1894 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -21,6 +21,7 @@ import generateApiToken from './parsefunction/generateApiToken.js'; import getapitoken from './parsefunction/getapitoken.js'; import TemplateAfterSave from './parsefunction/TemplateAfterSave.js'; import GetTemplate from './parsefunction/GetTemplate.js'; +import savewebhook from './parsefunction/saveWebhook.js'; Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('UserGroups', getUserGroups); @@ -41,6 +42,7 @@ Parse.Cloud.define('getReport', getReport); Parse.Cloud.define('generateapitoken', generateApiToken); Parse.Cloud.define('getapitoken', getapitoken); Parse.Cloud.define('getTemplate', GetTemplate); +Parse.Cloud.define('savewebhook', savewebhook); Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index b6f989cb7..3400963d3 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -2,7 +2,6 @@ import SignPDF from './SignPDF.min.cjs'; import fs from 'node:fs'; import axios from 'axios'; import FormData from 'form-data'; -// import plainplaceholder from './customSignPdf/plainplaceholder.min.js'; import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js'; const serverUrl = process.env.SERVER_URL, APPID = process.env.APP_ID, @@ -19,22 +18,22 @@ async function uploadFile(a) { console.log('err ', e), fs.unlinkSync(a); } } -async function updateDoc(t, s, r, i, n, o) { +async function updateDoc(t, s, r, i, o, n) { try { var d = { - UserPtr: { __type: 'Pointer', className: o, objectId: r }, + UserPtr: { __type: 'Pointer', className: n, objectId: r }, SignedUrl: s, Activity: 'Signed', ipAddress: i, }; let e; - var l = (e = n.AuditTrail && 0 < n.AuditTrail.length ? [...n.AuditTrail, d] : [d]).filter( + var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter( e => 'Signed' === e.Activity ); let a = !1; - !((n.Signers && 0 < n.Signers.length && l.length !== n.Signers.length) || !(a = !0)); - var p = { SignedUrl: s, AuditTrail: e, IsCompleted: a }; - await axios.put(serverUrl + '/classes/contracts_Document/' + t, p, { + !((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0)); + var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a }; + await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, { headers: { 'Content-Type': 'application/json', 'X-Parse-Application-Id': APPID, @@ -61,7 +60,7 @@ async function sendMail(e) { s + ' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + t.Mail + - ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>' + ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -86,7 +85,7 @@ async function sendCompletedMail(e) { s + '. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + t.Mail + - ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>', + ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -96,12 +95,58 @@ async function sendCompletedMail(e) { }, }); } -async function PDF(i, n) { +async function sendDoctoWebhook(t) { + var e; + t.data.ExtUserPtr?.Webhook && + ((e = { + File: t?.data?.SignedUrl, + Name: t?.data?.Name, + Note: t?.data?.Note, + Description: t?.data?.Description, + Signers: t?.data?.Signers?.map(e => e.Name), + Completed: !0, + CompletedAt: new Date(), + CreatedAt: t?.data?.createdAt, + }), + await axios + .post(t?.data?.ExtUserPtr?.Webhook, e, { headers: { 'Content-Type': 'application/json' } }) + .then(e => { + try { + console.log('res ', e); + var a = new Parse.Object('contracts_Webhook'); + a.set('Log', e?.status), + a.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: t.data.ExtUserPtr.UserId.objectId, + }), + a.save(null, { useMasterKey: !0 }); + } catch (e) { + console.log('err save in contracts_Webhook', e); + } + }) + .catch(e => { + console.log('Err send data to webhook', e); + try { + var a = new Parse.Object('contracts_Webhook'); + a.set('Log', e?.status), + a.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: t.data.ExtUserPtr.UserId.objectId, + }), + a.save(null, { useMasterKey: !0 }); + } catch (e) { + console.log('err save in contracts_Webhook', e); + } + })); +} +async function PDF(i, o) { try { i.params.sign; var e = i.params.docId, a = i.params.userId, - o = await axios.get( + n = await axios.get( serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers', { headers: { @@ -121,28 +166,28 @@ async function PDF(i, n) { { var d, l, - p, - c = JSON.stringify({ objectId: a }); + c, + p = JSON.stringify({ objectId: a }); let s, r; r = a - ? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, { + ? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Session-Token': i.headers.sessiontoken, }, })).data && 0 < d.data.results.length ? ((s = d), 'contracts_Contactbook') - : ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, { + : ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY }, })), 'contracts_Users') : ((l = JSON.stringify({ UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId }, })), - (p = await axios.get(serverUrl + '/classes/contracts_Users?where=' + l, { + (c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + l, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY }, - })).data && 0 < p.data.results.length - ? ((s = p), 'contracts_Users') + })).data && 0 < c.data.results.length + ? ((s = c), 'contracts_Users') : ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + l, { headers: { 'X-Parse-Application-Id': APPID, @@ -155,8 +200,8 @@ async function PDF(i, n) { if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' }; { let e = Buffer.from(i.params.pdfFile, 'base64'); - var u = process.env.PFX_BASE64, - h = Buffer.from(u, 'base64'), + var h = process.env.PFX_BASE64, + u = Buffer.from(h, 'base64'), f = { UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId }, SignedUrl: '', @@ -165,20 +210,20 @@ async function PDF(i, n) { }; let a; var y = (a = - o.data.AuditTrail && 0 < o.data.AuditTrail.length - ? [...o.data.AuditTrail, f] + n.data.AuditTrail && 0 < n.data.AuditTrail.length + ? [...n.data.AuditTrail, f] : [f]).filter(e => 'Signed' === e.Activity); let t = !1; !( - (o.data.Signers && 0 < o.data.Signers.length && y.length !== o.data.Signers.length) || + (n.data.Signers && 0 < n.data.Signers.length && y.length !== n.data.Signers.length) || !(t = !0) ); var v, P, x = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`, - A = + b = (t - ? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), + ? ((v = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), (e = v && 0 < v.length ? plainAddPlaceholder({ @@ -193,38 +238,39 @@ async function PDF(i, n) { location: 'location', signatureLength: 1e4, })), - (P = await new SignPDF(e, h).signPDF()), + (P = await new SignPDF(e, u).signPDF()), fs.writeFileSync(x, P)) : fs.writeFileSync(x, e), await uploadFile(x)); - if (A && A.imageUrl) { - const n = await updateDoc( + if (b && b.imageUrl) { + const o = await updateDoc( i.params.docId, - A.imageUrl, + b.imageUrl, s.data.results[0].objectId, i.headers['x-real-ip'], - o.data, + n.data, r ); return ( sendMail({ - url: A.imageUrl, - sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name }, - pdfName: o.data.Name, + url: b.imageUrl, + sender: { Mail: n.data.ExtUserPtr.Email, Name: n.data.ExtUserPtr.Name }, + pdfName: n.data.Name, receiver: g, }), - n && - n.isCompleted && - sendCompletedMail({ - url: A.imageUrl, - sender: { Mail: o.data.ExtUserPtr.Email, Name: 'Open sign' }, - pdfName: o.data.Name, - receiver: o.data.ExtUserPtr.Email, + o && + o.isCompleted && + (sendCompletedMail({ + url: b.imageUrl, + sender: { Mail: n.data.ExtUserPtr.Email, Name: 'Open sign' }, + pdfName: n.data.Name, + receiver: n.data.ExtUserPtr.Email, }), + sendDoctoWebhook(n)), fs.unlinkSync(x), console.log('New Signed PDF created called: ' + x), - 'success' === n.message - ? { status: 'success', data: A.imageUrl } + 'success' === o.message + ? { status: 'success', data: b.imageUrl } : { status: 'error', message: 'please provide required parameters!' } ); } diff --git a/apps/OpenSignServer/cloud/parsefunction/saveWebhook.js b/apps/OpenSignServer/cloud/parsefunction/saveWebhook.js new file mode 100644 index 000000000..1beff7c4b --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/saveWebhook.js @@ -0,0 +1,29 @@ +import axios from 'axios'; +export default async function savewebhook(request) { + const serverUrl = 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; + } +} diff --git a/apps/OpenSignServer/databases/migrations/20240123122932-add_webhook_menu.cjs b/apps/OpenSignServer/databases/migrations/20240123122932-add_webhook_menu.cjs new file mode 100644 index 000000000..01f30c910 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20240123122932-add_webhook_menu.cjs @@ -0,0 +1,684 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const updateUserMenu = await userMenu.get('H9vRfEYKhT'); + updateUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'fa-solid fa-key', + title: 'API Token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + { + icon: 'fa-solid fa-globe', + title: 'Webhook', + target: '_self', + pageType: 'webhook', + description: '', + objectId: '', + }, + ], + }, + ]); + + const AdminMenu = new Parse.Query(className); + const updateAdminMenu = await AdminMenu.get('VPh91h0ZHk'); + updateAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + { + icon: 'fa-solid fa-key', + title: 'API Token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + { + icon: 'fa-solid fa-globe', + title: 'Webhook', + target: '_self', + pageType: 'webhook', + description: '', + objectId: '', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [updateUserMenu, updateAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + // TODO: set className here + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const revertUserMenu = await userMenu.get('H9vRfEYKhT'); + revertUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'fa-solid fa-key', + title: 'API Token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + ], + }, + ]); + + const adminMenu = new Parse.Query(className); + const revertAdminMenu = await adminMenu.get('VPh91h0ZHk'); + revertAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + { + icon: 'fa-solid fa-key', + title: 'API Token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [revertUserMenu, revertAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; From fd778c25e6fc57ac8e2963a0b5cc487ba453a314 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Tue, 23 Jan 2024 13:06:56 +0530 Subject: [PATCH 25/73] fix: add link mail tag --- apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 3400963d3..49be44df9 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -60,7 +60,7 @@ async function sendMail(e) { s + ' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + t.Mail + - ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>', + ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -85,7 +85,7 @@ async function sendCompletedMail(e) { s + '. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + t.Mail + - ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>', + ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { From 85a1c10d2658142f4568a026c32e3b597aff8d96 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 24 Jan 2024 12:04:37 +0530 Subject: [PATCH 26/73] feat: api for webhook crate,Read, update, delete --- .../cloud/customRoute/v1/apiV1.js | 12 ++++++ .../customRoute/v1/routes/deleteWebhook.js | 31 +++++++++++++++ .../cloud/customRoute/v1/routes/getWebhook.js | 32 +++++++++++++++ .../customRoute/v1/routes/saveWebhook.js | 39 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index b9585b119..dcaa73259 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -21,6 +21,9 @@ import multer from 'multer'; import updateDocument from './routes/updateDocument.js'; import deleteDocument from './routes/deleteDocument.js'; import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; +import saveWebhook from './routes/saveWebhook.js'; +import deleteWebhook from './routes/deleteWebhook.js'; +import getWebhook from './routes/getWebhook.js'; dotenv.config(); const storage = multer.memoryStorage(); @@ -77,3 +80,12 @@ app.delete('/template/:template_id', deletedTemplate); // get all types of documents on the basis of doctype app.get('/templatelist', getTemplatetList); + +// set and update webhook +app.get('/webhook', getWebhook); + +// set and update webhook +app.post('/webhook', saveWebhook); + +// set and update webhook +app.delete('/webhook', deleteWebhook); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js new file mode 100644 index 000000000..b51be025a --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js @@ -0,0 +1,31 @@ +export default async function deleteWebhook(request, response) { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userPtr = token.get('userId'); + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + const user = await query.first({ useMasterKey: true }); + if (user) { + const updateQuery = new Parse.Object('contracts_Users'); + updateQuery.id = user.id; + updateQuery.unset('Webhook'); + const res = await updateQuery.save(null, { useMasterKey: true }); + if (res) { + return response.json({ + result: 'Webhook deleted successfully!', + }); + } + } else { + return response.status(404).json({ error: 'User not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js new file mode 100644 index 000000000..9b55c3cf0 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -0,0 +1,32 @@ +export default async function getWebhook(request, response) { + const Url = request.body.Url; + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userPtr = token.get('userId'); + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + const user = await query.first({ useMasterKey: true }); + if (user) { + const parseUser = JSON.parse(JSON.stringify(user)); + + if (parseUser && parseUser.Webhook) { + return response.json({ + Webhook: parseUser.Webhook, + }); + } else { + return response.json({}); + } + } else { + return response.status(404).json({ error: 'User not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js new file mode 100644 index 000000000..3c2051a31 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -0,0 +1,39 @@ +export default async function saveWebhook(request, response) { + const Url = request.body.Url; + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userPtr = token.get('userId'); + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + const user = await query.first({ useMasterKey: true }); + if (user) { + const parseUser = JSON.parse(JSON.stringify(user)); + const isUrlExist = parseUser?.Webhook && parseUser?.Webhook === Url; + + if (!isUrlExist) { + const updateQuery = new Parse.Object('contracts_Users'); + updateQuery.id = user.id; + updateQuery.set('Webhook', Url); + const res = await updateQuery.save(null, { useMasterKey: true }); + if (res) { + return response.json({ + result: 'Webhook updated successfully!', + }); + } + } else { + return response.status(401).json({ error: 'Webhook url already exists!' }); + } + } else { + return response.status(404).json({ error: 'User not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } +} From 07851ccde21090ad2dab242f534d4459b97f966f Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 24 Jan 2024 18:12:38 +0530 Subject: [PATCH 27/73] feat: add create document api with base64 --- apps/OpenSign/src/App.js | 4 + apps/OpenSign/src/primitives/Validate.js | 57 ++++++ .../cloud/customRoute/v1/apiV1.js | 5 +- .../customRoute/v1/routes/createDocument.js | 162 ++++++++++++------ 4 files changed, 178 insertions(+), 50 deletions(-) create mode 100644 apps/OpenSign/src/primitives/Validate.js diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index e2cce85b5..c0920e2d7 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -18,6 +18,7 @@ import LoadMf from "./routes/LoadMf"; import GenerateToken from "./routes/GenerateToken"; import ValidateRoute from "./primitives/ValidateRoute"; import Webhook from "./routes/Webhook"; +import Validate from "./primitives/Validate"; function App() { const [isloading, setIsLoading] = useState(true); @@ -65,6 +66,9 @@ function App() { <Route exact path="/" element={<Login />} /> <Route exact path="/signup" element={<Signup />} /> </Route> + <Route element={<Validate />}> + <Route exact path="/load/:remoteApp/*" element={<LoadMf />} /> + </Route> <Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} /> <Route exact path="/forgetpassword" element={<ForgetPassword />} /> {process.env.REACT_APP_ENABLE_SUBSCRIPTION && ( diff --git a/apps/OpenSign/src/primitives/Validate.js b/apps/OpenSign/src/primitives/Validate.js new file mode 100644 index 000000000..86993d8b3 --- /dev/null +++ b/apps/OpenSign/src/primitives/Validate.js @@ -0,0 +1,57 @@ +import React, { useState, useEffect } from "react"; +import Parse from "parse"; +import { Outlet, useNavigate, useLocation } from "react-router-dom"; +import ModalUi from "./ModalUi"; +const Validate = () => { + const navigate = useNavigate(); + const location = useLocation(); + const [isUserValid, setIsUserValid] = useState(true); + useEffect(() => { + (async () => { + try { + // Use the session token to validate the user + const userQuery = new Parse.Query(Parse.User); + const user = await userQuery.get(Parse.User.current().id, { + sessionToken: localStorage.getItem("accesstoken") + }); + if (user) { + setIsUserValid(true); + } else { + setIsUserValid(false); + } + } catch (error) { + // Session token is invalid or there was an error + setIsUserValid(false); + } + })(); + }, []); + const handleLoginBtn = () => { + try { + Parse.User.logOut(); + } catch (err) { + console.log("err ", err); + } finally { + localStorage.removeItem("accesstoken"); + navigate("/", { replace: true, state: { from: location } }); + } + }; + return isUserValid ? ( + <div> + <Outlet /> + </div> + ) : ( + <ModalUi title={"Session Expired"} isOpen={true} showClose={false}> + <div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5"> + <p className="text-xl font-normal">Your session has expired.</p> + <button + onClick={handleLoginBtn} + className="text-base px-3 py-1.5 rounded shadow-md text-white bg-[#1ab6ce]" + > + Login + </button> + </div> + </ModalUi> + ); +}; + +export default Validate; diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index dcaa73259..6938d02f2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -49,7 +49,10 @@ app.delete('/contact/:contact_id', deleteContact); app.get('/contactlist', getContactList); // create Document -app.post('/createdocument', upload.array('file', 1), createDocument); +app.post('/createdocumentwithbinary', upload.array('file', 1), createDocument); + +// create Document with base64 +app.post('/createdocument', createDocument); // create Document with templateId app.post('/createdocument/:template_id', createDocumentWithTemplate); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 05c99ccde..0f2a1505d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -1,13 +1,16 @@ -const randomId = () => Math.floor(1000 + Math.random() * 9000); +// import batchQuery from './batchquery.js'; + +// const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocument(request, response) { const name = request.body.Title; const note = request.body.Note; const description = request.body.Description; const signers = request.body.Signers; const folderId = request.body.FolderId; - // const file = request.body.file; - const url = process.env.SERVER_URL; - const fileData = request.files[0] ? request.files[0].buffer : null; + const base64File = request.body.file; + const url = request?.get('host'); + const fileData = request.files?.[0] ? request.files[0].buffer : null; + console.log('fileData ', fileData); try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -18,55 +21,116 @@ export default async function createDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + if (signers) { + const userPtr = token.get('userId'); + let fileUrl; + if (request.files?.[0]) { + const file = new Parse.File(request.files?.[0]?.originalname, { + base64: fileData?.toString('base64'), + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } else { + const file = new Parse.File(`${name}.pdf`, { + base64: base64File, + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userPtr); + const extUser = await contractsUser.first({ useMasterKey: true }); + const extUserPtr = { + __type: 'Pointer', + className: 'contracts_Users', + objectId: extUser.id, + }; - const file = new Parse.File(request.files?.[0]?.originalname, { - base64: fileData.toString('base64'), - }); - await file.save({ useMasterKey: true }); - const fileUrl = file.url(); - const contractsUser = new Parse.Query('contracts_Users'); - contractsUser.equalTo('UserId', userPtr); - const extUser = await contractsUser.first({ useMasterKey: true }); - const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; + const folderPtr = { + __type: 'Pointer', + className: 'contracts_Document', + objectId: folderId, + }; - const folderPtr = { __type: 'Pointer', className: 'contracts_Document', objectId: folderId }; + const object = new Parse.Object('contracts_Document'); + object.set('Name', name); + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', fileUrl); + object.set('CreatedBy', userPtr); + object.set('ExtUserPtr', extUserPtr); + if (signers) { + let parseSigners; + if (base64File) { + parseSigners = signers; + } else { + parseSigners = JSON.parse(signers); + } - const object = new Parse.Object('contracts_Document'); - object.set('Name', name); - if (note) { - object.set('Note', note); - } - if (description) { - object.set('Description', description); - } - object.set('URL', fileUrl); - object.set('CreatedBy', userPtr); - object.set('ExtUserPtr', extUserPtr); - if (signers) { - const parseSigners = JSON.parse(signers); - const placeholders = parseSigners.map(x => ({ - email: x, - Id: randomId(), - Role: '', - blockColor: '', - signerObjId: '', - signerPtr: {}, - placeHolder: [], - })); - object.set('Placeholders', placeholders); - } - if (folderId) { - object.set('Folder', folderPtr); + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.equalTo('UserId', userPtr); + contactbook.notEqualTo('IsDeleted', true); + contactbook.containedIn('Email', parseSigners); + const contactbookRes = await contactbook.find({ useMasterKey: true }); + console.log('contactbookRes ', contactbookRes); + const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); + // console.log('userPtr ', userPtr); + // const newContacts = parseSigners + // .filter(x => !parseContactbookRes.some(y => y.Email === x)) + // .map(email => ({ + // method: 'POST', + // path: '/app/classes/contracts_Contactbook', + // body: { + // Email: email, + // CreatedBy: { __type: 'Pointer', className: '_User', objectId: userPtr.id }, + // UserId: { __type: 'Pointer', className: '_User', objectId: userPtr.id }, + // Role: 'contracts_Guest', + // IsDeleted: false, + // ACL: { + // [userPtr.id]: { read: true, write: true }, + // }, + // }, + // })); + // console.log('newContacts', newContacts); + let contactSigners = parseContactbookRes?.map(x => ({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: x.objectId, + })); + // if (newContacts.length > 0) { + // const batchRes = await batchQuery(newContacts); + // const contacts = batchRes?.map(x => ({ + // __type: 'Pointer', + // className: 'contracts_Contactbook', + // objectId: x.success.objectId, + // })); + // contactSigners = [...contactSigners, ...contacts]; + // } + // console.log('contactsigners', contactSigners); + + object.set('Signers', contactSigners); + } + if (folderId) { + object.set('Folder', folderPtr); + } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(userPtr.id, true); + newACL.setWriteAccess(userPtr.id, true); + object.setACL(newACL); + const res = await object.save(null, { useMasterKey: true }); + return response.json({ + objectId: res.id, + url: 'https://' + url + '/load/signmicroapp/placeholdersign/' + res.id, + }); + } else { + return response.status(400).json({ error: 'Please provide signers!' }); } - const newACL = new Parse.ACL(); - newACL.setPublicReadAccess(false); - newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.id, true); - newACL.setWriteAccess(userPtr.id, true); - object.setACL(newACL); - const res = await object.save(null, { useMasterKey: true }); - return response.json({ objectId: res.id, url: url }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); } From 55cfbae8a7ed573755299a0c046894a468137d07 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 24 Jan 2024 23:17:44 +0530 Subject: [PATCH 28/73] feat: api for createtemplate using base64 and binary --- apps/OpenSign/src/routes/GenerateToken.js | 18 +---- apps/OpenSign/src/routes/Webhook.js | 23 +----- .../customRoute/v1/routes/createContact.js | 2 +- .../customRoute/v1/routes/createDocument.js | 6 +- .../customRoute/v1/routes/createTemplate.js | 77 ++++++++++++------- .../cloud/parsefunction/TemplateAfterSave.js | 2 +- .../cloud/parsefunction/pdf/PDF.min.js | 1 - 7 files changed, 62 insertions(+), 67 deletions(-) diff --git a/apps/OpenSign/src/routes/GenerateToken.js b/apps/OpenSign/src/routes/GenerateToken.js index 1adc0f3e7..9c23bf344 100644 --- a/apps/OpenSign/src/routes/GenerateToken.js +++ b/apps/OpenSign/src/routes/GenerateToken.js @@ -90,7 +90,7 @@ function GenerateToken() { const handleModal = () => setIsModal(!isModal); return ( <React.Fragment> - <Title title={"token"} /> + <Title title={"API Token"} /> {isGenerate && ( <Alert type="success">Token generated successfully!</Alert> )} @@ -115,9 +115,10 @@ function GenerateToken() { </div> ) : ( <div className="bg-white flex flex-col justify-center shadow rounded"> - <ul className="w-full flex flex-col p-2 text-sm"> + <h1 className="ml-4 mt-3 mb-2 font-semibold">API Token</h1> + <ul className="w-full flex flex-col p-2 text-sm"> <li - className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all py-2`} + className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} > <span className="w-[40%]">Api Token:</span>{" "} <span @@ -128,17 +129,6 @@ function GenerateToken() { {apiToken && apiToken} </span> </li> - <li - className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} - > - <span className="w-[40%]">Application Id:</span>{" "} - <span - className="w-[60%] md:text-end cursor-pointer" - onClick={() => copytoclipboard(localStorage.getItem("AppID12"))} - > - {localStorage.getItem("AppID12")} - </span> - </li> </ul> <div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4"> <button diff --git a/apps/OpenSign/src/routes/Webhook.js b/apps/OpenSign/src/routes/Webhook.js index 2c1424ec5..c67e97b19 100644 --- a/apps/OpenSign/src/routes/Webhook.js +++ b/apps/OpenSign/src/routes/Webhook.js @@ -12,7 +12,6 @@ function Webhook() { const [parseAppId] = useState(localStorage.getItem("parseAppId")); const [webhook, setWebhook] = useState(); const [isLoader, setIsLoader] = useState(true); - const [copied, setCopied] = useState(false); const [isGenerate, setIsGenerate] = useState(false); const [isErr, setIsErr] = useState(false); const [isModal, setIsModal] = useState(false); @@ -77,19 +76,11 @@ function Webhook() { } }; - const copytoclipboard = (text) => { - navigator.clipboard.writeText(text); - setCopied(true); - setTimeout(() => { - setCopied(false); - }, 1500); // Reset copied state after 1.5 seconds - }; const handleModal = () => setIsModal(!isModal); return ( <React.Fragment> <Title title={"Webhook"} /> {isGenerate && <Alert type="success">Webhook added successfully!</Alert>} - {copied && <Alert type="success">Copied</Alert>} {isErr && <Alert type="danger">Something went wrong!</Alert>} {isLoader ? ( <div @@ -110,26 +101,16 @@ function Webhook() { </div> ) : ( <div className="bg-white flex flex-col justify-center shadow rounded"> + <h1 className="ml-4 mt-3 mb-2 font-semibold">Webhook</h1> <ul className="w-full flex flex-col p-2 text-sm"> <li - className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all py-2`} + className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} > <span className="w-[40%]">Webhook:</span>{" "} <span id="token" className="w-[60%] md:text-end cursor-pointer"> {webhook && webhook} </span> </li> - <li - className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} - > - <span className="w-[40%]">Application Id:</span>{" "} - <span - className="w-[60%] md:text-end cursor-pointer" - onClick={() => copytoclipboard(localStorage.getItem("AppID12"))} - > - {localStorage.getItem("AppID12")} - </span> - </li> </ul> <div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4"> <button diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index 2079f059a..59aa21aa2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -131,7 +131,7 @@ export default async function createContact(request, response) { } catch (err) { console.log('err ', err); if (err.code === 137) { - return response.status(137).json({ error: 'Contact already exists!' }); + return response.status(401).json({ error: 'Contact already exists!' }); } else { return response .status(400) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 0f2a1505d..c34601520 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -7,10 +7,10 @@ export default async function createDocument(request, response) { const description = request.body.Description; const signers = request.body.Signers; const folderId = request.body.FolderId; - const base64File = request.body.file; + const base64File = request.body.File; const url = request?.get('host'); const fileData = request.files?.[0] ? request.files[0].buffer : null; - console.log('fileData ', fileData); + // console.log('fileData ', fileData); try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -76,7 +76,7 @@ export default async function createDocument(request, response) { contactbook.notEqualTo('IsDeleted', true); contactbook.containedIn('Email', parseSigners); const contactbookRes = await contactbook.find({ useMasterKey: true }); - console.log('contactbookRes ', contactbookRes); + // console.log('contactbookRes ', contactbookRes); const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); // console.log('userPtr ', userPtr); // const newContacts = parseSigners diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 83580707f..ecd48381a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -1,13 +1,13 @@ const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createTemplate(request, response) { - const name = request.body.Title; - const note = request.body.Note; - const description = request.body.Description; - const signers = request.body.Signers; - const folderId = request.body.FolderId; - // const file = request.body.file; - const url = process.env.SERVER_URL; - const fileData = request.files[0] ? request.files[0].buffer : null; + const name = request.body?.Title; + const note = request.body?.Note; + const description = request.body?.Description; + const signers = request.body?.Signers; + const folderId = request.body?.FolderId; + const url = request?.get('host'); + const base64File = request.body.File; + const fileData = request.files?.[0] ? request.files[0].buffer : null; try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -19,13 +19,23 @@ export default async function createTemplate(request, response) { if (token !== undefined) { // Valid Token then proceed request const userPtr = token.get('userId'); - const file = new Parse.File(request.files?.[0]?.originalname, { - base64: fileData.toString('base64'), - }); - await file.save({ useMasterKey: true }); - const fileUrl = file.url(); + let fileUrl; + if (base64File) { + const file = new Parse.File(`${name}.pdf`, { + base64: base64File, + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } else { + const file = new Parse.File(request.files?.[0]?.originalname, { + base64: fileData?.toString('base64'), + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } + const contractsUser = new Parse.Query('contracts_Users'); - contractsUser.equalTo('UserId', userId); + contractsUser.equalTo('UserId', userPtr); const extUser = await contractsUser.first({ useMasterKey: true }); const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; @@ -43,17 +53,29 @@ export default async function createTemplate(request, response) { object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); if (signers) { - const parseSigners = JSON.parse(signers); - const placeholders = parseSigners.map((x, i) => ({ - email: x, - Id: randomId(), - Role: 'User ' + (i + 1), - blockColor: '', - signerObjId: '', - signerPtr: {}, - placeHolder: [], - })); - object.set('Placeholders', placeholders); + let parseSigners; + if (base64File) { + parseSigners = signers; + } else { + parseSigners = JSON.parse(signers); + } + + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.containedIn('Email', parseSigners); + contactbook.equalTo('UserId', userPtr); + contactbook.notEqualTo('IsDeleted', true); + const contactbookRes = await contactbook.find({ useMasterKey: true }); + // console.log('contactbookRes ', contactbookRes); + const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); + + object.set( + 'Signers', + parseContactbookRes?.map(x => ({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: x.objectId, + })) + ); } if (folderId) { object.set('Folder', folderPtr); @@ -65,7 +87,10 @@ export default async function createTemplate(request, response) { newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); - return response.json({ objectId: res.id, url: url }); + return response.json({ + objectId: res.id, + url: 'https://' + url + '/load/signmicroapp/template/' + res.id, + }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index d5bcc168a..556cf1c39 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -13,7 +13,7 @@ export default async function TemplateAfterSave(request) { } } } else { - if (request.user) { + if (request?.user) { const signers = request.object.get('Signers'); if (signers && signers.length > 0) { await updateAclDoc(request.object.id); diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 49be44df9..ee778c228 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -112,7 +112,6 @@ async function sendDoctoWebhook(t) { .post(t?.data?.ExtUserPtr?.Webhook, e, { headers: { 'Content-Type': 'application/json' } }) .then(e => { try { - console.log('res ', e); var a = new Parse.Object('contracts_Webhook'); a.set('Log', e?.status), a.set('UserId', { From bbedb13f3ef6ec49453a4dfafa3a066acf8cb58a Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 24 Jan 2024 23:18:08 +0530 Subject: [PATCH 29/73] feat: api for createtemplate using base64 and binary --- apps/OpenSignServer/cloud/customRoute/v1/apiV1.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 6938d02f2..b4a5449b3 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -70,7 +70,10 @@ app.delete('/document/:document_id', deleteDocument); app.get('/documentlist/:doctype', getDocumentList); // create Template -app.post('/createtemplate', upload.array('file', 1), createTemplate); +app.post('/createtemplate', createTemplate); + +// create Template with binary +app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplate); // get template on the basis of id app.get('/template/:template_id', getTemplate); From 00e9396590dcd7480dbab01df199e3f08ae65514 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 24 Jan 2024 23:38:49 +0530 Subject: [PATCH 30/73] change API doc url in webhook and API token in menu --- apps/OpenSign/src/routes/GenerateToken.js | 6 +++++- apps/OpenSign/src/routes/Webhook.js | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/OpenSign/src/routes/GenerateToken.js b/apps/OpenSign/src/routes/GenerateToken.js index 9c23bf344..d112f15c3 100644 --- a/apps/OpenSign/src/routes/GenerateToken.js +++ b/apps/OpenSign/src/routes/GenerateToken.js @@ -140,7 +140,11 @@ function GenerateToken() { </button> <button type="button" - onClick={() => openInNewTab("https://docs.opensignlabs.com")} + onClick={() => + openInNewTab( + "https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1" + ) + } className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none" > View Docs diff --git a/apps/OpenSign/src/routes/Webhook.js b/apps/OpenSign/src/routes/Webhook.js index c67e97b19..eaaf5b226 100644 --- a/apps/OpenSign/src/routes/Webhook.js +++ b/apps/OpenSign/src/routes/Webhook.js @@ -122,7 +122,11 @@ function Webhook() { </button> <button type="button" - onClick={() => openInNewTab("https://docs.opensignlabs.com")} + onClick={() => + openInNewTab( + "https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1" + ) + } className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none" > View Docs From d3b2e1f24be60028bf98d00ee31172a4e0c4bc9e Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 25 Jan 2024 18:04:22 +0530 Subject: [PATCH 31/73] fix: all body parameter must be in lowercase --- .../v1/routes/CreateDocumentWithTemplate.js | 82 ++++-- .../customRoute/v1/routes/createContact.js | 240 ++++++++++-------- .../customRoute/v1/routes/createDocument.js | 100 ++++---- .../customRoute/v1/routes/createTemplate.js | 70 +++-- .../cloud/customRoute/v1/routes/getWebhook.js | 1 - .../customRoute/v1/routes/saveWebhook.js | 2 +- .../customRoute/v1/routes/updateDocument.js | 4 +- .../customRoute/v1/routes/updateTemplate.js | 2 +- .../cloud/parsefunction/DocumentAftersave.js | 29 +-- .../cloud/parsefunction/TemplateAfterSave.js | 15 +- 10 files changed, 305 insertions(+), 240 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 3ae07bac3..6efa6f84d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -1,9 +1,17 @@ const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocumentWithTemplate(request, response) { - const signers = request.body.Signers; - const folderId = request.body.FolderId; + const signers = request.body.signers; + const folderId = request.body.folderId; const templateId = request.params.template_id; - const url = process.env.SERVER_URL; + const url = request?.get('host'); + let protocol = 'https://' + url; + if (request.hostname === 'localhost') { + // console.log('Running in development environment'); + protocol = 'http://' + url; + } else { + // console.log('Running in production environment'); + protocol = 'https://' + url; + } try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -40,31 +48,52 @@ export default async function createDocumentWithTemplate(request, response) { if (template?.Description) { object.set('Description', template.Description); } - if (template?.Signers) { - object.set('Signers', template?.Signers); - } - object.set('URL', template.URL); - object.set('CreatedBy', template.CreatedBy); - object.set('ExtUserPtr', template.ExtUserPtr); - if (signers) { - const placeholders = template?.Placeholders?.map(placeholder => { - let matchingSigner = signers.find(y => y.Role === placeholder.Role); - if (matchingSigner) { - return { - ...placeholder, - email: matchingSigner.Email, - signerObjId: '', - signerPtr: {}, - }; + let templateSigner = template?.Signers ? template?.Signers : []; + if (signers && signers.length > 0) { + let parseSigners; + if (base64File) { + parseSigners = signers; } else { - return { - ...placeholder, + parseSigners = JSON.parse(signers); + } + let createContactUrl = protocol + '/v1/createcontact'; + + let contact = []; + for (const obj of parseSigners) { + const body = { + name: obj?.name || '', + email: obj?.email || '', + phone: obj?.phone || '', }; + try { + const res = await axios.post(createContactUrl, body, { + headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, + }); + // console.log('res ', res.data); + contact.push({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: res.data?.objectId, + }); + } catch (err) { + // console.log('err ', err.response); + if (err?.response?.data?.objectId) { + contact.push({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: err.response.data?.objectId, + }); + } + } } - }); - console.log('placeholders ', placeholders); - object.set('Placeholders', placeholders); + object.set('Signers', [...templateSigner, ...contact]); + } else { + object.set('Signers', templateSigner); } + + object.set('URL', template.URL); + object.set('CreatedBy', template.CreatedBy); + object.set('ExtUserPtr', template.ExtUserPtr); if (folderId) { object.set('Folder', folderPtr); } @@ -75,7 +104,10 @@ export default async function createDocumentWithTemplate(request, response) { newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); - return response.json({ objectId: res.id, url: url }); + return response.json({ + objectId: res.id, + url: protocol + '/load/signmicroapp/placeholdersign/' + res.id, + }); } else { return response.status(400).json({ error: 'Please provide signers properly!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index 59aa21aa2..ba6ffa503 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -2,9 +2,9 @@ import axios from 'axios'; export default async function createContact(request, response) { const serverUrl = process.env.SERVER_URL; const appId = process.env.APP_ID; - const name = request.body.Name; - const phone = request.body.Phone; - const email = request.body.Email; + const name = request.body.name; + const phone = request.body.phone; + const email = request.body.email; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -16,127 +16,143 @@ export default async function createContact(request, response) { // Valid Token then proceed request const userPtr = token.get('userId'); try { - const Tenant = new Parse.Query('partners_Tenant'); - Tenant.equalTo('UserId', userPtr); - const tenantRes = await Tenant.first({ useMasterKey: true }); + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.equalTo('Email', email); + contactbook.equalTo('CreatedBy', userPtr); - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', name); - contactQuery.set('Phone', phone); - contactQuery.set('Email', email); - contactQuery.set('UserRole', 'contracts_Guest'); - if (tenantRes && tenantRes.id) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantRes.id, - }); - } - try { - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('phone', phone); - _user.set('password', phone); + const userExists = await contactbook.first({ useMasterKey: true }); - const user = await _user.save(); - if (user) { - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: user.id, - }; - await axios.post(roleurl, body, { headers: headers }); - const currentUser = userPtr; - contactQuery.set('CreatedBy', currentUser); - contactQuery.set('UserId', user); + if (userExists) { + return response + .status(401) + .json({ error: 'Contact already exists!', objectId: userExists.id }); + } else { + try { + const Tenant = new Parse.Query('partners_Tenant'); + Tenant.equalTo('UserId', userPtr); + const tenantRes = await Tenant.first({ useMasterKey: true }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); - acl.setReadAccess(user.id, true); - acl.setWriteAccess(user.id, true); - contactQuery.setACL(acl); + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + contactQuery.set('Phone', phone); + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + if (tenantRes && tenantRes.id) { + contactQuery.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: tenantRes.id, + }); + } + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', name); + _user.set('username', email); + _user.set('email', email); + _user.set('phone', phone); + _user.set('password', phone); - const contactRes = await contactQuery.save(); - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } catch (err) { - console.log('err in', err); - if (err.code === 202) { - const params = { email: email }; - const userRes = await Parse.Cloud.run('getUserId', params); - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: userRes.id, - }; - await axios.post(roleurl, body, { headers: headers }); - contactQuery.set('CreatedBy', userPtr); - contactQuery.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userRes.id, - }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); - acl.setReadAccess(userRes.id, true); - acl.setWriteAccess(userRes.id, true); + const user = await _user.save(); + if (user) { + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: user.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = userPtr; + contactQuery.set('CreatedBy', currentUser); + contactQuery.set('UserId', user); - contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - if (contactRes) { - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + contactQuery.setACL(acl); + + const contactRes = await contactQuery.save(); + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } + } catch (err) { + console.log('err in', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: userRes.id, + }; + await axios.post(roleurl, body, { headers: headers }); + contactQuery.set('CreatedBy', userPtr); + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + + contactQuery.setACL(acl); + const contactRes = await contactQuery.save(); + if (contactRes) { + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } + } else { + if (err.code === 137) { + return response.status(401).json({ error: 'Contact already exists!' }); + } + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); + } } - } else { + } catch (err) { + console.log('err ', err); if (err.code === 137) { return response.status(401).json({ error: 'Contact already exists!' }); + } else { + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); } } } catch (err) { - console.log('err ', err); - if (err.code === 137) { - return response.status(401).json({ error: 'Contact already exists!' }); - } else { - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index c34601520..e4c7a4a7f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -1,16 +1,26 @@ // import batchQuery from './batchquery.js'; +import axios from 'axios'; + // const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocument(request, response) { - const name = request.body.Title; - const note = request.body.Note; - const description = request.body.Description; - const signers = request.body.Signers; - const folderId = request.body.FolderId; - const base64File = request.body.File; + const name = request.body.title; + const note = request.body.note; + const description = request.body.description; + const signers = request.body.signers; + const folderId = request.body.folderId; + const base64File = request.body.file; const url = request?.get('host'); const fileData = request.files?.[0] ? request.files[0].buffer : null; // console.log('fileData ', fileData); + let protocol = 'https://' + url; + if (request.hostname === 'localhost') { + // console.log('Running in development environment'); + protocol = 'http://' + url; + } else { + // console.log('Running in production environment'); + protocol = 'https://' + url; + } try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -21,7 +31,7 @@ export default async function createDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - if (signers) { + if (signers && signers.length > 0) { const userPtr = token.get('userId'); let fileUrl; if (request.files?.[0]) { @@ -63,56 +73,44 @@ export default async function createDocument(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); - if (signers) { + if (signers && signers.length > 0) { let parseSigners; if (base64File) { parseSigners = signers; } else { parseSigners = JSON.parse(signers); } + let createContactUrl = protocol + '/v1/createcontact'; - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.equalTo('UserId', userPtr); - contactbook.notEqualTo('IsDeleted', true); - contactbook.containedIn('Email', parseSigners); - const contactbookRes = await contactbook.find({ useMasterKey: true }); - // console.log('contactbookRes ', contactbookRes); - const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); - // console.log('userPtr ', userPtr); - // const newContacts = parseSigners - // .filter(x => !parseContactbookRes.some(y => y.Email === x)) - // .map(email => ({ - // method: 'POST', - // path: '/app/classes/contracts_Contactbook', - // body: { - // Email: email, - // CreatedBy: { __type: 'Pointer', className: '_User', objectId: userPtr.id }, - // UserId: { __type: 'Pointer', className: '_User', objectId: userPtr.id }, - // Role: 'contracts_Guest', - // IsDeleted: false, - // ACL: { - // [userPtr.id]: { read: true, write: true }, - // }, - // }, - // })); - // console.log('newContacts', newContacts); - let contactSigners = parseContactbookRes?.map(x => ({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: x.objectId, - })); - // if (newContacts.length > 0) { - // const batchRes = await batchQuery(newContacts); - // const contacts = batchRes?.map(x => ({ - // __type: 'Pointer', - // className: 'contracts_Contactbook', - // objectId: x.success.objectId, - // })); - // contactSigners = [...contactSigners, ...contacts]; - // } - // console.log('contactsigners', contactSigners); - - object.set('Signers', contactSigners); + let contact = []; + for (const obj of parseSigners) { + const body = { + name: obj?.name || '', + email: obj?.email || '', + phone: obj?.phone || '', + }; + try { + const res = await axios.post(createContactUrl, body, { + headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, + }); + // console.log('res ', res.data); + contact.push({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: res.data?.objectId, + }); + } catch (err) { + // console.log('err ', err.response); + if (err?.response?.data?.objectId) { + contact.push({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: err.response.data?.objectId, + }); + } + } + } + object.set('Signers', contact); } if (folderId) { object.set('Folder', folderPtr); @@ -126,7 +124,7 @@ export default async function createDocument(request, response) { const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, - url: 'https://' + url + '/load/signmicroapp/placeholdersign/' + res.id, + url: protocol + '/load/signmicroapp/placeholdersign/' + res.id, }); } else { return response.status(400).json({ error: 'Please provide signers!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index ecd48381a..4879d7988 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -1,13 +1,21 @@ const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createTemplate(request, response) { - const name = request.body?.Title; - const note = request.body?.Note; - const description = request.body?.Description; - const signers = request.body?.Signers; - const folderId = request.body?.FolderId; + const name = request.body?.title; + const note = request.body?.note; + const description = request.body?.description; + const signers = request.body?.signers; + const folderId = request.body?.folderId; const url = request?.get('host'); - const base64File = request.body.File; + const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; + let protocol = 'https://' + url; + if (request.hostname === 'localhost') { + // console.log('Running in development environment'); + protocol = 'http://' + url; + } else { + // console.log('Running in production environment'); + protocol = 'https://' + url; + } try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -52,30 +60,44 @@ export default async function createTemplate(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); - if (signers) { + if (signers && signers.length > 0) { let parseSigners; if (base64File) { parseSigners = signers; } else { parseSigners = JSON.parse(signers); } + let createContactUrl = protocol + '/v1/createcontact'; - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.containedIn('Email', parseSigners); - contactbook.equalTo('UserId', userPtr); - contactbook.notEqualTo('IsDeleted', true); - const contactbookRes = await contactbook.find({ useMasterKey: true }); - // console.log('contactbookRes ', contactbookRes); - const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); - - object.set( - 'Signers', - parseContactbookRes?.map(x => ({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: x.objectId, - })) - ); + let contact = []; + for (const obj of parseSigners) { + const body = { + name: obj?.name || '', + email: obj?.email || '', + phone: obj?.phone || '', + }; + try { + const res = await axios.post(createContactUrl, body, { + headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, + }); + // console.log('res ', res.data); + contact.push({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: res.data?.objectId, + }); + } catch (err) { + // console.log('err ', err.response); + if (err?.response?.data?.objectId) { + contact.push({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: err.response.data?.objectId, + }); + } + } + } + object.set('Signers', contact); } if (folderId) { object.set('Folder', folderPtr); @@ -89,7 +111,7 @@ export default async function createTemplate(request, response) { const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, - url: 'https://' + url + '/load/signmicroapp/template/' + res.id, + url: protocol + '/load/signmicroapp/template/' + res.id, }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js index 9b55c3cf0..c022d0d38 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -1,5 +1,4 @@ export default async function getWebhook(request, response) { - const Url = request.body.Url; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js index 3c2051a31..675fe6e90 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -1,5 +1,5 @@ export default async function saveWebhook(request, response) { - const Url = request.body.Url; + const Url = request.body.url; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index 2f0b76c53..c6ecc0c2c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -8,8 +8,8 @@ export default async function updateDocument(request, response) { tokenQuery.equalTo('token', reqToken); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { - // Valid Token then proceed request - const allowedKeys = ['Name', 'Note', 'Description']; + // Valid Token then proceed request + const allowedKeys = ['name', 'note', 'description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index d3445bcf5..791844a8b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -9,7 +9,7 @@ export default async function updateTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const allowedKeys = ['Name', 'Note', 'Description']; + const allowedKeys = ['name', 'note', 'description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js index 701ebd608..dc26a3e09 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js @@ -4,20 +4,11 @@ async function DocumentAftersave(request) { console.log('new entry is insert in contracts_Document'); const createdAt = request.object.get('createdAt'); const Folder = request.object.get('Type'); - // console.log("createdAt") - // console.log(createdAt) - // console.log("Folder") - // console.log(Folder) - // console.log("before If condition") if (createdAt && Folder === undefined) { // console.log("IN If condition") const TimeToCompleteDays = request.object.get('TimeToCompleteDays'); const ExpiryDate = new Date(createdAt); - // console.log("ExpiryDate") - // console.log(ExpiryDate) ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays); - // console.log("ExpiryDate date after update") - // console.log(ExpiryDate) const documentQuery = new Parse.Query('contracts_Document'); const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true }); updateQuery.set('ExpiryDate', ExpiryDate); @@ -37,8 +28,6 @@ async function DocumentAftersave(request) { } const signers = request.object.get('Signers'); - // console.log("Signers") - // console.log(signers.length) // update acl of New Document If There are signers present in array if (signers && signers.length > 0) { await updateAclDoc(request.object.id); @@ -48,7 +37,7 @@ async function DocumentAftersave(request) { } } } else { - if (request.user) { + if (request?.user) { const signers = request.object.get('Signers'); if (signers && signers.length > 0) { await updateAclDoc(request.object.id); @@ -69,6 +58,7 @@ async function DocumentAftersave(request) { // console.log(objId) const Query = new Parse.Query('contracts_Document'); Query.include('Signers'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -91,9 +81,10 @@ async function DocumentAftersave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); - + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } UsersPtr.forEach(x => { newACL.setReadAccess(x.objectId, true); newACL.setWriteAccess(x.objectId, true); @@ -104,9 +95,9 @@ async function DocumentAftersave(request) { } async function updateSelfDoc(objId) { - // console.log("In side updateSelfDoc func") // console.log(objId) const Query = new Parse.Query('contracts_Document'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -114,8 +105,10 @@ async function DocumentAftersave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } updateACL.setACL(newACL); updateACL.save(null, { useMasterKey: true }); } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index 556cf1c39..96389e6cc 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -34,6 +34,7 @@ export default async function TemplateAfterSave(request) { // console.log(objId) const Query = new Parse.Query('contracts_Template'); Query.include('Signers'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -56,9 +57,10 @@ export default async function TemplateAfterSave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); - + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } UsersPtr.forEach(x => { newACL.setReadAccess(x.objectId, true); newACL.setWriteAccess(x.objectId, true); @@ -72,6 +74,7 @@ export default async function TemplateAfterSave(request) { // console.log("Inside updateSelfDoc func") const Query = new Parse.Query('contracts_Template'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); // const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -79,8 +82,10 @@ export default async function TemplateAfterSave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } updateACL.setACL(newACL); updateACL.save(null, { useMasterKey: true }); } From a92d90db4ab7b0b404589c49aa2f7baccee7826d Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 25 Jan 2024 18:36:49 +0530 Subject: [PATCH 32/73] change body parameter of update API --- .../customRoute/v1/routes/updateDocument.js | 16 ++++++++-------- .../customRoute/v1/routes/updateTemplate.js | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index c6ecc0c2c..30c9b9d41 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -26,20 +26,20 @@ export default async function updateDocument(request, response) { const document = Parse.Object.extend('contracts_Document'); const updateQuery = new document(); updateQuery.id = request.params.document_id; - if (request?.body?.Name) { - updateQuery.set('Name', request?.body?.Name); + if (request?.body?.name) { + updateQuery.set('Name', request?.body?.name); } - if (request?.body?.Note) { - updateQuery.set('Note', request?.body?.Note); + if (request?.body?.note) { + updateQuery.set('Note', request?.body?.note); } - if (request?.body?.Description) { - updateQuery.set('Name', request?.body?.Description); + if (request?.body?.description) { + updateQuery.set('Name', request?.body?.description); } - if (request?.body?.FolderId) { + if (request?.body?.folderId) { updateQuery.set('Folder', { __type: 'Pointer', className: 'contracts_Document', - objectId: request?.body?.FolderId, + objectId: request?.body?.folderId, }); } const updatedRes = await updateQuery.save(null, { useMasterKey: true }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 791844a8b..38dac8e6d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -26,20 +26,20 @@ export default async function updateTemplate(request, response) { const template = Parse.Object.extend('contracts_Template'); const updateQuery = new template(); updateQuery.id = request.params.template_id; - if (request?.body?.Name) { - updateQuery.set('Name', request?.body?.Name); + if (request?.body?.name) { + updateQuery.set('Name', request?.body?.name); } - if (request?.body?.Note) { - updateQuery.set('Note', request?.body?.Note); + if (request?.body?.note) { + updateQuery.set('Note', request?.body?.note); } - if (request?.body?.Description) { - updateQuery.set('Name', request?.body?.Description); + if (request?.body?.description) { + updateQuery.set('Name', request?.body?.description); } - if (request?.body?.FolderId) { + if (request?.body?.folderId) { updateQuery.set('Folder', { __type: 'Pointer', className: 'contracts_Template', - objectId: request?.body?.FolderId, + objectId: request?.body?.folderId, }); } const updatedRes = await updateQuery.save(null, { useMasterKey: true }); From 8686a35405c5ea2d8e3ccfa53ac9e101cb02b0e2 Mon Sep 17 00:00:00 2001 From: Amol <amol@nxglabs.in> Date: Thu, 25 Jan 2024 18:59:55 +0530 Subject: [PATCH 33/73] Revert "fix: all body parameter of API must be in lowercase" --- .../v1/routes/CreateDocumentWithTemplate.js | 82 ++---- .../customRoute/v1/routes/createContact.js | 240 ++++++++---------- .../customRoute/v1/routes/createDocument.js | 100 ++++---- .../customRoute/v1/routes/createTemplate.js | 70 ++--- .../cloud/customRoute/v1/routes/getWebhook.js | 1 + .../customRoute/v1/routes/saveWebhook.js | 2 +- .../customRoute/v1/routes/updateDocument.js | 4 +- .../customRoute/v1/routes/updateTemplate.js | 2 +- .../cloud/parsefunction/DocumentAftersave.js | 29 ++- .../cloud/parsefunction/TemplateAfterSave.js | 15 +- 10 files changed, 240 insertions(+), 305 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 6efa6f84d..3ae07bac3 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -1,17 +1,9 @@ const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocumentWithTemplate(request, response) { - const signers = request.body.signers; - const folderId = request.body.folderId; + const signers = request.body.Signers; + const folderId = request.body.FolderId; const templateId = request.params.template_id; - const url = request?.get('host'); - let protocol = 'https://' + url; - if (request.hostname === 'localhost') { - // console.log('Running in development environment'); - protocol = 'http://' + url; - } else { - // console.log('Running in production environment'); - protocol = 'https://' + url; - } + const url = process.env.SERVER_URL; try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -48,52 +40,31 @@ export default async function createDocumentWithTemplate(request, response) { if (template?.Description) { object.set('Description', template.Description); } - let templateSigner = template?.Signers ? template?.Signers : []; - if (signers && signers.length > 0) { - let parseSigners; - if (base64File) { - parseSigners = signers; - } else { - parseSigners = JSON.parse(signers); - } - let createContactUrl = protocol + '/v1/createcontact'; - - let contact = []; - for (const obj of parseSigners) { - const body = { - name: obj?.name || '', - email: obj?.email || '', - phone: obj?.phone || '', - }; - try { - const res = await axios.post(createContactUrl, body, { - headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, - }); - // console.log('res ', res.data); - contact.push({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: res.data?.objectId, - }); - } catch (err) { - // console.log('err ', err.response); - if (err?.response?.data?.objectId) { - contact.push({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: err.response.data?.objectId, - }); - } - } - } - object.set('Signers', [...templateSigner, ...contact]); - } else { - object.set('Signers', templateSigner); + if (template?.Signers) { + object.set('Signers', template?.Signers); } - object.set('URL', template.URL); object.set('CreatedBy', template.CreatedBy); object.set('ExtUserPtr', template.ExtUserPtr); + if (signers) { + const placeholders = template?.Placeholders?.map(placeholder => { + let matchingSigner = signers.find(y => y.Role === placeholder.Role); + if (matchingSigner) { + return { + ...placeholder, + email: matchingSigner.Email, + signerObjId: '', + signerPtr: {}, + }; + } else { + return { + ...placeholder, + }; + } + }); + console.log('placeholders ', placeholders); + object.set('Placeholders', placeholders); + } if (folderId) { object.set('Folder', folderPtr); } @@ -104,10 +75,7 @@ export default async function createDocumentWithTemplate(request, response) { newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); - return response.json({ - objectId: res.id, - url: protocol + '/load/signmicroapp/placeholdersign/' + res.id, - }); + return response.json({ objectId: res.id, url: url }); } else { return response.status(400).json({ error: 'Please provide signers properly!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index ba6ffa503..59aa21aa2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -2,9 +2,9 @@ import axios from 'axios'; export default async function createContact(request, response) { const serverUrl = process.env.SERVER_URL; const appId = process.env.APP_ID; - const name = request.body.name; - const phone = request.body.phone; - const email = request.body.email; + const name = request.body.Name; + const phone = request.body.Phone; + const email = request.body.Email; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -16,143 +16,127 @@ export default async function createContact(request, response) { // Valid Token then proceed request const userPtr = token.get('userId'); try { - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.equalTo('Email', email); - contactbook.equalTo('CreatedBy', userPtr); + const Tenant = new Parse.Query('partners_Tenant'); + Tenant.equalTo('UserId', userPtr); + const tenantRes = await Tenant.first({ useMasterKey: true }); - const userExists = await contactbook.first({ useMasterKey: true }); - - if (userExists) { - return response - .status(401) - .json({ error: 'Contact already exists!', objectId: userExists.id }); - } else { - try { - const Tenant = new Parse.Query('partners_Tenant'); - Tenant.equalTo('UserId', userPtr); - const tenantRes = await Tenant.first({ useMasterKey: true }); - - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', name); - contactQuery.set('Phone', phone); - contactQuery.set('Email', email); - contactQuery.set('UserRole', 'contracts_Guest'); - if (tenantRes && tenantRes.id) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantRes.id, - }); - } - try { - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('phone', phone); - _user.set('password', phone); + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + contactQuery.set('Phone', phone); + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + if (tenantRes && tenantRes.id) { + contactQuery.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: tenantRes.id, + }); + } + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', name); + _user.set('username', email); + _user.set('email', email); + _user.set('phone', phone); + _user.set('password', phone); - const user = await _user.save(); - if (user) { - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: user.id, - }; - await axios.post(roleurl, body, { headers: headers }); - const currentUser = userPtr; - contactQuery.set('CreatedBy', currentUser); - contactQuery.set('UserId', user); + const user = await _user.save(); + if (user) { + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: user.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = userPtr; + contactQuery.set('CreatedBy', currentUser); + contactQuery.set('UserId', user); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); - acl.setReadAccess(user.id, true); - acl.setWriteAccess(user.id, true); - contactQuery.setACL(acl); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } catch (err) { - console.log('err in', err); - if (err.code === 202) { - const params = { email: email }; - const userRes = await Parse.Cloud.run('getUserId', params); - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: userRes.id, - }; - await axios.post(roleurl, body, { headers: headers }); - contactQuery.set('CreatedBy', userPtr); - contactQuery.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userRes.id, - }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); - acl.setReadAccess(userRes.id, true); - acl.setWriteAccess(userRes.id, true); + const contactRes = await contactQuery.save(); + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } + } catch (err) { + console.log('err in', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: userRes.id, + }; + await axios.post(roleurl, body, { headers: headers }); + contactQuery.set('CreatedBy', userPtr); + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); - contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - if (contactRes) { - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } else { - if (err.code === 137) { - return response.status(401).json({ error: 'Contact already exists!' }); - } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } + contactQuery.setACL(acl); + const contactRes = await contactQuery.save(); + if (contactRes) { + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); } - } catch (err) { - console.log('err ', err); + } else { if (err.code === 137) { return response.status(401).json({ error: 'Contact already exists!' }); - } else { - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); } + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } } } catch (err) { - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); + console.log('err ', err); + if (err.code === 137) { + return response.status(401).json({ error: 'Contact already exists!' }); + } else { + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); + } } } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index e4c7a4a7f..c34601520 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -1,26 +1,16 @@ // import batchQuery from './batchquery.js'; -import axios from 'axios'; - // const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocument(request, response) { - const name = request.body.title; - const note = request.body.note; - const description = request.body.description; - const signers = request.body.signers; - const folderId = request.body.folderId; - const base64File = request.body.file; + const name = request.body.Title; + const note = request.body.Note; + const description = request.body.Description; + const signers = request.body.Signers; + const folderId = request.body.FolderId; + const base64File = request.body.File; const url = request?.get('host'); const fileData = request.files?.[0] ? request.files[0].buffer : null; // console.log('fileData ', fileData); - let protocol = 'https://' + url; - if (request.hostname === 'localhost') { - // console.log('Running in development environment'); - protocol = 'http://' + url; - } else { - // console.log('Running in production environment'); - protocol = 'https://' + url; - } try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -31,7 +21,7 @@ export default async function createDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - if (signers && signers.length > 0) { + if (signers) { const userPtr = token.get('userId'); let fileUrl; if (request.files?.[0]) { @@ -73,44 +63,56 @@ export default async function createDocument(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); - if (signers && signers.length > 0) { + if (signers) { let parseSigners; if (base64File) { parseSigners = signers; } else { parseSigners = JSON.parse(signers); } - let createContactUrl = protocol + '/v1/createcontact'; - let contact = []; - for (const obj of parseSigners) { - const body = { - name: obj?.name || '', - email: obj?.email || '', - phone: obj?.phone || '', - }; - try { - const res = await axios.post(createContactUrl, body, { - headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, - }); - // console.log('res ', res.data); - contact.push({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: res.data?.objectId, - }); - } catch (err) { - // console.log('err ', err.response); - if (err?.response?.data?.objectId) { - contact.push({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: err.response.data?.objectId, - }); - } - } - } - object.set('Signers', contact); + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.equalTo('UserId', userPtr); + contactbook.notEqualTo('IsDeleted', true); + contactbook.containedIn('Email', parseSigners); + const contactbookRes = await contactbook.find({ useMasterKey: true }); + // console.log('contactbookRes ', contactbookRes); + const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); + // console.log('userPtr ', userPtr); + // const newContacts = parseSigners + // .filter(x => !parseContactbookRes.some(y => y.Email === x)) + // .map(email => ({ + // method: 'POST', + // path: '/app/classes/contracts_Contactbook', + // body: { + // Email: email, + // CreatedBy: { __type: 'Pointer', className: '_User', objectId: userPtr.id }, + // UserId: { __type: 'Pointer', className: '_User', objectId: userPtr.id }, + // Role: 'contracts_Guest', + // IsDeleted: false, + // ACL: { + // [userPtr.id]: { read: true, write: true }, + // }, + // }, + // })); + // console.log('newContacts', newContacts); + let contactSigners = parseContactbookRes?.map(x => ({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: x.objectId, + })); + // if (newContacts.length > 0) { + // const batchRes = await batchQuery(newContacts); + // const contacts = batchRes?.map(x => ({ + // __type: 'Pointer', + // className: 'contracts_Contactbook', + // objectId: x.success.objectId, + // })); + // contactSigners = [...contactSigners, ...contacts]; + // } + // console.log('contactsigners', contactSigners); + + object.set('Signers', contactSigners); } if (folderId) { object.set('Folder', folderPtr); @@ -124,7 +126,7 @@ export default async function createDocument(request, response) { const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, - url: protocol + '/load/signmicroapp/placeholdersign/' + res.id, + url: 'https://' + url + '/load/signmicroapp/placeholdersign/' + res.id, }); } else { return response.status(400).json({ error: 'Please provide signers!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 4879d7988..ecd48381a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -1,21 +1,13 @@ const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createTemplate(request, response) { - const name = request.body?.title; - const note = request.body?.note; - const description = request.body?.description; - const signers = request.body?.signers; - const folderId = request.body?.folderId; + const name = request.body?.Title; + const note = request.body?.Note; + const description = request.body?.Description; + const signers = request.body?.Signers; + const folderId = request.body?.FolderId; const url = request?.get('host'); - const base64File = request.body.file; + const base64File = request.body.File; const fileData = request.files?.[0] ? request.files[0].buffer : null; - let protocol = 'https://' + url; - if (request.hostname === 'localhost') { - // console.log('Running in development environment'); - protocol = 'http://' + url; - } else { - // console.log('Running in production environment'); - protocol = 'https://' + url; - } try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -60,44 +52,30 @@ export default async function createTemplate(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); - if (signers && signers.length > 0) { + if (signers) { let parseSigners; if (base64File) { parseSigners = signers; } else { parseSigners = JSON.parse(signers); } - let createContactUrl = protocol + '/v1/createcontact'; - let contact = []; - for (const obj of parseSigners) { - const body = { - name: obj?.name || '', - email: obj?.email || '', - phone: obj?.phone || '', - }; - try { - const res = await axios.post(createContactUrl, body, { - headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, - }); - // console.log('res ', res.data); - contact.push({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: res.data?.objectId, - }); - } catch (err) { - // console.log('err ', err.response); - if (err?.response?.data?.objectId) { - contact.push({ - __type: 'Pointer', - className: 'contracts_Contactbook', - objectId: err.response.data?.objectId, - }); - } - } - } - object.set('Signers', contact); + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.containedIn('Email', parseSigners); + contactbook.equalTo('UserId', userPtr); + contactbook.notEqualTo('IsDeleted', true); + const contactbookRes = await contactbook.find({ useMasterKey: true }); + // console.log('contactbookRes ', contactbookRes); + const parseContactbookRes = JSON.parse(JSON.stringify(contactbookRes)); + + object.set( + 'Signers', + parseContactbookRes?.map(x => ({ + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: x.objectId, + })) + ); } if (folderId) { object.set('Folder', folderPtr); @@ -111,7 +89,7 @@ export default async function createTemplate(request, response) { const res = await object.save(null, { useMasterKey: true }); return response.json({ objectId: res.id, - url: protocol + '/load/signmicroapp/template/' + res.id, + url: 'https://' + url + '/load/signmicroapp/template/' + res.id, }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js index c022d0d38..9b55c3cf0 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -1,4 +1,5 @@ export default async function getWebhook(request, response) { + const Url = request.body.Url; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js index 675fe6e90..3c2051a31 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -1,5 +1,5 @@ export default async function saveWebhook(request, response) { - const Url = request.body.url; + const Url = request.body.Url; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index c6ecc0c2c..2f0b76c53 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -8,8 +8,8 @@ export default async function updateDocument(request, response) { tokenQuery.equalTo('token', reqToken); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { - // Valid Token then proceed request - const allowedKeys = ['name', 'note', 'description']; + // Valid Token then proceed request + const allowedKeys = ['Name', 'Note', 'Description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 791844a8b..d3445bcf5 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -9,7 +9,7 @@ export default async function updateTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const allowedKeys = ['name', 'note', 'description']; + const allowedKeys = ['Name', 'Note', 'Description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js index dc26a3e09..701ebd608 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js @@ -4,11 +4,20 @@ async function DocumentAftersave(request) { console.log('new entry is insert in contracts_Document'); const createdAt = request.object.get('createdAt'); const Folder = request.object.get('Type'); + // console.log("createdAt") + // console.log(createdAt) + // console.log("Folder") + // console.log(Folder) + // console.log("before If condition") if (createdAt && Folder === undefined) { // console.log("IN If condition") const TimeToCompleteDays = request.object.get('TimeToCompleteDays'); const ExpiryDate = new Date(createdAt); + // console.log("ExpiryDate") + // console.log(ExpiryDate) ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays); + // console.log("ExpiryDate date after update") + // console.log(ExpiryDate) const documentQuery = new Parse.Query('contracts_Document'); const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true }); updateQuery.set('ExpiryDate', ExpiryDate); @@ -28,6 +37,8 @@ async function DocumentAftersave(request) { } const signers = request.object.get('Signers'); + // console.log("Signers") + // console.log(signers.length) // update acl of New Document If There are signers present in array if (signers && signers.length > 0) { await updateAclDoc(request.object.id); @@ -37,7 +48,7 @@ async function DocumentAftersave(request) { } } } else { - if (request?.user) { + if (request.user) { const signers = request.object.get('Signers'); if (signers && signers.length > 0) { await updateAclDoc(request.object.id); @@ -58,7 +69,6 @@ async function DocumentAftersave(request) { // console.log(objId) const Query = new Parse.Query('contracts_Document'); Query.include('Signers'); - Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -81,10 +91,9 @@ async function DocumentAftersave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - if (res?.CreatedBy) { - newACL.setReadAccess(res?.CreatedBy?.objectId, true); - newACL.setWriteAccess(res?.CreatedBy?.objectId, true); - } + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); + UsersPtr.forEach(x => { newACL.setReadAccess(x.objectId, true); newACL.setWriteAccess(x.objectId, true); @@ -95,9 +104,9 @@ async function DocumentAftersave(request) { } async function updateSelfDoc(objId) { + // console.log("In side updateSelfDoc func") // console.log(objId) const Query = new Parse.Query('contracts_Document'); - Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -105,10 +114,8 @@ async function DocumentAftersave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - if (res?.CreatedBy) { - newACL.setReadAccess(res?.CreatedBy?.objectId, true); - newACL.setWriteAccess(res?.CreatedBy?.objectId, true); - } + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); updateACL.setACL(newACL); updateACL.save(null, { useMasterKey: true }); } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index 96389e6cc..556cf1c39 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -34,7 +34,6 @@ export default async function TemplateAfterSave(request) { // console.log(objId) const Query = new Parse.Query('contracts_Template'); Query.include('Signers'); - Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -57,10 +56,9 @@ export default async function TemplateAfterSave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - if (res?.CreatedBy) { - newACL.setReadAccess(res?.CreatedBy?.objectId, true); - newACL.setWriteAccess(res?.CreatedBy?.objectId, true); - } + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); + UsersPtr.forEach(x => { newACL.setReadAccess(x.objectId, true); newACL.setWriteAccess(x.objectId, true); @@ -74,7 +72,6 @@ export default async function TemplateAfterSave(request) { // console.log("Inside updateSelfDoc func") const Query = new Parse.Query('contracts_Template'); - Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); // const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -82,10 +79,8 @@ export default async function TemplateAfterSave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - if (res?.CreatedBy) { - newACL.setReadAccess(res?.CreatedBy?.objectId, true); - newACL.setWriteAccess(res?.CreatedBy?.objectId, true); - } + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); updateACL.setACL(newACL); updateACL.save(null, { useMasterKey: true }); } From 8ce31d3d80bf623cbbdb783a77035754164317b2 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 25 Jan 2024 19:16:09 +0530 Subject: [PATCH 34/73] fix: get host method in API --- .../v1/routes/CreateDocumentWithTemplate.js | 12 +++--------- .../cloud/customRoute/v1/routes/createDocument.js | 12 +++--------- .../cloud/customRoute/v1/routes/createTemplate.js | 12 +++--------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 6efa6f84d..0f5857aa1 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -3,15 +3,9 @@ export default async function createDocumentWithTemplate(request, response) { const signers = request.body.signers; const folderId = request.body.folderId; const templateId = request.params.template_id; - const url = request?.get('host'); - let protocol = 'https://' + url; - if (request.hostname === 'localhost') { - // console.log('Running in development environment'); - protocol = 'http://' + url; - } else { - // console.log('Running in production environment'); - protocol = 'https://' + url; - } + const url = new URL(process.env.SERVER_URL); + let protocol = url.origin; + try { const reqToken = request.headers['x-api-token']; if (!reqToken) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index e4c7a4a7f..8b93a72d2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -10,17 +10,11 @@ export default async function createDocument(request, response) { const signers = request.body.signers; const folderId = request.body.folderId; const base64File = request.body.file; - const url = request?.get('host'); const fileData = request.files?.[0] ? request.files[0].buffer : null; // console.log('fileData ', fileData); - let protocol = 'https://' + url; - if (request.hostname === 'localhost') { - // console.log('Running in development environment'); - protocol = 'http://' + url; - } else { - // console.log('Running in production environment'); - protocol = 'https://' + url; - } + const url = new URL(process.env.SERVER_URL); + let protocol = url.origin; + try { const reqToken = request.headers['x-api-token']; if (!reqToken) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 4879d7988..36014c48f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -5,17 +5,11 @@ export default async function createTemplate(request, response) { const description = request.body?.description; const signers = request.body?.signers; const folderId = request.body?.folderId; - const url = request?.get('host'); const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; - let protocol = 'https://' + url; - if (request.hostname === 'localhost') { - // console.log('Running in development environment'); - protocol = 'http://' + url; - } else { - // console.log('Running in production environment'); - protocol = 'https://' + url; - } + const url = new URL(process.env.SERVER_URL); + let protocol = url.origin; + try { const reqToken = request.headers['x-api-token']; if (!reqToken) { From 95cc15ec4c6dcdfa1a6ab0b90c3851ae35b4b0e8 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 25 Jan 2024 19:58:16 +0530 Subject: [PATCH 35/73] fix: all API body parameter must be in lowercase --- .../customRoute/v1/routes/createContact.js | 240 ++++++++++-------- .../cloud/customRoute/v1/routes/getWebhook.js | 1 - .../customRoute/v1/routes/saveWebhook.js | 2 +- .../customRoute/v1/routes/updateDocument.js | 4 +- .../customRoute/v1/routes/updateTemplate.js | 2 +- .../cloud/parsefunction/DocumentAftersave.js | 29 +-- .../cloud/parsefunction/TemplateAfterSave.js | 18 +- 7 files changed, 155 insertions(+), 141 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index 59aa21aa2..ba6ffa503 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -2,9 +2,9 @@ import axios from 'axios'; export default async function createContact(request, response) { const serverUrl = process.env.SERVER_URL; const appId = process.env.APP_ID; - const name = request.body.Name; - const phone = request.body.Phone; - const email = request.body.Email; + const name = request.body.name; + const phone = request.body.phone; + const email = request.body.email; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); @@ -16,127 +16,143 @@ export default async function createContact(request, response) { // Valid Token then proceed request const userPtr = token.get('userId'); try { - const Tenant = new Parse.Query('partners_Tenant'); - Tenant.equalTo('UserId', userPtr); - const tenantRes = await Tenant.first({ useMasterKey: true }); + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.equalTo('Email', email); + contactbook.equalTo('CreatedBy', userPtr); - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', name); - contactQuery.set('Phone', phone); - contactQuery.set('Email', email); - contactQuery.set('UserRole', 'contracts_Guest'); - if (tenantRes && tenantRes.id) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantRes.id, - }); - } - try { - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('phone', phone); - _user.set('password', phone); + const userExists = await contactbook.first({ useMasterKey: true }); - const user = await _user.save(); - if (user) { - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: user.id, - }; - await axios.post(roleurl, body, { headers: headers }); - const currentUser = userPtr; - contactQuery.set('CreatedBy', currentUser); - contactQuery.set('UserId', user); + if (userExists) { + return response + .status(401) + .json({ error: 'Contact already exists!', objectId: userExists.id }); + } else { + try { + const Tenant = new Parse.Query('partners_Tenant'); + Tenant.equalTo('UserId', userPtr); + const tenantRes = await Tenant.first({ useMasterKey: true }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); - acl.setReadAccess(user.id, true); - acl.setWriteAccess(user.id, true); - contactQuery.setACL(acl); + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + contactQuery.set('Phone', phone); + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + if (tenantRes && tenantRes.id) { + contactQuery.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: tenantRes.id, + }); + } + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', name); + _user.set('username', email); + _user.set('email', email); + _user.set('phone', phone); + _user.set('password', phone); - const contactRes = await contactQuery.save(); - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } catch (err) { - console.log('err in', err); - if (err.code === 202) { - const params = { email: email }; - const userRes = await Parse.Cloud.run('getUserId', params); - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: userRes.id, - }; - await axios.post(roleurl, body, { headers: headers }); - contactQuery.set('CreatedBy', userPtr); - contactQuery.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: userRes.id, - }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); - acl.setReadAccess(userRes.id, true); - acl.setWriteAccess(userRes.id, true); + const user = await _user.save(); + if (user) { + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: user.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = userPtr; + contactQuery.set('CreatedBy', currentUser); + contactQuery.set('UserId', user); - contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - if (contactRes) { - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + contactQuery.setACL(acl); + + const contactRes = await contactQuery.save(); + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } + } catch (err) { + console.log('err in', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: userRes.id, + }; + await axios.post(roleurl, body, { headers: headers }); + contactQuery.set('CreatedBy', userPtr); + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.id, true); + acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + + contactQuery.setACL(acl); + const contactRes = await contactQuery.save(); + if (contactRes) { + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } + } else { + if (err.code === 137) { + return response.status(401).json({ error: 'Contact already exists!' }); + } + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); + } } - } else { + } catch (err) { + console.log('err ', err); if (err.code === 137) { return response.status(401).json({ error: 'Contact already exists!' }); + } else { + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); } } } catch (err) { - console.log('err ', err); - if (err.code === 137) { - return response.status(401).json({ error: 'Contact already exists!' }); - } else { - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js index 9b55c3cf0..c022d0d38 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -1,5 +1,4 @@ export default async function getWebhook(request, response) { - const Url = request.body.Url; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js index 3c2051a31..675fe6e90 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -1,5 +1,5 @@ export default async function saveWebhook(request, response) { - const Url = request.body.Url; + const Url = request.body.url; const reqToken = request.headers['x-api-token']; if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index 2253afca8..30c9b9d41 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -8,8 +8,8 @@ export default async function updateDocument(request, response) { tokenQuery.equalTo('token', reqToken); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { - // Valid Token then proceed request - const allowedKeys = ['Name', 'Note', 'Description']; + // Valid Token then proceed request + const allowedKeys = ['name', 'note', 'description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index b9cd47949..38dac8e6d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -9,7 +9,7 @@ export default async function updateTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const allowedKeys = ['Name', 'Note', 'Description']; + const allowedKeys = ['name', 'note', 'description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; if (isValid) { diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js index 701ebd608..dc26a3e09 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js @@ -4,20 +4,11 @@ async function DocumentAftersave(request) { console.log('new entry is insert in contracts_Document'); const createdAt = request.object.get('createdAt'); const Folder = request.object.get('Type'); - // console.log("createdAt") - // console.log(createdAt) - // console.log("Folder") - // console.log(Folder) - // console.log("before If condition") if (createdAt && Folder === undefined) { // console.log("IN If condition") const TimeToCompleteDays = request.object.get('TimeToCompleteDays'); const ExpiryDate = new Date(createdAt); - // console.log("ExpiryDate") - // console.log(ExpiryDate) ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays); - // console.log("ExpiryDate date after update") - // console.log(ExpiryDate) const documentQuery = new Parse.Query('contracts_Document'); const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true }); updateQuery.set('ExpiryDate', ExpiryDate); @@ -37,8 +28,6 @@ async function DocumentAftersave(request) { } const signers = request.object.get('Signers'); - // console.log("Signers") - // console.log(signers.length) // update acl of New Document If There are signers present in array if (signers && signers.length > 0) { await updateAclDoc(request.object.id); @@ -48,7 +37,7 @@ async function DocumentAftersave(request) { } } } else { - if (request.user) { + if (request?.user) { const signers = request.object.get('Signers'); if (signers && signers.length > 0) { await updateAclDoc(request.object.id); @@ -69,6 +58,7 @@ async function DocumentAftersave(request) { // console.log(objId) const Query = new Parse.Query('contracts_Document'); Query.include('Signers'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -91,9 +81,10 @@ async function DocumentAftersave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); - + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } UsersPtr.forEach(x => { newACL.setReadAccess(x.objectId, true); newACL.setWriteAccess(x.objectId, true); @@ -104,9 +95,9 @@ async function DocumentAftersave(request) { } async function updateSelfDoc(objId) { - // console.log("In side updateSelfDoc func") // console.log(objId) const Query = new Parse.Query('contracts_Document'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -114,8 +105,10 @@ async function DocumentAftersave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } updateACL.setACL(newACL); updateACL.save(null, { useMasterKey: true }); } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index 556cf1c39..a1d8e7417 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -8,7 +8,7 @@ export default async function TemplateAfterSave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - if (request?.object?.id && request.user) { + if (request?.object?.id && request?.user) { await updateSelfDoc(request.object.id); } } @@ -34,6 +34,7 @@ export default async function TemplateAfterSave(request) { // console.log(objId) const Query = new Parse.Query('contracts_Template'); Query.include('Signers'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); const res = JSON.parse(JSON.stringify(updateACL)); // console.log("res"); @@ -56,8 +57,10 @@ export default async function TemplateAfterSave(request) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } UsersPtr.forEach(x => { newACL.setReadAccess(x.objectId, true); @@ -72,15 +75,18 @@ export default async function TemplateAfterSave(request) { // console.log("Inside updateSelfDoc func") const Query = new Parse.Query('contracts_Template'); + Query.include('CreatedBy'); const updateACL = await Query.get(objId, { useMasterKey: true }); - // const res = JSON.parse(JSON.stringify(updateACL)); + 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); - newACL.setReadAccess(request.user, true); - newACL.setWriteAccess(request.user, true); + if (res?.CreatedBy) { + newACL.setReadAccess(res?.CreatedBy?.objectId, true); + newACL.setWriteAccess(res?.CreatedBy?.objectId, true); + } updateACL.setACL(newACL); updateACL.save(null, { useMasterKey: true }); } From 17cb4479cbc17f6cd5974f7e637fe3e4dfb32afa Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 25 Jan 2024 22:49:20 +0530 Subject: [PATCH 36/73] fix: createdocument from template --- .../v1/routes/CreateDocumentWithTemplate.js | 55 ++++++++++++------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 2ed415c83..f83608e99 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -1,4 +1,5 @@ -const randomId = () => Math.floor(1000 + Math.random() * 9000); +import axios from 'axios'; + export default async function createDocumentWithTemplate(request, response) { const signers = request.body.signers; const folderId = request.body.folderId; @@ -27,6 +28,7 @@ export default async function createDocumentWithTemplate(request, response) { let updateSigners = template?.Placeholders?.every(y => signers?.some(x => x.Role === y.Role) ); + if (isValid && updateSigners) { const folderPtr = { __type: 'Pointer', @@ -44,47 +46,62 @@ export default async function createDocumentWithTemplate(request, response) { } let templateSigner = template?.Signers ? template?.Signers : []; if (signers && signers.length > 0) { - let parseSigners; - if (base64File) { - parseSigners = signers; - } else { - parseSigners = JSON.parse(signers); - } + let parseSigners = [...signers]; let createContactUrl = protocol + '/v1/createcontact'; let contact = []; for (const obj of parseSigners) { const body = { - name: obj?.name || '', - email: obj?.email || '', - phone: obj?.phone || '', + name: obj?.Name || '', + email: obj?.Email || '', + phone: obj?.Phone || '', }; try { const res = await axios.post(createContactUrl, body, { headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, }); - // console.log('res ', res.data); - contact.push({ + const contactPtr = { __type: 'Pointer', className: 'contracts_Contactbook', objectId: res.data?.objectId, - }); + }; + const newObj = { ...obj, contactPtr: contactPtr }; + contact.push(newObj); } catch (err) { - // console.log('err ', err.response); + console.log('err ', err); if (err?.response?.data?.objectId) { - contact.push({ + const contactPtr = { __type: 'Pointer', className: 'contracts_Contactbook', objectId: err.response.data?.objectId, - }); + }; + const newObj = { ...obj, contactPtr: contactPtr }; + contact.push(newObj); } } } - object.set('Signers', [...templateSigner, ...contact]); + const contactPtrs = contact.map(x => x.contactPtr); + object.set('Signers', [...templateSigner, ...contactPtrs]); + + let updatedPlaceholder = template?.Placeholders?.map(x => { + let matchingSigner = contact.find(y => x.Role && x.Role === y.Role); + + if (matchingSigner) { + return { + ...x, + signerObjId: matchingSigner?.contactPtr?.objectId, + signerPtr: matchingSigner?.contactPtr, + }; + } else { + return { + ...x, + }; + } + }); + object.set('Placeholders', updatedPlaceholder); } else { object.set('Signers', templateSigner); } - object.set('URL', template.URL); object.set('CreatedBy', template.CreatedBy); object.set('ExtUserPtr', template.ExtUserPtr); @@ -121,4 +138,4 @@ export default async function createDocumentWithTemplate(request, response) { } return response.status(400).json({ error: 'Something went wrong!' }); } -} \ No newline at end of file +} From fee3d8f672d080f3fe60d416ced7633d4e12bd08 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Sun, 28 Jan 2024 16:34:08 +0530 Subject: [PATCH 37/73] fix: createdocument, createtemplate and createdocumentwithtemplate APIs not working --- apps/OpenSignServer/Utils.js | 4 ++++ .../v1/routes/CreateDocumentWithTemplate.js | 21 ++++++++++++------- .../customRoute/v1/routes/createDocument.js | 6 +++--- .../customRoute/v1/routes/createTemplate.js | 7 ++++--- 4 files changed, 24 insertions(+), 14 deletions(-) create mode 100644 apps/OpenSignServer/Utils.js diff --git a/apps/OpenSignServer/Utils.js b/apps/OpenSignServer/Utils.js new file mode 100644 index 000000000..884e8fdad --- /dev/null +++ b/apps/OpenSignServer/Utils.js @@ -0,0 +1,4 @@ +export function customAPIurl() { + const url = new URL(process.env.SERVER_URL); + return url.pathname === '/api/app' ? url.origin + '/api' : url.origin; +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index f83608e99..add07d2e7 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -1,11 +1,11 @@ import axios from 'axios'; +import { customAPIurl } from '../../../../Utils.js'; export default async function createDocumentWithTemplate(request, response) { const signers = request.body.signers; const folderId = request.body.folderId; const templateId = request.params.template_id; - const url = new URL(process.env.SERVER_URL); - let protocol = url.origin; + const protocol = customAPIurl(); try { const reqToken = request.headers['x-api-token']; @@ -24,11 +24,14 @@ export default async function createDocumentWithTemplate(request, response) { if (templateRes) { const template = JSON.parse(JSON.stringify(templateRes)); if (template?.Placeholders?.length > 0) { - let isValid = template?.Placeholders?.length <= signers?.length; - let updateSigners = template?.Placeholders?.every(y => - signers?.some(x => x.Role === y.Role) - ); - + const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId); + const isValid = + signers.length >= emptyplaceholder.length && + signers.length <= template?.Placeholders?.length; + const placeholder = + signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder; + const updateSigners = placeholder.every(y => signers?.some(x => x.Role === y.Role)); + // console.log('isValid ', isValid); if (isValid && updateSigners) { const folderPtr = { __type: 'Pointer', @@ -68,7 +71,7 @@ export default async function createDocumentWithTemplate(request, response) { const newObj = { ...obj, contactPtr: contactPtr }; contact.push(newObj); } catch (err) { - console.log('err ', err); + // console.log('err ', err); if (err?.response?.data?.objectId) { const contactPtr = { __type: 'Pointer', @@ -77,6 +80,8 @@ export default async function createDocumentWithTemplate(request, response) { }; const newObj = { ...obj, contactPtr: contactPtr }; contact.push(newObj); + } else { + console.log('err ', err); } } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 78c0549ec..0235302d7 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import { customAPIurl } from '../../../../Utils.js'; // const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocument(request, response) { @@ -10,8 +11,7 @@ export default async function createDocument(request, response) { const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; // console.log('fileData ', fileData); - const url = new URL(process.env.SERVER_URL); - let protocol = url.origin; + const protocol = customAPIurl(); try { const reqToken = request.headers['x-api-token']; @@ -128,4 +128,4 @@ export default async function createDocument(request, response) { console.log('err ', err); return response.status(400).json({ error: 'Something went wrong!' }); } -} \ No newline at end of file +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index cfc910e0e..5d8e4fb14 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -1,3 +1,5 @@ +import { customAPIurl } from '../../../../Utils.js'; + const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createTemplate(request, response) { const name = request.body?.title; @@ -7,8 +9,7 @@ export default async function createTemplate(request, response) { const folderId = request.body?.folderId; const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; - const url = new URL(process.env.SERVER_URL); - let protocol = url.origin; + const protocol = customAPIurl(); try { const reqToken = request.headers['x-api-token']; @@ -114,4 +115,4 @@ export default async function createTemplate(request, response) { console.log('err ', err); return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } -} \ No newline at end of file +} From 2d7571af5ae8b22a2b5ea9e0561184ec5f1d6ee1 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 29 Jan 2024 15:04:07 +0530 Subject: [PATCH 38/73] fix: change response of createdocumentwithtemplate API for signing document --- .../v1/routes/CreateDocumentWithTemplate.js | 106 +++++++++++++++--- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index add07d2e7..dacc083e7 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -6,7 +6,7 @@ export default async function createDocumentWithTemplate(request, response) { const folderId = request.body.folderId; const templateId = request.params.template_id; const protocol = customAPIurl(); - + const baseUrl = new URL(process.env.SERVER_URL); try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -19,8 +19,9 @@ export default async function createDocumentWithTemplate(request, response) { // Valid Token then proceed request const userPtr = token.get('userId'); - const templateQyuery = new Parse.Query('contracts_Template'); - const templateRes = await templateQyuery.get(templateId, { useMasterKey: true }); + const templateQuery = new Parse.Query('contracts_Template'); + templateQuery.include('ExtUserPtr'); + const templateRes = await templateQuery.get(templateId, { useMasterKey: true }); if (templateRes) { const template = JSON.parse(JSON.stringify(templateRes)); if (template?.Placeholders?.length > 0) { @@ -30,7 +31,7 @@ export default async function createDocumentWithTemplate(request, response) { signers.length <= template?.Placeholders?.length; const placeholder = signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder; - const updateSigners = placeholder.every(y => signers?.some(x => x.Role === y.Role)); + const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role)); // console.log('isValid ', isValid); if (isValid && updateSigners) { const folderPtr = { @@ -48,16 +49,16 @@ export default async function createDocumentWithTemplate(request, response) { object.set('Description', template.Description); } let templateSigner = template?.Signers ? template?.Signers : []; + let contact = []; if (signers && signers.length > 0) { let parseSigners = [...signers]; let createContactUrl = protocol + '/v1/createcontact'; - let contact = []; for (const obj of parseSigners) { const body = { - name: obj?.Name || '', - email: obj?.Email || '', - phone: obj?.Phone || '', + name: obj?.name || '', + email: obj?.email || '', + phone: obj?.phone || '', }; try { const res = await axios.post(createContactUrl, body, { @@ -89,7 +90,7 @@ export default async function createDocumentWithTemplate(request, response) { object.set('Signers', [...templateSigner, ...contactPtrs]); let updatedPlaceholder = template?.Placeholders?.map(x => { - let matchingSigner = contact.find(y => x.Role && x.Role === y.Role); + let matchingSigner = contact.find(y => x.Role && x.Role === y.role); if (matchingSigner) { return { @@ -109,7 +110,11 @@ export default async function createDocumentWithTemplate(request, response) { } object.set('URL', template.URL); object.set('CreatedBy', template.CreatedBy); - object.set('ExtUserPtr', template.ExtUserPtr); + object.set('ExtUserPtr', { + __type: 'Pointer', + className: 'contracts_Users', + objectId: template.ExtUserPtr.objectId, + }); if (folderId) { object.set('Folder', folderPtr); } @@ -120,10 +125,85 @@ export default async function createDocumentWithTemplate(request, response) { newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); - return response.json({ - objectId: res.id, - url: protocol + '/load/signmicroapp/placeholdersign/' + res.id, + + const newDate = new Date(); + newDate.setDate(newDate.getDate() + 15); + const localExpireDate = newDate.toLocaleDateString('en-US', { + day: 'numeric', + month: 'long', + year: 'numeric', }); + let sender = template.ExtUserPtr.Email; + let sendMail; + const serverUrl = process.env.SERVER_URL; + const newServer = serverUrl.replaceAll('/', '%2F'); + const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`; + + for (let i = 0; i < contact.length; i++) { + try { + const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; + let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + + const objectId = contact[i].contactPtr.objectId; + + const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; + let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; + const openSignUrl = 'https://www.opensignlabs.com/contact-us'; + const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : ''; + const themeBGcolor = '#47a3ad'; + let params = { + recipient: contact[i].email, + subject: `${template.ExtUserPtr.Name} has requested you to sign ${template.ExtUserPtr.Name}`, + 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;'> " + + template.ExtUserPtr.Name + + ' has requested you to review and sign <strong> ' + + template.Name + + "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + + sender + + "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + + orgName + + "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>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 " + + 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>', + }; + sendMail = await axios.post(url, params, { headers: headers }); + } catch (error) { + console.log('error', error); + } + } + + if (sendMail.data.result.status === 'success') { + const user = contact.find(x => x.email === template.ExtUserPtr.Email); + if (user && user.email) { + return response.json({ + objectId: res.id, + url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${user.email}/${user.contactPtr.objectId}/${serverParams}`, + message: 'Document sent successfully!', + }); + } else { + return response.json({ + objectId: res.id, + message: 'Document sent successfully!', + }); + } + } } else { return response.status(400).json({ error: 'Please provide signers properly!' }); } From 7a5cdefcfaf410857920cebc2166009484490443 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 31 Jan 2024 13:48:30 +0530 Subject: [PATCH 39/73] fix: document completion webhook not working in selfsign --- apps/OpenSign/src/routes/LoadMf.js | 3 +- .../cloud/parsefunction/pdf/PDF.min.js | 33 +++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/OpenSign/src/routes/LoadMf.js b/apps/OpenSign/src/routes/LoadMf.js index 2f8a43a1f..cdb1cc384 100644 --- a/apps/OpenSign/src/routes/LoadMf.js +++ b/apps/OpenSign/src/routes/LoadMf.js @@ -32,7 +32,8 @@ function RemoteApp({ app }) { width: "100%", overflow: "hidden", borderRadius: 3, - minHeight: "70vh" + height: "100%", + minHeight: "100vh" }} > {RemoteComponent && <RemoteComponent />} diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index ee778c228..9922362e5 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -95,15 +95,20 @@ async function sendCompletedMail(e) { }, }); } -async function sendDoctoWebhook(t) { - var e; +async function sendDoctoWebhook(t, e) { t.data.ExtUserPtr?.Webhook && ((e = { - File: t?.data?.SignedUrl, + File: e || '', Name: t?.data?.Name, - Note: t?.data?.Note, - Description: t?.data?.Description, - Signers: t?.data?.Signers?.map(e => e.Name), + Note: t?.data?.Note || '', + Description: t?.data?.Description || '', + Signers: t?.data?.Signers?.map(e => ({ Name: e.Name, Email: e.Email, Phone: e.Phone })) || [ + { + Name: t?.data?.ExtUserPtr?.Name, + Email: t?.data?.ExtUserPtr?.Email, + Phone: t?.data?.ExtUserPtr?.Phone, + }, + ], Completed: !0, CompletedAt: new Date(), CreatedAt: t?.data?.createdAt, @@ -217,17 +222,17 @@ async function PDF(i, o) { (n.data.Signers && 0 < n.data.Signers.length && y.length !== n.data.Signers.length) || !(t = !0) ); - var v, - P, + var P, + v, x = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`, b = (t - ? ((v = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), + ? ((P = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), (e = - v && 0 < v.length + P && 0 < P.length ? plainAddPlaceholder({ pdfBuffer: e, - reason: 'Digitally signed by Open sign for ' + v?.join(', '), + reason: 'Digitally signed by Open sign for ' + P?.join(', '), location: 'location', signatureLength: 1e4, }) @@ -237,8 +242,8 @@ async function PDF(i, o) { location: 'location', signatureLength: 1e4, })), - (P = await new SignPDF(e, u).signPDF()), - fs.writeFileSync(x, P)) + (v = await new SignPDF(e, u).signPDF()), + fs.writeFileSync(x, v)) : fs.writeFileSync(x, e), await uploadFile(x)); if (b && b.imageUrl) { @@ -265,7 +270,7 @@ async function PDF(i, o) { pdfName: n.data.Name, receiver: n.data.ExtUserPtr.Email, }), - sendDoctoWebhook(n)), + sendDoctoWebhook(n, b.imageUrl)), fs.unlinkSync(x), console.log('New Signed PDF created called: ' + x), 'success' === o.message From 8bbbf9b3d83e57f423870d088613abf4b3ebc2fe Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 1 Feb 2024 16:31:34 +0530 Subject: [PATCH 40/73] feat: add debug pdf page --- .../SignDocuments/package-lock.json | 85 ++++ microfrontends/SignDocuments/package.json | 1 + .../SignDocuments/src/Component/DebugUi.js | 432 ++++++++++++++++++ .../src/Component/component/RenderDebugPdf.js | 83 ++++ microfrontends/SignDocuments/src/Routes.js | 5 +- .../SignDocuments/src/premitives/Alert.js | 37 +- .../src/premitives/GuestLogin.js | 294 ------------ 7 files changed, 635 insertions(+), 302 deletions(-) create mode 100644 microfrontends/SignDocuments/src/Component/DebugUi.js create mode 100644 microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js delete mode 100644 microfrontends/SignDocuments/src/premitives/GuestLogin.js diff --git a/microfrontends/SignDocuments/package-lock.json b/microfrontends/SignDocuments/package-lock.json index 98359a78d..2c4f6bc78 100644 --- a/microfrontends/SignDocuments/package-lock.json +++ b/microfrontends/SignDocuments/package-lock.json @@ -30,6 +30,7 @@ "react-dom": "^18.2.0", "react-draggable": "^4.4.6", "react-helmet": "^6.1.0", + "react-konva": "^18.2.10", "react-pdf": "^7.4.0", "react-rnd": "^10.4.1", "react-router-dom": "^6.16.0", @@ -6442,6 +6443,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-reconciler": { + "version": "0.28.8", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", + "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.7", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz", @@ -12523,6 +12532,17 @@ "set-function-name": "^2.0.1" } }, + "node_modules/its-fine": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.1.1.tgz", + "integrity": "sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, "node_modules/jake": { "version": "10.8.7", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", @@ -14685,6 +14705,26 @@ "node": ">= 8" } }, + "node_modules/konva": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/konva/-/konva-9.3.2.tgz", + "integrity": "sha512-I4CFGVbWKpzgYi1I0pmoHz8iYfmGc/A61yfltzcuBHMFuBwDsR2VnQo4+eFQ1dGyEAmHcdvTumJ871KqkhuGng==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "peer": true + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -17904,6 +17944,36 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-konva": { + "version": "18.2.10", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.10.tgz", + "integrity": "sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "dependencies": { + "@types/react-reconciler": "^0.28.2", + "its-fine": "^1.1.1", + "react-reconciler": "~0.29.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "konva": "^8.0.1 || ^7.2.5 || ^9.0.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -17950,6 +18020,21 @@ "node": ">=6" } }, + "node_modules/react-reconciler": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", + "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", diff --git a/microfrontends/SignDocuments/package.json b/microfrontends/SignDocuments/package.json index 1eae68515..b1b4f8eba 100644 --- a/microfrontends/SignDocuments/package.json +++ b/microfrontends/SignDocuments/package.json @@ -26,6 +26,7 @@ "react-dom": "^18.2.0", "react-draggable": "^4.4.6", "react-helmet": "^6.1.0", + "react-konva": "^18.2.10", "react-pdf": "^7.4.0", "react-rnd": "^10.4.1", "react-router-dom": "^6.16.0", diff --git a/microfrontends/SignDocuments/src/Component/DebugUi.js b/microfrontends/SignDocuments/src/Component/DebugUi.js new file mode 100644 index 000000000..94ff9bdf8 --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/DebugUi.js @@ -0,0 +1,432 @@ +import React, { useEffect, useState, useRef } from "react"; +import RenderAllPdfPage from "./component/renderAllPdfPage"; +import "../css/./signature.css"; +import { pdfNewWidthFun } from "../utils/Utils"; +import "../css/AddUser.css"; +import Title from "./component/Title"; +import ModalUi from "../premitives/ModalUi"; +import RenderDebugPdf from "./component/RenderDebugPdf"; +import { pdfjs } from "react-pdf"; +import Alert from "../premitives/Alert"; + +function processDimensions(x, y, width, height) { + if (width < 0) { + x -= Math.abs(width); + width = Math.abs(width); + } + + if (height < 0) { + y -= Math.abs(height); + height = Math.abs(height); + } + + return { + x: Math.floor(x), + y: Math.floor(y), + width: Math.floor(width), + height: Math.floor(height) + }; +} +const DebugUi = () => { + const divRef = useRef(null); + const isMobile = window.innerWidth < 767; + const [pdf, setPdf] = useState(""); + const [isModal, setIsModal] = useState(true); + const [allPages, setAllPages] = useState(null); + const [pageNumber, setPageNumber] = useState(1); + const [pdfNewWidth, setPdfNewWidth] = useState(); + const [containerWH, setContainerWH] = useState(); + const [pdfOriginalWidth, setPdfOriginalWidth] = useState(); + const [pdfLoadFail, setPdfLoadFail] = useState({ + status: false, + type: "load" + }); + const [pdfDetails, setPdfDetails] = useState({ + name: "", + pdftype: "", + totalPages: "", + currentPage: 1, + x: 0, + y: 0, + base64: "" + }); + const [hoverCoordinates, setHoverCoordinates] = useState({ x: 0, y: 0 }); + const [drawing, setDrawing] = useState(false); + const [pdfDimension, setPdfDimension] = useState({ width: 0, height: 0 }); + const [annotations, setAnnotations] = useState([]); + const [newAnnotation, setNewAnnotation] = useState([]); + const [copied, setCopied] = useState(false); + useEffect(() => { + if (divRef.current) { + const pdfWidth = pdfNewWidthFun(divRef); + setPdfNewWidth(pdfWidth); + setContainerWH({ + width: divRef.current.offsetWidth, + height: divRef.current.offsetHeight + }); + } + }, [divRef.current]); + + useEffect(() => { + if (pdf && pdf.name) { + const fetchPdfMetadata = async () => { + try { + const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL + console.log("pdfDataURL ", pdfDataURL); + const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise; + const pdfType = await inferPdfType(pdfInfo); + setPdfDetails((prevDetails) => ({ + ...prevDetails, + pdftype: pdfType + })); + } catch (error) { + console.error("Error fetching PDF metadata:", error); + } + }; + + fetchPdfMetadata(); + } + }, [pdf]); + + const inferPdfType = async (pdf) => { + try { + const firstPage = await pdf.getPage(1); + const scale = 1; + const { width, height } = firstPage.getViewport({ scale }); + setPdfDimension({ width: width, height: height }); + + // Assuming a standard DPI of 72, you can adjust this value if needed + const dpi = 72; + + const widthInInches = width / dpi; + const heightInInches = height / dpi; + + const isA1 = widthInInches > 23.39 && heightInInches > 16.54; + const isA2 = widthInInches > 16.54 && heightInInches > 11.69; + const isA3 = widthInInches > 11.69 && heightInInches > 8.27; + const isA4 = widthInInches > 8.27 && heightInInches > 5.83; + const isLegal = widthInInches > 8.5 && heightInInches > 14; + const isLetter = widthInInches > 8.5 && heightInInches > 11; + const isLedger = widthInInches > 11 && heightInInches > 17; + + if (isA1) return "A1"; + if (isA2) return "A2"; + if (isA3) return "A3"; + if (isA4) return "A4"; + if (isLegal) return "Legal"; + if (isLetter) return "Letter"; + if (isLedger) return "Ledger"; + + return "Unknown"; + } catch (error) { + console.error("Error getting page dimensions:", error); + return "Unknown"; + } + }; + + const handleSubmit = (e) => { + e.preventDefault(); + setIsModal(false); + setPdfDetails((prevData) => ({ ...prevData, name: pdf?.name })); + }; + + //function for get pdf page details + const pageDetails = async ({ numPages }) => { + const load = { + status: true + }; + setPdfDetails((prevDetails) => ({ ...prevDetails, totalPages: numPages })); + setPdfLoadFail(load); + }; + + const handleMouseMoveDiv = (event) => { + setHoverCoordinates({ + x: event.nativeEvent.offsetX, + y: event.nativeEvent.offsetY + }); + }; + const handleMouseDown = (event) => { + if (newAnnotation.length === 0) { + const { x, y } = event.target.getStage().getPointerPosition(); + setNewAnnotation([{ x, y, width: 0, height: 0, key: "0" }]); + } + }; + + const handleMouseUp = (event) => { + if (newAnnotation.length === 1) { + const sx = newAnnotation[0].x; + const sy = newAnnotation[0].y; + const { x, y } = event.target.getStage().getPointerPosition(); + const result = processDimensions(sx, sy, x - sx, y - sy); + const annotationToAdd = { ...result, key: annotations.length + 1 }; + annotations.push(annotationToAdd); + setNewAnnotation([]); + setAnnotations(annotations); + setPdfDetails((prevDetails) => ({ + ...prevDetails, + x: result.x, + y: result.y + })); + } + }; + + const handleMouseMove = (event) => { + if (newAnnotation.length === 1) { + const sx = newAnnotation[0].x; + const sy = newAnnotation[0].y; + const { x, y } = event.target.getStage().getPointerPosition(); + setNewAnnotation([ + { + x: sx, + y: sy, + width: x - sx, + height: y - sy, + key: "0" + } + ]); + } + }; + + const annotationsToDraw = [...annotations, ...newAnnotation]; + + const handlePageLoadSuccess = (page) => { + setPdfDetails((prevDetails) => ({ + ...prevDetails, + currentPage: page.pageNumber + })); + }; + + const copytoclipboard = (text) => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 1500); // Reset copied state after 1.5 seconds + }; + const handleFileChange = (files) => { + const file = files[0]; + setPdf(file); + + if (file && file.type === "application/pdf") { + const reader = new FileReader(); + + reader.onloadend = () => { + const base64String = reader.result.split(",")[1]; + setPdfDetails((prevdata) => ({ ...prevdata, base64: base64String })); + }; + + reader.readAsDataURL(file); + } + }; + const handleDelete = (key) => { + const updateAnnotations = annotations.filter((x) => x.key !== key); + setAnnotations(updateAnnotations); + }; + return ( + <div> + {copied && <Alert type="success">Copied</Alert>} + <Title title={"Debug Pdf"} /> + {!isModal && ( + <div className="signatureContainer" ref={divRef}> + {/* this component used to render all pdf pages in left side */} + <RenderAllPdfPage + signPdfUrl={pdf} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + pageNumber={pageNumber} + /> + {/* pdf render view */} + <div + style={{ + marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px", + marginRight: !isMobile && pdfOriginalWidth > 500 && "20px" + }} + > + <div data-tut="reactourThird"> + {containerWH && ( + <RenderDebugPdf + pdfUrl={pdf} + pageDetails={pageDetails} + pageNumber={pageNumber} + pdfOriginalWidth={pdfOriginalWidth} + pdfNewWidth={pdfNewWidth} + setPdfLoadFail={setPdfLoadFail} + pdfLoadFail={pdfLoadFail} + handlePageLoadSuccess={handlePageLoadSuccess} + handleMouseMove={handleMouseMove} + handleMouseUp={handleMouseUp} + handleMouseDown={handleMouseDown} + hoverCoordinates={hoverCoordinates} + annotations={annotationsToDraw} + pdfDimension={pdfDimension} + handleMouseMoveDiv={handleMouseMoveDiv} + /> + )} + </div> + </div> + <div style={{ backgroundColor: "white", width: 220 }}> + <div + style={{ + fontSize: 18, + fontWeight: 500, + padding: "10px 12px", + borderBottom: "1px solid grey" + }} + > + PDF details + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Name: {pdfDetails?.name} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Pdf type: {pdfDetails?.pdftype} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Total Pages: {pdfDetails?.totalPages} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Current Page: {pdfDetails?.currentPage} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Base64 : {pdfDetails?.base64.slice(0, 10)}... + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => copytoclipboard(pdfDetails?.base64)} + > + <i className="fa-solid fa-copy"></i> + </span> + </div> + <div + style={{ + fontSize: 18, + fontWeight: 500, + padding: "10px 12px", + borderBottom: "1px solid grey" + }} + > + Last click + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + x co-ordinate: {pdfDetails?.x} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + y co-ordinate: {pdfDetails?.y} + </div> + + <div + style={{ + fontSize: 18, + fontWeight: 500, + padding: "10px 12px", + borderBottom: "1px solid grey", + borderTop: "1px solid grey" + }} + > + Annotation + </div> + <ul + style={{ + listStyle: "none", + padding: 10, + height: 500, + overflowY: "auto", + scrollbarWidth: 5 + }} + > + {annotations.map((coord, index) => ( + <li key={index}> + <span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${ + index + 1 + }:`}</span> + <code + style={{ fontSize: 12, color: "black", cursor: "pointer" }} + > + {` ["x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`} + </code> + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => + copytoclipboard( + `["x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]` + ) + } + > + <i className="fa-solid fa-copy"></i> + </span> + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => handleDelete(coord.key)} + > + <i className="fa-solid fa-trash-can"></i> + </span> + </li> + ))} + </ul> + </div> + </div> + )} + + <ModalUi title={"Select PDF"} isOpen={isModal}> + <form onSubmit={handleSubmit} style={{ margin: "10px" }}> + <input + type="file" + onChange={(e) => handleFileChange(e.target.files)} + style={{ + width: "100%", + border: "1px solid grey", + borderRadius: "4px", + padding: "5px", + fontSize: 12 + }} + accept=".pdf" + required + /> + <div style={{ borderTop: "1px solid grey", margin: "10px 0" }}></div> + <button + style={{ + background: "#32a3ac", + borderRadius: "2px", + boxShadow: + "0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)", + border: "none", + textTransform: "uppercase", + fontSize: "13px", + fontWeight: "600", + padding: "0.375rem 0.75rem", + textAlign: "center", + color: "#ffffff", + outline: "none" + }} + type="submit" + > + Submit + </button> + </form> + </ModalUi> + </div> + ); +}; + +export default DebugUi; diff --git a/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js b/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js new file mode 100644 index 000000000..5c31d56c8 --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js @@ -0,0 +1,83 @@ +import React from "react"; +import { Document, Page, pdfjs } from "react-pdf"; +import { Stage, Layer, Rect } from "react-konva"; +const RenderDebugPdf = (props) => { + pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`; + + return ( + <div> + <div + style={{ + position: "sticky", + top: 0, + padding: 10, + zIndex: 1, + backgroundColor: "white", + border: "1px solid grey", + margin: "5px 0" + }} + > + {`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`} + </div> + <div + style={{ + flex: 1, + position: "relative", + border: "1px solid grey", + overflow: "auto" + }} + onMouseMove={props.handleMouseMoveDiv} + > + <Document + onLoadError={(e) => { + const load = { + status: false, + type: "failed" + }; + props.setPdfLoadFail(load); + }} + loading={"Loading Document.."} + onLoadSuccess={props.pageDetails} + ref={props.pdfRef} + file={props.pdfUrl} + > + <Page + onLoadSuccess={props.handlePageLoadSuccess} + pageNumber={props.pageNumber} + renderAnnotationLayer={false} + renderTextLayer={false} + onGetAnnotationsError={(error) => { + console.log("annotation error", error); + }} + /> + </Document> + + <Stage + onMouseMove={props.handleMouseMove} + onMouseDown={props.handleMouseDown} + onMouseUp={props.handleMouseUp} + width={props.pdfDimension.width} + height={props.pdfDimension.height} + style={{ position: "absolute", top: 0, left: 0 }} + > + <Layer> + {props.annotations.map((value) => { + return ( + <Rect + x={value.x} + y={value.y} + width={value.width} + height={value.height} + fill="transparent" + stroke="black" + /> + ); + })} + </Layer> + </Stage> + </div> + </div> + ); +}; + +export default RenderDebugPdf; diff --git a/microfrontends/SignDocuments/src/Routes.js b/microfrontends/SignDocuments/src/Routes.js index 58039a599..117ea04fe 100644 --- a/microfrontends/SignDocuments/src/Routes.js +++ b/microfrontends/SignDocuments/src/Routes.js @@ -10,7 +10,7 @@ import LegaDrive from "./Component/LegaDrive/LegaDrive"; import PageNotFound from "./Component/PageNotFound"; import TemplatePlaceHolder from "./Component/TemplatePlaceholder"; import Parse from "parse"; -import GuestLogin from "./premitives/GuestLogin"; +import DebugUi from "./Component/DebugUi"; Parse.serverURL = localStorage.getItem("baseUrl"); Parse.initialize(localStorage.getItem("parseAppId")); // `AppRoutes` is used to define route path of app and @@ -51,8 +51,7 @@ function AppRoutes() { <Route path="/legadrive" element={<LegaDrive />} /> {/* Page Not Found */} <Route path="/template/:templateId" element={<TemplatePlaceHolder />} /> - <Route path="/guestlogin" element={<GuestLogin />} /> - + <Route path="/debugpdf" element={<DebugUi />} /> <Route path="*" element={<PageNotFound />} /> </Routes> </div> diff --git a/microfrontends/SignDocuments/src/premitives/Alert.js b/microfrontends/SignDocuments/src/premitives/Alert.js index 72e3d1458..0f10cf3c8 100644 --- a/microfrontends/SignDocuments/src/premitives/Alert.js +++ b/microfrontends/SignDocuments/src/premitives/Alert.js @@ -5,20 +5,47 @@ const Alert = ({ children, type }) => { function theme(color) { switch (color) { case "success": - return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]"; + return { + border: `1px solid #c3e6cb`, // Border color + backgroundColor: "#d4edda", // Background color + color: "#155724" // Text color + }; + case "info": - return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]"; + return { + border: `1px solid #adcdeb`, // Border color + backgroundColor: "#c1daf0", // Background color + color: "#153756" // Text color + }; case "danger": - return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]"; + return { + border: `1px solid #f0a8a8`, // Border color + backgroundColor: "#f4bebe", // Background color + color: "#c42121" // Text color + }; default: - return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]"; + return { + border: `1px solid #d6d6d6`, // Border color + backgroundColor: "#d9d9d9", // Background color + color: "#575757" // Text color + }; } } return ( <> {children && ( <div - className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `} + style={{ + ...textcolor, + position: "fixed", + top: "20px", + left: "50%", + transform: "translateX(-50%)", + fontSize: "0.875rem", // Corresponds to text-sm in Tailwind CSS + borderRadius: "5px", // Rounded corners + padding: "10px 15px", // Padding + zIndex: 40 + }} > {children} </div> diff --git a/microfrontends/SignDocuments/src/premitives/GuestLogin.js b/microfrontends/SignDocuments/src/premitives/GuestLogin.js deleted file mode 100644 index 4df8a9960..000000000 --- a/microfrontends/SignDocuments/src/premitives/GuestLogin.js +++ /dev/null @@ -1,294 +0,0 @@ -import React, { useState } from "react"; -import ModalUi from './ModalUi' -import "../css/LoginPage.css"; -import loader from "../assests/loader2.gif"; -import axios from "axios"; -import { useParams } from "react-router-dom"; -import { themeColor } from "../utils/ThemeColor/backColor"; -import { useEffect } from "react"; -import { useNavigate } from "react-router-dom"; -import GuestSign from "./GuestSign"; - -function GuestLogin({children, userdetails}) { - const { id, userMail, contactBookId, serverUrl } = useParams(); - let navigate = useNavigate(); - const [email, setEmail] = useState(userMail || "prafull.navkar@nxglabs.com"); - const [OTP, setOTP] = useState(""); - const [EnterOTP, setEnterOtp] = useState(false); - const [loading, setLoading] = useState(false); - const [isLoading, setIsLoading] = useState(true); - - useEffect(() => { - handleServerUrl(); - }, []); - - //function generate serverUrl and parseAppId from url and save it in local storage - const handleServerUrl = () => { - //split url in array from '&' - localStorage.clear(); - // const checkSplit = serverUrl?.split("&"); - // const server = checkSplit?.[0]; - // const parseId = checkSplit?.[1]; - // const appName = checkSplit?.[2]; - - // const newServer = server.replaceAll("%2F", "/"); - // localStorage.setItem("baseUrl", newServer); - // localStorage.setItem("parseAppId", parseId); - // localStorage.setItem("_appName", appName); - - localStorage.setItem("baseUrl", "https://staging-app.opensignlabs.com/api/app/"); - localStorage.setItem("parseAppId", "opensignstgn"); - localStorage.setItem("_appName", "contracts"); - setIsLoading(false); - }; - - const handleChange = (event) => { - const { value } = event.target; - setOTP(value); - }; - - //send email OTP function - const SendOtp = async (e) => { - const serverUrl = - localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); - const parseId = - localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); - if (serverUrl && localStorage) { - setLoading(true); - e.preventDefault(); - setEmail(email); - - try { - let url = `${serverUrl}functions/SendOTPMailV1/`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseId - }; - let body = { - email: email.toString() - }; - let Otp = await axios.post(url, body, { headers: headers }); - - if (Otp) { - setLoading(false); - setEnterOtp(true); - } - } catch (error) { - alert("something went wrong!"); - } - } else { - alert("something went wrong!"); - } - }; - - //verify OTP send on via email - const VerifyOTP = async (e) => { - e.preventDefault(); - const serverUrl = - localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); - const parseId = - localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); - if (OTP) { - setLoading(true); - try { - let url = `${serverUrl}functions/AuthLoginAsMail/`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseId - }; - let body = { - email: email, - otp: OTP - }; - let user = await axios.post(url, body, { headers: headers }); - if (user.data.result === "Invalid Otp") { - alert("Invalid Otp"); - setLoading(false); - } else if (user.data.result === "user not found!") { - alert("User not found!"); - setLoading(false); - } else { - let _user = user.data.result; - const parseId = localStorage.getItem("parseAppId"); - localStorage.setItem("UserInformation", JSON.stringify(_user)); - localStorage.setItem( - `Parse/${parseId}/currentUser`, - JSON.stringify(_user) - ); - localStorage.setItem("username", _user.name); - localStorage.setItem("accesstoken", _user.sessionToken); - //save isGuestSigner true in local to handle login flow header in mobile view - localStorage.setItem("isGuestSigner", true); - setLoading(false); - // uKymQWaYL6 - navigate( - `/loadmf/signmicroapp/recipientSignPdf/${id}/${contactBookId}` - ); - } - } catch (error) {} - } else { - alert("Please Enter OTP!"); - } - }; - - return ( - <div style={{ padding: "2rem" }}> - <ModalUi isOpen> -<> - {isLoading ? ( - <div - style={{ - display: "flex", - justifyContent: "center", - alignItems: "center", - height: "100vh", - flexDirection: "column" - }} - > - <img - alt="no img" - src={loader} - style={{ width: "80px", height: "80px" }} - /> - <span style={{ fontSize: "13px", color: "gray" }}> - {isLoading.message} - </span> - </div> - ) : ( - <div - style={{ - margin: "10px", - border: "0.5px solid #c5c7c9", - padding: "30px", - boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px" - }} - > - <div className="main_head"> - <div className="main-logo"> - <img - alt="sign img" - src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png" - width="100%" - /> - </div> - </div> - - {!EnterOTP ? ( - <div > - <div > - <span className="welcomeText">Welcome Back !</span> - <br /> - <span className="KNLO"> - Verification code is sent to your email - </span> - <div className="card card-box" style={{ borderRadius: "0px" }}> - <div className="card-body"> - <input - type="email" - name="mobile" - value={email} - disabled - className="loginInput" - /> - <br /> - </div> - </div> - <div className="btnContainer"> - {loading ? ( - <button - type="button" - style={{ - background: themeColor(), - color: "white" - }} - className="verifyBtn" - disabled - > - <span - className="spinner-border spinner-border-sm " - role="status" - aria-hidden="true" - ></span> - Loading... - </button> - ) : ( - <button - className="verifyBtn" - style={{ - background: themeColor(), - color: "white", - marginLeft: "0px !important" - }} - onClick={(e) => SendOtp(e)} - > - Send OTP - </button> - )} - </div> - </div> - </div> - ) : ( - <div > - <div > - <span className="welcomeText">Welcome Back !</span> - <br /> - <span className="KNLO">You will get a OTP via Email</span> - <div className="card card-box"> - <div className="card-body"> - <label>Enter Verification Code</label> - <input - type="number" - className="loginInput" - name="OTP" - value={OTP} - onChange={handleChange} - /> - - <br /> - </div> - </div> - <div> - {loading ? ( - <button - style={{ - background: themeColor(), - color: "white" - }} - className="verifyBtn" - type="button" - disabled - > - <span - className="spinner-border spinner-border-sm " - role="status" - aria-hidden="true" - ></span> - Loading... - </button> - ) : ( - <button - type="button" - onClick={(e) => VerifyOTP(e)} - style={{ - background: themeColor(), - color: "white" - }} - className="verifyBtn" - > - Verify - </button> - )} - </div> - </div> - </div> - )} - </div> - )} - </> - </ModalUi> - <div><GuestSign /></div> - </div> - ); -} - -export default GuestLogin; From 98c8af5b9ced5680256da080c1c9f194193f3530 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 1 Feb 2024 20:26:36 +0530 Subject: [PATCH 41/73] feat: create document and template with coordinate --- apps/OpenSignServer/Utils.js | 15 ++ .../cloud/customRoute/v1/apiV1.js | 15 +- .../v1/routes/createDocumentwithCoordinate.js | 247 ++++++++++++++++++ .../v1/routes/createTemplatewithCoordinate.js | 183 +++++++++++++ .../cloud/parsefunction/pdf/PDF.min.js | 2 +- 5 files changed, 457 insertions(+), 5 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js diff --git a/apps/OpenSignServer/Utils.js b/apps/OpenSignServer/Utils.js index 884e8fdad..98c1a4366 100644 --- a/apps/OpenSignServer/Utils.js +++ b/apps/OpenSignServer/Utils.js @@ -2,3 +2,18 @@ export function customAPIurl() { const url = new URL(process.env.SERVER_URL); return url.pathname === '/api/app' ? url.origin + '/api' : url.origin; } + +export const color = [ + '#93a3db', + '#e6c3db', + '#c0e3bc', + '#bce3db', + '#b8ccdb', + '#ceb8db', + '#ffccff', + '#99ffcc', + '#cc99ff', + '#ffcc99', + '#66ccff', + '#ffffcc', +]; diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index b4a5449b3..cf671c8d9 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -24,7 +24,8 @@ import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; import saveWebhook from './routes/saveWebhook.js'; import deleteWebhook from './routes/deleteWebhook.js'; import getWebhook from './routes/getWebhook.js'; - +import createDocumentwithCoordinate from './routes/createDocumentwithCoordinate.js'; +import createTemplatewithCoordinate from './routes/createTemplatewithCoordinate.js'; dotenv.config(); const storage = multer.memoryStorage(); const upload = multer({ storage: storage }); @@ -51,8 +52,11 @@ app.get('/contactlist', getContactList); // create Document app.post('/createdocumentwithbinary', upload.array('file', 1), createDocument); -// create Document with base64 -app.post('/createdocument', createDocument); +// create Document with co-ordinate +app.post('/createdocument', upload.array('file', 1), createDocumentwithCoordinate); + +// create Document with base64 without placeholder +app.post('/draftdocument', createDocument); // create Document with templateId app.post('/createdocument/:template_id', createDocumentWithTemplate); @@ -69,8 +73,11 @@ app.delete('/document/:document_id', deleteDocument); // get all types of documents on the basis of doctype app.get('/documentlist/:doctype', getDocumentList); +// create Template with co-ordinate +app.post('/createtemplate', upload.array('file', 1), createTemplatewithCoordinate); + // create Template -app.post('/createtemplate', createTemplate); +app.post('/drafttemplate', createTemplate); // create Template with binary app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplate); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js new file mode 100644 index 000000000..8c1c4e68d --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -0,0 +1,247 @@ +import axios from 'axios'; +import { color, customAPIurl } from '../../../../Utils.js'; + +const randomId = () => Math.floor(1000 + Math.random() * 9000); +export default async function createDocumentwithCoordinate(request, response) { + const name = request.body.title; + const note = request.body.note; + const description = request.body.description; + const signers = request.body.signers; + const folderId = request.body.folderId; + const base64File = request.body.file; + const fileData = request.files?.[0] ? request.files[0].buffer : null; + // console.log('fileData ', fileData); + const protocol = customAPIurl(); + const baseUrl = new URL(process.env.SERVER_URL); + + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + if (signers && signers.length > 0) { + const userPtr = token.get('userId'); + let fileUrl; + if (request.files?.[0]) { + const file = new Parse.File(request.files?.[0]?.originalname, { + base64: fileData?.toString('base64'), + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } else { + const file = new Parse.File(`${name}.pdf`, { + base64: base64File, + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userPtr); + const extUser = await contractsUser.first({ useMasterKey: true }); + const parseExtUser = JSON.parse(JSON.stringify(extUser)); + + const extUserPtr = { + __type: 'Pointer', + className: 'contracts_Users', + objectId: extUser.id, + }; + + const object = new Parse.Object('contracts_Document'); + object.set('Name', name); + + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', fileUrl); + object.set('CreatedBy', userPtr); + object.set('ExtUserPtr', extUserPtr); + let contact = []; + if (signers && signers.length > 0) { + let parseSigners; + if (base64File) { + parseSigners = signers; + } else { + parseSigners = JSON.parse(signers); + } + let createContactUrl = protocol + '/v1/createcontact'; + + for (const [index, element] of parseSigners.entries()) { + const body = { + name: element?.name || '', + email: element?.email || '', + phone: element?.phone || '', + }; + try { + const res = await axios.post(createContactUrl, body, { + headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, + }); + // console.log('res ', res.data); + const contactPtr = { + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: res.data?.objectId, + }; + const newObj = { ...element, contactPtr: contactPtr, index: index }; + contact.push(newObj); + } catch (err) { + // console.log('err ', err.response); + if (err?.response?.data?.objectId) { + const contactPtr = { + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: err.response.data?.objectId, + }; + const newObj = { ...element, contactPtr: contactPtr, index: index }; + contact.push(newObj); + } + } + } + object.set( + 'Signers', + contact?.map(x => x.contactPtr) + ); + let updatePlaceholders = contact.map(x => { + return { + signerObjId: x?.contactPtr?.objectId, + signerPtr: x?.contactPtr, + Role: x.role, + Id: randomId(), + blockColor: color[x?.index], + placeHolder: x.widgets.map((widget, i) => ({ + pageNumber: widget.page, + pos: [ + { + xPosition: widget.x, + yPosition: widget.y, + isStamp: widget.type === 'stamp' || widget.type === 'image' ? true : false, + key: randomId(), + isDrag: false, + firstXPos: widget.x, + firstYPos: widget.y, + yBottom: 0, + scale: 1, + isMobile: false, + zIndex: i + 1, + type: widget.type, + widgetValue: '', + Width: widget.w, + Height: widget.h, + }, + ], + })), + }; + }); + object.set('Placeholders', updatePlaceholders); + } + if (folderId) { + object.set('Folder', { + __type: 'Pointer', + className: 'contracts_Document', + objectId: folderId, + }); + } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(userPtr.id, true); + newACL.setWriteAccess(userPtr.id, true); + object.setACL(newACL); + const res = await object.save(null, { useMasterKey: true }); + + const newDate = new Date(); + newDate.setDate(newDate.getDate() + 15); + const localExpireDate = newDate.toLocaleDateString('en-US', { + day: 'numeric', + month: 'long', + year: 'numeric', + }); + let sender = parseExtUser.Email; + let sendMail; + const serverUrl = process.env.SERVER_URL; + const newServer = serverUrl.replaceAll('/', '%2F'); + const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`; + + for (let i = 0; i < contact.length; i++) { + try { + const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; + let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + + const objectId = contact[i].contactPtr.objectId; + + const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; + let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; + const openSignUrl = 'https://www.opensignlabs.com/contact-us'; + const orgName = parseExtUser.Company ? parseExtUser.Company : ''; + const themeBGcolor = '#47a3ad'; + let params = { + recipient: contact[i].email, + subject: `${parseExtUser.Name} has requested you to sign ${parseExtUser.Name}`, + 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;'> " + + parseExtUser.Name + + ' has requested you to review and sign <strong> ' + + name + + "</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" + + sender + + "</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " + + orgName + + "</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>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 " + + 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>', + }; + sendMail = await axios.post(url, params, { headers: headers }); + } catch (error) { + console.log('error', error); + } + } + + if (sendMail.data.result.status === 'success') { + const user = contact.find(x => x.email === parseExtUser.Email); + if (user && user.email) { + return response.json({ + objectId: res.id, + url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${user.email}/${user.contactPtr.objectId}/${serverParams}`, + message: 'Document sent successfully!', + }); + } else { + return response.json({ + objectId: res.id, + message: 'Document sent successfully!', + }); + } + } + } else { + return response.status(400).json({ error: 'Please provide signers!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.status(400).json({ error: 'Something went wrong!' }); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js new file mode 100644 index 000000000..88230c6d2 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -0,0 +1,183 @@ +import axios from 'axios'; +import { color, customAPIurl } from '../../../../Utils.js'; + +const randomId = () => Math.floor(1000 + Math.random() * 9000); +export default async function createTemplatewithCoordinate(request, response) { + const name = request.body.title; + const note = request.body.note; + const description = request.body.description; + const signers = request.body.signers; + const folderId = request.body.folderId; + const base64File = request.body.file; + const fileData = request.files?.[0] ? request.files[0].buffer : null; + // console.log('fileData ', fileData); + const protocol = customAPIurl(); + const baseUrl = new URL(process.env.SERVER_URL); + + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + if (signers && signers.length > 0) { + const userPtr = token.get('userId'); + let fileUrl; + if (request.files?.[0]) { + const file = new Parse.File(request.files?.[0]?.originalname, { + base64: fileData?.toString('base64'), + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } else { + const file = new Parse.File(`${name}.pdf`, { + base64: base64File, + }); + await file.save({ useMasterKey: true }); + fileUrl = file.url(); + } + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userPtr); + const extUser = await contractsUser.first({ useMasterKey: true }); + const parseExtUser = JSON.parse(JSON.stringify(extUser)); + + const extUserPtr = { + __type: 'Pointer', + className: 'contracts_Users', + objectId: extUser.id, + }; + + const object = new Parse.Object('contracts_Template'); + object.set('Name', name); + + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', fileUrl); + object.set('CreatedBy', userPtr); + object.set('ExtUserPtr', extUserPtr); + let contact = []; + if (signers && signers.length > 0) { + let parseSigners; + if (base64File) { + parseSigners = signers; + } else { + parseSigners = JSON.parse(signers); + } + let createContactUrl = protocol + '/v1/createcontact'; + + for (const [index, element] of parseSigners.entries()) { + if (element?.name && element.phone && element?.email) { + const body = { + name: element?.name || '', + email: element?.email || '', + phone: element?.phone || '', + }; + try { + const res = await axios.post(createContactUrl, body, { + headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken }, + }); + // console.log('res ', res.data); + const contactPtr = { + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: res.data?.objectId, + }; + const newObj = { ...element, contactPtr: contactPtr, index: index }; + contact.push(newObj); + } catch (err) { + // console.log('err ', err.response); + if (err?.response?.data?.objectId) { + const contactPtr = { + __type: 'Pointer', + className: 'contracts_Contactbook', + objectId: err.response.data?.objectId, + }; + const newObj = { ...element, contactPtr: contactPtr, index: index }; + contact.push(newObj); + } + } + } else { + const newObj = { ...element, contactPtr: {}, index: index }; + contact.push(newObj); + } + } + const updatedSigners = contact?.filter(x => x.contactPtr && x.contactPtr.objectId); + if (updatedSigners && updatedSigners.length > 0) { + object.set( + 'Signers', + updatedSigners?.map(x => x.contactPtr) + ); + } + let updatePlaceholders = contact.map(x => { + return { + signerObjId: x?.contactPtr?.objectId || '', + signerPtr: x?.contactPtr || {}, + Role: x.role, + Id: randomId(), + blockColor: color[x?.index], + placeHolder: x.widgets.map((widget, i) => ({ + pageNumber: widget.page, + pos: [ + { + xPosition: widget.x, + yPosition: widget.y, + isStamp: widget.type === 'stamp' || widget.type === 'image' ? true : false, + key: randomId(), + isDrag: false, + firstXPos: widget.x, + firstYPos: widget.y, + yBottom: 0, + scale: 1, + isMobile: false, + zIndex: i + 1, + type: widget.type, + widgetValue: '', + Width: widget.w, + Height: widget.h, + }, + ], + })), + }; + }); + // console.log('updatePLacholders', updatePlaceholders); + + object.set('Placeholders', updatePlaceholders); + } + if (folderId) { + object.set('Folder', { + __type: 'Pointer', + className: 'contracts_Template', + objectId: folderId, + }); + } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(userPtr.id, true); + newACL.setWriteAccess(userPtr.id, true); + object.setACL(newACL); + const res = await object.save(null, { useMasterKey: true }); + + return response.json({ + objectId: res.id, + url: protocol + '/load/signmicroapp/template/' + res.id, + }); + } else { + return response.status(400).json({ error: 'Please provide signers!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.status(400).json({ error: 'Something went wrong!' }); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 9922362e5..7b2f197d4 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -109,7 +109,7 @@ async function sendDoctoWebhook(t, e) { Phone: t?.data?.ExtUserPtr?.Phone, }, ], - Completed: !0, + Event: 'Completed', CompletedAt: new Date(), CreatedAt: t?.data?.createdAt, }), From c9ed29261d9f478235c70a28bc77c9fc25e5847e Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 2 Feb 2024 12:28:30 +0530 Subject: [PATCH 42/73] fix:remov edit template url from create template --- .../customRoute/v1/routes/createTemplatewithCoordinate.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index 88230c6d2..8e6c619e9 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -12,7 +12,6 @@ export default async function createTemplatewithCoordinate(request, response) { const fileData = request.files?.[0] ? request.files[0].buffer : null; // console.log('fileData ', fileData); const protocol = customAPIurl(); - const baseUrl = new URL(process.env.SERVER_URL); try { const reqToken = request.headers['x-api-token']; @@ -43,8 +42,6 @@ export default async function createTemplatewithCoordinate(request, response) { const contractsUser = new Parse.Query('contracts_Users'); contractsUser.equalTo('UserId', userPtr); const extUser = await contractsUser.first({ useMasterKey: true }); - const parseExtUser = JSON.parse(JSON.stringify(extUser)); - const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', @@ -168,7 +165,7 @@ export default async function createTemplatewithCoordinate(request, response) { return response.json({ objectId: res.id, - url: protocol + '/load/signmicroapp/template/' + res.id, + message: 'Template created successfully!', }); } else { return response.status(400).json({ error: 'Please provide signers!' }); From 7cde6fd73c6b7e8f2ee8969744ca0e82b4bcd7cb Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 2 Feb 2024 14:41:45 +0530 Subject: [PATCH 43/73] fix: co-ordinates in debugpdf page is not stick on top --- apps/OpenSign/src/routes/LoadMf.js | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/OpenSign/src/routes/LoadMf.js b/apps/OpenSign/src/routes/LoadMf.js index cdb1cc384..aac217d98 100644 --- a/apps/OpenSign/src/routes/LoadMf.js +++ b/apps/OpenSign/src/routes/LoadMf.js @@ -30,7 +30,6 @@ function RemoteApp({ app }) { boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.33)", backgroundColor: "#ffffff", width: "100%", - overflow: "hidden", borderRadius: 3, height: "100%", minHeight: "100vh" From f1b7e1164b27d666e2bf74746718490104bcd09f Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 2 Feb 2024 18:33:21 +0530 Subject: [PATCH 44/73] fix: change copy box parameter from array to key value pair --- .../SignDocuments/src/Component/DebugUi.js | 75 +++++++++++-------- .../src/Component/component/RenderDebugPdf.js | 26 ++++--- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/microfrontends/SignDocuments/src/Component/DebugUi.js b/microfrontends/SignDocuments/src/Component/DebugUi.js index 94ff9bdf8..39237fd59 100644 --- a/microfrontends/SignDocuments/src/Component/DebugUi.js +++ b/microfrontends/SignDocuments/src/Component/DebugUi.js @@ -148,7 +148,9 @@ const DebugUi = () => { const handleMouseDown = (event) => { if (newAnnotation.length === 0) { const { x, y } = event.target.getStage().getPointerPosition(); - setNewAnnotation([{ x, y, width: 0, height: 0, key: "0" }]); + setNewAnnotation([ + { x, y, width: 0, height: 0, key: "0", page: pageNumber } + ]); } }; @@ -158,7 +160,11 @@ const DebugUi = () => { const sy = newAnnotation[0].y; const { x, y } = event.target.getStage().getPointerPosition(); const result = processDimensions(sx, sy, x - sx, y - sy); - const annotationToAdd = { ...result, key: annotations.length + 1 }; + const annotationToAdd = { + ...result, + key: annotations.length + 1, + page: pageNumber + }; annotations.push(annotationToAdd); setNewAnnotation([]); setAnnotations(annotations); @@ -181,6 +187,7 @@ const DebugUi = () => { y: sy, width: x - sx, height: y - sy, + page: pageNumber, key: "0" } ]); @@ -349,38 +356,40 @@ const DebugUi = () => { <code style={{ fontSize: 12, color: "black", cursor: "pointer" }} > - {` ["x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`} + {` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`} </code> - <span - style={{ - borderRadius: 4, - padding: "3px 5px", - border: "1px solid gray", - fontSize: 12, - margin: 2, - cursor: "pointer" - }} - onClick={() => - copytoclipboard( - `["x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]` - ) - } - > - <i className="fa-solid fa-copy"></i> - </span> - <span - style={{ - borderRadius: 4, - padding: "3px 5px", - border: "1px solid gray", - fontSize: 12, - margin: 2, - cursor: "pointer" - }} - onClick={() => handleDelete(coord.key)} - > - <i className="fa-solid fa-trash-can"></i> - </span> + <div> + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => + copytoclipboard( + `"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}` + ) + } + > + <i className="fa-solid fa-copy"></i> + </span> + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => handleDelete(coord.key)} + > + <i className="fa-solid fa-trash-can"></i> + </span> + </div> </li> ))} </ul> diff --git a/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js b/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js index 5c31d56c8..89ddd03f5 100644 --- a/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js +++ b/microfrontends/SignDocuments/src/Component/component/RenderDebugPdf.js @@ -61,18 +61,20 @@ const RenderDebugPdf = (props) => { style={{ position: "absolute", top: 0, left: 0 }} > <Layer> - {props.annotations.map((value) => { - return ( - <Rect - x={value.x} - y={value.y} - width={value.width} - height={value.height} - fill="transparent" - stroke="black" - /> - ); - })} + {props.annotations + .filter((value) => value.page === props.pageNumber) + .map((value) => { + return ( + <Rect + x={value.x} + y={value.y} + width={value.width} + height={value.height} + fill="transparent" + stroke="black" + /> + ); + })} </Layer> </Stage> </div> From 39c6560a2d34296c0cdbe20e506d04def601db2a Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Sat, 3 Feb 2024 18:06:27 +0530 Subject: [PATCH 45/73] refactor: remove rjsf package & change rjsf forms to normal forms --- apps/OpenSign/moduleFederation.config.js | 4 - apps/OpenSign/package-lock.json | 206 --- apps/OpenSign/package.json | 4 - apps/OpenSign/src/components/AddUser.js | 283 +++ apps/OpenSign/src/components/TreeEditForm.js | 391 ---- .../src/components/TreeFormComponent.js | 237 --- apps/OpenSign/src/components/TreeWidget.js | 895 --------- .../src/components/fields/FileUpload.js | 312 ---- .../src/components/fields/HiddenField.js | 98 - .../src/components/fields/LabelField.js | 70 - .../src/components/fields/Level1Dropdown.js | 482 ----- .../src/components/fields/MultiSelectField.js | 709 -------- .../src/components/fields/Rjsf-layout.js | 92 - .../src/components/fields/SignersInput.js | 1 + .../src/components/fields/TimeWidget.js | 26 - apps/OpenSign/src/constant/const.js | 1 + apps/OpenSign/src/json/FormJson.js | 253 +-- apps/OpenSign/src/primitives/TemplateForm.js | 336 ---- apps/OpenSign/src/redux/actions/index.js | 9 +- apps/OpenSign/src/routes/Form.js | 1602 ++++------------- .../cloud/parsefunction/getUserDetails.js | 6 +- 21 files changed, 636 insertions(+), 5381 deletions(-) create mode 100644 apps/OpenSign/src/components/AddUser.js delete mode 100644 apps/OpenSign/src/components/TreeEditForm.js delete mode 100644 apps/OpenSign/src/components/TreeFormComponent.js delete mode 100644 apps/OpenSign/src/components/TreeWidget.js delete mode 100644 apps/OpenSign/src/components/fields/FileUpload.js delete mode 100644 apps/OpenSign/src/components/fields/HiddenField.js delete mode 100644 apps/OpenSign/src/components/fields/LabelField.js delete mode 100644 apps/OpenSign/src/components/fields/Level1Dropdown.js delete mode 100644 apps/OpenSign/src/components/fields/MultiSelectField.js delete mode 100644 apps/OpenSign/src/components/fields/Rjsf-layout.js delete mode 100644 apps/OpenSign/src/components/fields/TimeWidget.js delete mode 100644 apps/OpenSign/src/primitives/TemplateForm.js diff --git a/apps/OpenSign/moduleFederation.config.js b/apps/OpenSign/moduleFederation.config.js index 5324d4c8c..9ba314cd1 100644 --- a/apps/OpenSign/moduleFederation.config.js +++ b/apps/OpenSign/moduleFederation.config.js @@ -20,10 +20,6 @@ module.exports = { "react-router-dom": { singleton: true, requiredVersion: dependencies["react-router-dom"] - }, - "rjsf-conditionals": { - singleton: true, - requiredVersion: dependencies["rjsf-conditionals"] } } }; diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index 4832ae0ee..a4c879102 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -9,9 +9,6 @@ "version": "0.1.0", "dependencies": { "@reduxjs/toolkit": "^1.9.7", - "@rjsf/core": "^5.13.0", - "@rjsf/utils": "^5.13.0", - "@rjsf/validator-ajv8": "^5.13.0", "axios": "^1.5.1", "daisyui": "^3.9.2", "file-saver": "^2.0.5", @@ -39,7 +36,6 @@ "reactour": "^1.19.2", "redux": "^4.2.1", "redux-thunk": "^2.4.2", - "rjsf-conditionals": "github:prafullnavkar-nxg/rjsf-conditionals", "serve": "^14.2.1", "styled-components": "^4.4.1", "web-vitals": "^2.1.4" @@ -3921,85 +3917,6 @@ "react": ">=16.14.0" } }, - "node_modules/@rjsf/core": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.13.0.tgz", - "integrity": "sha512-rCpJGR0yPP/ip9LKcr3SmDMkbLx4QIaRA+ag0rcalSw1XLXBSzh53SpfgaB2HN++1xhUvWtIUERRHpWjQp1E7w==", - "dependencies": { - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "markdown-to-jsx": "^7.3.2", - "nanoid": "^3.3.6", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@rjsf/utils": "^5.12.x", - "react": "^16.14.0 || >=17" - } - }, - "node_modules/@rjsf/utils": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.13.0.tgz", - "integrity": "sha512-tG2OuOJUJZ0W7VMZceD0I2SOjfMRRT1tRtG+SKbdNqhtH/gpg40aOMUj9cWgSQnYISEkNZjZq/z7NWln5RxW6A==", - "dependencies": { - "json-schema-merge-allof": "^0.8.1", - "jsonpointer": "^5.0.1", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "react-is": "^18.2.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.14.0 || >=17" - } - }, - "node_modules/@rjsf/utils/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/@rjsf/validator-ajv8": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.13.0.tgz", - "integrity": "sha512-8j0xLsxJA/k1UADeDYZ2aMVrswvOCEYNC++YchoAgWRHqDiaGAUyRbbk7oxMi6QUXnhnlCIepzNeTclHnSfPXQ==", - "dependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^2.1.1", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@rjsf/utils": "^5.12.x" - } - }, - "node_modules/@rjsf/validator-ajv8/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@rjsf/validator-ajv8/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -6965,27 +6882,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "node_modules/compute-gcd": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", - "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", - "dependencies": { - "validate.io-array": "^1.0.3", - "validate.io-function": "^1.0.2", - "validate.io-integer-array": "^1.0.0" - } - }, - "node_modules/compute-lcm": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", - "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", - "dependencies": { - "compute-gcd": "^1.2.1", - "validate.io-array": "^1.0.3", - "validate.io-function": "^1.0.2", - "validate.io-integer-array": "^1.0.0" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -7676,14 +7572,6 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, - "node_modules/deepcopy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz", - "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==", - "dependencies": { - "type-detect": "^4.0.8" - } - }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -13418,27 +13306,6 @@ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, - "node_modules/json-schema-compare": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", - "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", - "dependencies": { - "lodash": "^4.17.4" - } - }, - "node_modules/json-schema-merge-allof": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", - "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", - "dependencies": { - "compute-lcm": "^1.1.2", - "json-schema-compare": "^0.2.2", - "lodash": "^4.17.20" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -13934,21 +13801,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "node_modules/lodash.isequalwith": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz", - "integrity": "sha512-dcZON0IalGBpRmJBmMkaoV7d3I80R2O+FrzsZyHdNSFrANq/cgDqKQNmAHE8UEj4+QYWwwhkQOVdLHiAopzlsQ==" - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -14310,17 +14167,6 @@ "tmpl": "1.0.5" } }, - "node_modules/markdown-to-jsx": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.3.2.tgz", - "integrity": "sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==", - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "react": ">= 0.14.0" - } - }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -18202,26 +18048,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rjsf-conditionals": { - "version": "1.5.0", - "resolved": "git+ssh://git@github.com/prafullnavkar-nxg/rjsf-conditionals.git#439aa44e3ece077b1c8098278f86f454ad7185cf", - "license": "Apache-2.0", - "dependencies": { - "@rjsf/validator-ajv8": "^5.13.0", - "deepcopy": "^2.0.0", - "lodash.isequalwith": "^4.4.0", - "selectn": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@rjsf/core": ">=2.0.0", - "core-js": "^2.5.7", - "prop-types": "^15.7.2", - "react": "^18.2.0" - } - }, "node_modules/rollup": { "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", @@ -20423,38 +20249,6 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, - "node_modules/validate.io-array": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", - "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" - }, - "node_modules/validate.io-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", - "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" - }, - "node_modules/validate.io-integer": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", - "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", - "dependencies": { - "validate.io-number": "^1.0.3" - } - }, - "node_modules/validate.io-integer-array": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", - "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", - "dependencies": { - "validate.io-array": "^1.0.3", - "validate.io-integer": "^1.0.4" - } - }, - "node_modules/validate.io-number": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", - "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index d18085126..edffdbc62 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -4,9 +4,6 @@ "private": true, "dependencies": { "@reduxjs/toolkit": "^1.9.7", - "@rjsf/core": "^5.13.0", - "@rjsf/utils": "^5.13.0", - "@rjsf/validator-ajv8": "^5.13.0", "axios": "^1.5.1", "daisyui": "^3.9.2", "file-saver": "^2.0.5", @@ -34,7 +31,6 @@ "reactour": "^1.19.2", "redux": "^4.2.1", "redux-thunk": "^2.4.2", - "rjsf-conditionals": "github:prafullnavkar-nxg/rjsf-conditionals", "serve": "^14.2.1", "styled-components": "^4.4.1", "web-vitals": "^2.1.4" diff --git a/apps/OpenSign/src/components/AddUser.js b/apps/OpenSign/src/components/AddUser.js new file mode 100644 index 000000000..5861f6be6 --- /dev/null +++ b/apps/OpenSign/src/components/AddUser.js @@ -0,0 +1,283 @@ +import React, { useState } from "react"; +import Parse from "parse"; +import axios from "axios"; +import Title from "./Title"; +import Alert from "../primitives/Alert"; + +const AddUser = (props) => { + const [name, setName] = useState(""); + const [phone, setPhone] = useState(""); + const [email, setEmail] = useState(""); + const [isLoader, setIsLoader] = useState(false); + const [isUserExist, setIsUserExist] = useState(false); + const parseBaseUrl = localStorage.getItem("baseUrl"); + const parseAppId = localStorage.getItem("parseAppId"); + Parse.serverURL = parseBaseUrl; + Parse.initialize(parseAppId); + + const checkUserExist = async () => { + try { + const res = await Parse.Cloud.run("getUserDetails", { + email: email, + userId: Parse.User.current().id + }); + if (res) { + return true; + } else { + return false; + } + } catch (err) { + console.log("err", err); + } + }; + // Define a function to handle form submission + const handleSubmit = async (e) => { + e.preventDefault(); + e.stopPropagation(); + setIsLoader(true); + const res = await checkUserExist(); + if (res) { + setIsUserExist(true); + setIsLoader(false); + setTimeout(() => { + setIsUserExist(false); + }, 1000); + } else { + try { + const contactQuery = new Parse.Object("contracts_Users"); + contactQuery.set("Name", name); + contactQuery.set("Phone", phone); + contactQuery.set("Email", email); + contactQuery.set("UserRole", "contracts_User"); + + if (localStorage.getItem("TenetId")) { + contactQuery.set("TenantId", { + __type: "Pointer", + className: "partners_Tenant", + objectId: localStorage.getItem("TenetId") + }); + } + + 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("phone", phone); + _user.set("password", phone); + + const user = await _user.save(); + if (user) { + const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessionToken: localStorage.getItem("accesstoken") + }; + const body = { + appName: localStorage.getItem("_appName"), + roleName: "contracts_User", + userId: user.id + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + + contactQuery.set("UserId", user); + const acl = new Parse.ACL(); + acl.setPublicReadAccess(true); + acl.setPublicWriteAccess(true); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + + contactQuery.setACL(acl); + + const res = await contactQuery.save(); + + const parseData = JSON.parse(JSON.stringify(res)); + if (props.details) { + props.details({ + value: parseData[props.valueKey], + label: parseData[props.displayKey] + }); + } + if (props.closePopup) { + props.closePopup(); + } + if (props.handleUserData) { + props.handleUserData(parseData); + } + + setIsLoader(false); + + setName(""); + setPhone(""); + setEmail(""); + } + } catch (err) { + console.log("err ", err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run("getUserId", params); + const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessionToken: localStorage.getItem("accesstoken") + }; + const body = { + appName: localStorage.getItem("_appName"), + roleName: "contracts_User", + userId: userRes.id + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + + contactQuery.set("UserId", { + __type: "Pointer", + className: "_User", + objectId: userRes.id + }); + const acl = new Parse.ACL(); + acl.setPublicReadAccess(true); + acl.setPublicWriteAccess(true); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + + contactQuery.setACL(acl); + const res = await contactQuery.save(); + + const parseData = JSON.parse(JSON.stringify(res)); + if (props.details) { + props.details({ + value: parseData[props.valueKey], + label: parseData[props.displayKey] + }); + } + if (props.closePopup) { + props.closePopup(); + } + if (props.handleUserData) { + props.handleUserData(parseData); + } + setIsLoader(false); + setName(""); + setPhone(""); + setEmail(""); + } + } + } catch (err) { + // console.log("err", err); + setIsLoader(false); + alert("something went wrong!"); + } + } + }; + + // Define a function to handle the "add yourself" checkbox + const handleReset = () => { + setName(""); + setPhone(""); + setEmail(""); + }; + + return ( + <div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50"> + <Title title={"Add User"} /> + {isUserExist && <Alert type="danger">User already exists!</Alert>} + {isLoader && ( + <div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50"> + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + )} + <div className="w-full mx-auto"> + <form onSubmit={handleSubmit}> + <h1 className="text-[20px] font-semibold mb-4">Add User</h1> + <div className="mb-3"> + <label + htmlFor="name" + className="block text-xs text-gray-700 font-semibold" + > + Name + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="text" + id="name" + value={name} + onChange={(e) => setName(e.target.value)} + required + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + /> + </div> + <div className="mb-3"> + <label + htmlFor="email" + className="block text-xs text-gray-700 font-semibold" + > + Email + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="email" + id="email" + value={email} + onChange={(e) => setEmail(e.target.value)} + required + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + /> + </div> + <div className="mb-3"> + <label + htmlFor="phone" + className="block text-xs text-gray-700 font-semibold" + > + Phone + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="text" + id="phone" + value={phone} + onChange={(e) => setPhone(e.target.value)} + required + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + /> + </div> + + <div className="flex items-center mt-3 gap-2 text-white"> + <button + type="submit" + className="bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none" + > + Submit + </button> + <div + type="button" + onClick={() => handleReset()} + className="bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none" + > + Reset + </div> + </div> + </form> + </div> + </div> + ); +}; + +export default AddUser; diff --git a/apps/OpenSign/src/components/TreeEditForm.js b/apps/OpenSign/src/components/TreeEditForm.js deleted file mode 100644 index 4de7e9c2f..000000000 --- a/apps/OpenSign/src/components/TreeEditForm.js +++ /dev/null @@ -1,391 +0,0 @@ -import React, { useState, useEffect } from "react"; -import Form from "@rjsf/core"; -import validator from "@rjsf/validator-ajv8"; -import Parse from "parse"; -import "../styles/loader.css"; -import LayoutField from "./fields/Rjsf-layout"; -import TimeWidget from "./fields/TimeWidget"; -import Level1Dropdown from "./fields/Level1Dropdown"; -import HiddenField from "./fields/HiddenField"; -import MultiSelectField from "./fields/MultiSelectField"; -import TreeWidget from "../components/TreeWidget"; -import { formJson } from "../json/FormJson"; -const TreeEditForm = (props) => { - const widget = { - TimeWidget: TimeWidget - }; - const fields = { - layout: LayoutField, - Level1Dropdown: Level1Dropdown, - HiddenField: HiddenField, - MultiSelectField: MultiSelectField, - FolderComponent: TreeWidget - }; - - const [schema, setschema] = useState({}); - const [ui_schema, setui_schema] = useState({}); - const [title, settitle] = useState(""); - const [schemaState, setschemaState] = useState({}); - const [formData, setformData] = useState({}); - const [active, setactive] = useState(true); - const [loading, setloading] = useState(false); - const [_validate, set_validate] = useState(null); - const [noValidate, setnoValidate] = useState(false); - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - - const getForm = async (id) => { - setloading(true); - try { - //get json form data (schema ,uischema) - const results = formJson(id); - try { - let _record = Parse.Object.extend(results.class); - var query1 = new Parse.Query(_record); - await query1.get(props.objectId).then( - (x) => { - try { - if (x) { - let result = x.toJSON(); - let new_result = result; - for (let [key, value] of Object.entries(result)) { - if (value["__type"] === "Date") { - let todayTime1 = new Date(value.iso); - var month = String(todayTime1.getMonth() + 1); - var day = String(todayTime1.getDate()); - var year = String(todayTime1.getFullYear()); - if (month.length < 2) month = "0" + month; - if (day.length < 2) day = "0" + day; - let date1 = year + "-" + month + "-" + day; - let bindVar = date1; - if (!results.jsonSchema.properties[key].format) { - bindVar = todayTime1.toISOString(); - } - new_result[key] = bindVar; - } - } - setschemaState(results.jsonSchema); - setformData(new_result); - } - } catch (error) { - //alert(error.message); - - setloading(false); - } - }, - (error) => { - console.log("err", error); - setloading(false); - } - ); - setschema(results.jsonSchema); - setui_schema(results.uiSchema); - set_validate(results.validFunction); - setnoValidate(results.noValidate); - settitle(results.class); - setloading(false); - setactive(true); - } catch (error) { - setloading(false); - } - } catch (e) { - setloading(false); - console.error("Problem", e); - } - }; - - const wrap = (s) => "{ return " + s + " };"; - - const dynamicValidate = (formData, errors) => { - try { - let body = atob(_validate); - let res = new Function(wrap(body)) - .call(null) - .call(null, formData, errors); - return res; - } catch (error) { - console.log(error); - } - }; - - const handleSubmit = async ({ formData }) => { - setactive(false); - setloading(true); - let RowData = formData; - RowData && - Object.entries(RowData).forEach(([key, value]) => { - if (typeof value === "string") { - RowData[key] = value.trim(); - } - }); - let _scanData = schemaState; - if (_scanData.dependencies) { - Object.keys(_scanData.dependencies).forEach((key) => { - if (_scanData.dependencies[key].oneOf) { - _scanData.dependencies[key].oneOf.forEach((val) => { - Object.keys(val.properties).forEach((k) => { - if (typeof val.properties[k] === "object") { - if (val.properties[k].format === "date") { - if (RowData[k]) { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - } - if (val.properties[k].component === "HtmlEditor") { - if (RowData[k]) { - let newHtml = RowData[k] - .replace(/<p[^>]*>/g, "") - .replace(/<\/p>/g, " "); - RowData[k] = newHtml; - } - } - if (val.properties[k].component === "DateTime") { - if (RowData[k]) { - let newDate11 = new Date(RowData[k]); - RowData[k] = newDate11; - } - } - if (val.properties[k].component === "CurrencyInput") { - if (val.properties[k].currencyColumn) { - RowData[`${val.properties[k].currencyColumn}`] = - val.properties[k].defaultcurrency; - } - } - if (val.properties[k].type === "string") { - if (typeof RowData[k] === "string") - RowData[k] = RowData[k].trim(); - } - if (val.properties[k].data !== undefined) { - if (val.properties[k].data.isPointer) { - let pointer = undefined; - if (val.properties[k].data.class) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: val.properties[k].data.class, - objectId: RowData[k] - }; - } - } else { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - } - RowData[k] = pointer; - } - if (val.properties[k].data.FolderTypeValue) { - if (RowData[k]) { - let obj = { - __type: "Pointer", - className: val.properties[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - } - } - }); - }); - } - }); - } - let temp = []; - - let _dd = _scanData.properties; - let allowed = []; - if (_dd) { - Object.keys(_dd).forEach(function (k) { - allowed.push(k); - if (RowData[k]) { - let pointer = { - __type: "Pointer", - className: _dd[k].class, - objectId: RowData[k] - }; - RowData[k] = pointer; - } - if (_dd[k].format === "date") { - if (RowData[k]) { - let newdate = new Date(RowData[k]); - if (!isNaN(newdate.getTime())) { - RowData[k] = newdate; - } - } - } - if (_dd[k].component === "HtmlEditor") { - if (RowData[k]) { - let newHtml = RowData[k] - .replace(/<p[^>]*>/g, "") - .replace(/<\/p>/g, " "); - RowData[k] = newHtml; - } - } - if (_dd[k].component === "DateTime") { - if (RowData[k]) { - let newdate = new Date(RowData[k]); - if (!isNaN(newdate.getTime())) { - RowData[k] = newdate; - } - } - } - if (_dd[k].format === "date-time") { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - if (_dd[k].component === "CurrencyInput") { - if (_dd[k].currencyColumn) { - RowData[`${_dd[k].currencyColumn}`] = _dd[k].defaultcurrency; - } - } - if (_dd[k].data !== undefined) { - if (_dd[k].data.isPointer) { - let pointer = undefined; - if (typeof RowData[k] === "object") { - if (RowData[k]) { - if (RowData[k].objectId !== "Select") { - let obj = { - __type: "Pointer", - className: RowData[k].className, - objectId: RowData[k].objectId - }; - pointer = obj; - } - } - } else if (_dd[k].data.class) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: _dd[k].data.class, - objectId: RowData[k] - }; - } - } else { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - } - - RowData[k] = pointer; - } - if (_dd[k].data.FolderTypeValue) { - if (RowData[k]) { - let obj = { - __type: "Pointer", - className: _dd[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - } - if (_dd[k].type === "string") { - if (typeof RowData[k] === "string") RowData[k] = RowData[k].trim(); - } - }); - } - const filtered = Object.keys(RowData) - .filter((key) => allowed.includes(key)) - .reduce((obj, key) => { - obj[key] = RowData[key]; - return obj; - }, {}); - - try { - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - const currentUser = Parse.User.current(); - if (temp.length !== 0) { - let userPointer = { - __type: "Pointer", - className: "_User", - objectId: currentUser.id - }; - filtered[[temp[0]]] = userPointer; - } - var data = Parse.Object.extend(title); - var query = new Parse.Query(data); - query.get(props.objectId).then(async (object) => { - object.save(filtered).then( - () => { - try { - alert("Record updated successfully"); - props.HideView(false); - setloading(false); - setactive(true); - } catch (error) { - console.log("err", error); - } - }, - (error) => { - console.log("err", error); - setloading(false); - setactive(true); - } - ); - }); - } catch (error) { - console.log("err", error); - - alert(error.message); - setloading(false); - setactive(true); - } - }; - - useEffect(() => { - if (props.FormId) { - getForm(props.FormId); - } - // eslint-disable-next-line - }, [props.FormId]); - - if (loading) { - return ( - <div - className="loader-01" - style={{ - marginTop: "50px", - marginLeft: "50%", - color: "rgb(0,28,28)", - fontSize: "35px" - }} - ></div> - ); - } - return ( - <Form - schema={schema} - uiSchema={ui_schema} - formData={formData} - showErrorList={false} - widgets={widget} - fields={fields} - validate={noValidate && dynamicValidate} - onSubmit={handleSubmit} - validator={validator} - > - <div> - {active ? ( - <button className="bg-[#1ab6ce] px-3 py-2 rounded text-white text-sm" type="submit"> - Update - </button> - ) : ( - <button className="bg-[#1ab6ce] px-3 py-2 rounded text-white text-sm" type="submit" disabled> - Update - </button> - )} - </div> - </Form> - ); -}; - -export default TreeEditForm; diff --git a/apps/OpenSign/src/components/TreeFormComponent.js b/apps/OpenSign/src/components/TreeFormComponent.js deleted file mode 100644 index 7f7ad806c..000000000 --- a/apps/OpenSign/src/components/TreeFormComponent.js +++ /dev/null @@ -1,237 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Form from "@rjsf/core"; -import validator from "@rjsf/validator-ajv8"; -import LayoutField from "./fields/Rjsf-layout"; -import Level1Dropdown from "./fields/Level1Dropdown"; -import HiddenField from "./fields/HiddenField"; -import MultiSelectField from "./fields/MultiSelectField"; -import "../styles/loader.css"; -import "../styles/form.css"; -import FileUpload from "./fields/FileUpload"; -import parse from "html-react-parser"; -import TimeWidget from "./fields/TimeWidget"; -import { formJson } from "../json/FormJson"; -function TreeFormComponent(props) { - const widget = { - TimeWidget: TimeWidget - }; - - const fields = { - layout: LayoutField, - FileUpload: FileUpload, - Level1Dropdown: Level1Dropdown, - HiddenField: HiddenField, - MultiSelectField: MultiSelectField - }; - - const [link, setLink] = useState(""); - const [help, setHelp] = useState(""); - const toastDescription = ""; - const toastColor = "#5cb85c"; - const [loading, setLoding] = useState(true); - const [schemaState, setSchemaState] = useState({}); - const [formData, setFormData] = useState({}); - const [ui_schema, setUi_schema] = useState({}); - const active = true; - - console.log("new form", props); - - const getForm = async (id) => { - setLoding(true); - try { - // get json from data(jsonschema, uischema) - const results = formJson(id); - // console.log("result", results); - if (results) { - let parentObject = {}, - childObject = {}; - const resultjson = results; - for (let [key, value] of Object.entries( - resultjson.jsonSchema.properties - )) { - if (key === props.ParentField) { - if (props.ParentValue[key]) { - parentObject = { [key]: props.ParentValue[key] }; - } - } else { - if (props.ParentValue && typeof props.ParentValue === "object") { - Object.entries(props.ParentValue).forEach(([k, value]) => { - if (k === key) { - let newO = { [k]: value }; - parentObject = { ...parentObject, ...newO }; - } - }); - } - } - if (props.ChildField) { - Object.entries(props.ChildField).forEach(([k, value]) => { - if (k === key) { - let newO = { [k]: value }; - childObject = { ...childObject, ...newO }; - } - }); - } - - if (typeof value === "object") { - for (let [k, v] of Object.entries(value)) { - if (k === "format" && v === "date") { - let today = new Date(); - let date = - today.getFullYear() + - "-" + - ("0" + (today.getMonth() + 1)).slice(-2) + - "-" + - ("0" + today.getDate()).slice(-2); - value.default = date; - } - } - } - } - if (props.ParentField) { - setFormData({ ...parentObject, ...childObject }); - } - - let txt, link; - if (resultjson.help) { - if (resultjson.help.htmlbody) { - txt = resultjson.help.htmlbody; - } - if (resultjson.help.link) { - link = resultjson.help.link; - } - } - setHelp(txt); - setLink(link); - - props.ClassName(resultjson.class); - props.SchemaState(resultjson.jsonSchema); - setSchemaState(resultjson.jsonSchema); - setUi_schema(resultjson.uiSchema); - setLoding(false); - } else { - alert("form not found"); - setLoding(false); - } - } catch (e) { - console.error("Problem", e); - setLoding(false); - } - }; - - useEffect(() => { - if (!props.IsEdit) { - getForm(props.Id); - } - // console.log("props tree", props); - // eslint-disable-next-line - }, []); - - let formView = ( - <React.Fragment> - <Form - schema={schemaState} - uiSchema={ui_schema} - showErrorList={false} - widgets={widget} - fields={fields} - formData={formData} - onSubmit={props.handleSubmit} - validator={validator} - > - {active ? ( - <button className="btn btn-info submiBtn" type="submit"> - {props.IsEdit ? "update folder" : "create folder"} - </button> - ) : ( - <button className="btn btn-info submiBtn " type="submit" disabled> - submitting... - </button> - )} - </Form> - </React.Fragment> - ); - - if (loading) { - formView = ( - <div style={{ height: "300px" }}> - <div - style={{ - marginLeft: "45%", - marginTop: "150px", - fontSize: "45px", - color: "#3dd3e0" - }} - className="loader-37" - ></div> - </div> - ); - } - - return ( - <React.Fragment> - <div className="row"> - <div className="col-md-12"> - <div className="card"> - <div className="card-body no-padding height-9"> - {help ? ( - <div className="dropdown" style={{ marginTop: "-30px" }}> - <i - className="far fa-question-circle dropdown-toggle hovereffect" - aria-hidden="true" - id="dropdownMenuButton" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" - style={{ - fontSize: "18px", - color: "purple", - cursor: "pointer !important", - position: "relative", - top: "40px", - left: "98%" - }} - ></i> - <div - className="dropdown-menu" - aria-labelledby="dropdownMenuButton" - style={{ - marginleft: "-121px", - margintop: "-14px", - position: "absolute", - padding: "10px", - width: "300px", - top: "102px!important" - }} - > - {parse(` - ${help} - `)} - <br /> - {link ? ( - <a - onClick={(e) => { - e.preventDefault(); - window.location.href = link; - }} - target="_blank" - className="btn btn-xs btn-primary" - > - Read more.. - </a> - ) : null} - </div> - </div> - ) : null} - <div style={{ fontSize: "13px" }}>{formView}</div> - </div> - </div> - </div> - </div> - <div id="snackbar" style={{ backgroundColor: toastColor }}> - {toastDescription} - </div> - </React.Fragment> - ); -} - -export default TreeFormComponent; diff --git a/apps/OpenSign/src/components/TreeWidget.js b/apps/OpenSign/src/components/TreeWidget.js deleted file mode 100644 index 569112d71..000000000 --- a/apps/OpenSign/src/components/TreeWidget.js +++ /dev/null @@ -1,895 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { connect } from "react-redux"; -import LabelField from "./fields/LabelField"; -import Parse from "parse"; -import axios from "axios"; -import "../styles/spinner.css"; -import TreeFormComponent from "./TreeFormComponent"; -// import TreeEditForm from "./TreeEditForm"; -import "../styles/modal.css"; -import Modal from "react-modal"; - -const TreeWidget = (props) => { - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - const [isAddField, setIsAddField] = useState(false); - const [folderList, setFolderList] = useState([]); - const [tabList, setTabList] = useState([]); - const [appId, setAppId] = useState(undefined); - const [selectedFolder, setSelectedFolder] = useState(undefined); - const [loader, setLoader] = useState(false); - const [className, setClassName] = useState(""); - const [schemaState, setSchemaState] = useState({}); - const [TabURL, setTabURL] = useState(""); - const [editable, setEditable] = useState(false); - // const [editId, setEditId] = useState(""); - const [defaultState, setDefaultState] = useState(false); - const [isShowModal, setIsShowModal] = useState(false); - const selectFolderHandle = async () => { - setIsShowModal(true); - setIsAddField(false); - setDefaultState(false); - setFolderList([]); - setLoader(true); - - if (tabList.length > 0) { - let len = tabList.length - 1; - selectedItemList(tabList[len]); - } else { - try { - var test; - if (props.schema.parent) { - try { - if (props.parent[props.schema.parent]) { - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - const currentUser = Parse.User.current(); - let res; - if (localStorage.getItem("Extand_Class")) { - let data = JSON.parse(localStorage.getItem("Extand_Class")); - res = data[0]; - } else { - res = await Parse.Cloud.run("getUserDetails", { - email: currentUser.get("email") - }); - if (res) res = res.toJSON(); - } - if (res) { - let json = res; - setAppId(json.AppId); - } - // eslint-disable-next-line - let reg = /(\#.*?\#)/gi; - let str = props.schema.data.Query; - if (str.includes("#")) { - test = str.replace(reg, props.parent[props.schema.parent]); - } else { - test = str; - } - } else { - if (props.child[props.schema.parent]) { - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - const currentUser = Parse.User.current(); - let res; - if (localStorage.getItem("Extand_Class")) { - let data = JSON.parse(localStorage.getItem("Extand_Class")); - res = data[0]; - } else { - res = await Parse.Cloud.run("getUserDetails", { - email: currentUser.get("email") - }); - if (res) res = res.toJSON(); - } - - if (res) { - let json = res; - setAppId(json.AppId); - } - // eslint-disable-next-line - let reg = /(\#.*?\#)/gi; - let str = props.schema.data.Query; - if (str.includes("#")) { - test = str.replace(reg, props.child[props.schema.parent]); - } else { - test = str; - } - } else { - alert(`Please select ${props.schema.parent}`); - setLoader(false); - return; - } - } - } catch (error) { - console.log("error ", error); - } - } else { - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - const currentUser = Parse.User.current(); - // eslint-disable-next-line - let reg = /(\#.*?\#)/gi; - let str = props.schema.data.Query; - let res; - if (localStorage.getItem("Extand_Class")) { - let data = JSON.parse(localStorage.getItem("Extand_Class")); - res = data[0]; - } else { - // emp = Parse.Object.extend(localStorage.getItem("extended_class")); - // q = new Parse.Query(emp); - // q.equalTo("UserId", currentUser); - // res = await q.first(); - // if (res) res = res.toJSON(); - const currentUser = Parse.User.current(); - res = await Parse.Cloud.run("getUserDetails", { - email: currentUser.get("email") - }); - if (res) res = res.toJSON(); - } - - if (res) { - let json = res; - setAppId(json.AppId); - } - if (str.includes("#")) { - if (res) { - let json = res.toJSON(); - let output = str.match(reg); - if (output.length === 1) { - output = output.join(); - output = output.substring(1, output.length - 1); - output = output.split("."); - if (output.length === 1) { - let out = output[0]; - if (json[out]) { - if (typeof json[out] === "object") { - test = str.replace(reg, JSON.stringify(json[out])); - } else { - test = str.replace(reg, json[out]); - } - } else { - test = str.replace(reg, currentUser.id); - } - } else if (output.length === 2) { - let out1 = json[output[0]][output[1]]; - if (out1) { - test = str.replace(reg, out1); - } - } - } - } - } else { - test = str; - } - } - - let url = `${parseBaseUrl}classes/${props.schema.data.ClassName}?${test}`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - "X-Parse-Session-Token": localStorage.getItem("accesstoken") - }; - await axios - .get(url, { headers: headers }) - .then((res) => { - if (res) { - setFolderList(res.data.results); - setLoader(false); - } - }) - .catch((err) => { - setLoader(false); - console.log(err); - }); - } catch (error) { - setLoader(false); - } - } - }; - - const selectedItemList = async (folder) => { - setLoader(true); - setFolderList([]); - try { - let url = `${parseBaseUrl}classes/${props.schema.data.ClassName}?where={"${props.schema.data.ParentFolderField}":{"__type":"Pointer","className":"${props.schema.data.ClassName}","objectId":"${folder.objectId}"}}`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - "X-Parse-Session-Token": localStorage.getItem("accesstoken") - }; - await axios.get(url, { headers: headers }).then((result) => { - if (result) { - setFolderList(result.data.results); - setLoader(false); - } - }); - } catch (error) { - setLoader(false); - } - }; - - const removeTabListItem = async (e, i) => { - e.preventDefault(); - setEditable(false); - setLoader(true); - setFolderList([]); - let list = tabList.filter((itm, j) => { - if (j <= i) { - return itm; - } - }); - setTabList(list); - setIsAddField(false); - try { - let _len = list.length - 1; - let url = `${parseBaseUrl}classes/${props.schema.data.ClassName}?where={"${props.schema.data.ParentFolderField}":{"__type":"Pointer","className":"${props.schema.data.ClassName}","objectId":"${list[_len].objectId}"}}`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - "X-Parse-Session-Token": localStorage.getItem("accesstoken") - }; - await axios.get(url, { headers: headers }).then((result) => { - if (result) { - setFolderList(result.data.results); - setLoader(false); - } - setLoader(false); - }); - } catch (error) { - setLoader(false); - } - }; - - const onDeleteFolder = async (e) => { - e.preventDefault(); - if (folderList.length > 0) { - alert( - "Folder should not delete. To delete first delete sub items in it." - ); - } else if (window.confirm(`Are you sure you want to delete this record`)) { - try { - setLoader(true); - let len = tabList.length - 1; - - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - var deleted = Parse.Object.extend(props.schema.data.ClassName); - var query = new Parse.Query(deleted); - await query.get(tabList[len].objectId).then( - (del) => { - del.destroy().then( - (y) => { - if (y) { - setLoader(false); - let list = tabList.filter((itm, j) => { - if (j !== len) return itm; - }); - setTabList(list); - if (list.length > 0) { - let len = list.length - 1; - selectedItemList(list[len]); - } else { - selectFolderHandle(); - } - alert("Folder deleted successfully."); - } - }, - (error) => { - alert(error.message); - setLoader(false); - } - ); - }, - (error) => { - console.log("error ", error); - // The object was not retrieved successfully. - setLoader(false); - } - ); - } catch (error) { - setLoader(false); - console.log(error); - } - } - }; - - const onSubmitResult = async (e) => { - setIsShowModal(false); - e.preventDefault(); - //console.log("tabList ", tabList); - if (tabList.length > 0) { - try { - let len = tabList.length - 1; - setSelectedFolder({ - Topic: tabList[len][`${props.schema.data.FolderNameField}`], - description: tabList[len][`${props.schema.data.FolderDescription}`] - }); - props.onChange(tabList[len]["objectId"]); - let url = "Folders"; - tabList.forEach((t) => { - url = url + " / " + t[`${props.schema.data.FolderNameField}`]; - }); - setTabURL(url); - setIsAddField(false); - if (!props.formData) { - setTabList([]); - } - } catch (error) { - setIsAddField(false); - alert(error.message); - } - } else { - setIsAddField(false); - } - }; - - const editFolderDisplay = async (formData) => { - try { - let objectId = formData.objectId; - let className = formData.className; - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - const fldr = Parse.Object.extend(className); - let query = new Parse.Query(fldr); - query.equalTo("objectId", objectId); - const result = await query.first(); - let resultJson = result.toJSON(); - let CustomTabList = []; - if (resultJson) { - CustomTabList.push(resultJson); - if (resultJson[`${props.schema.data.ParentFolderField}`]) { - let tabsRes = resultJson[`${props.schema.data.ParentFolderField}`]; - let looping = false; - do { - let fldttr = Parse.Object.extend(tabsRes.className); - let query2 = new Parse.Query(fldttr); - query2.equalTo("objectId", tabsRes.objectId); - let custome_res = await query2.first(); - if (custome_res) { - let tabsData = custome_res.toJSON(); - CustomTabList.push(tabsData); - if (tabsData[`${props.schema.data.ParentFolderField}`]) { - tabsRes = tabsData[`${props.schema.data.ParentFolderField}`]; - looping = true; - } else { - looping = false; - } - } - } while (looping); - } - let url = "Folders"; - CustomTabList.length > 0 && - CustomTabList.reverse().forEach( - (t) => (url = url + " / " + t[props.schema.data.FolderNameField]) - ); - setTabURL(url); - setSelectedFolder({ - Topic: resultJson[`${props.schema.data.FolderNameField}`], - description: resultJson[`${props.schema.data.FolderDescription}`] - }); - setTabList(CustomTabList); - props.onChange(resultJson.objectId); - } - } catch (error) { - console.log(error); - } - }; - - const handleSubmit = async ({ formData }) => { - setLoader(true); - - try { - let RowData = formData; - let _scanData = schemaState; - Object.keys(_scanData).forEach(function (key) { - let _dd = _scanData[key]; - Object.keys(_dd).forEach(function (k) { - if (_dd[k].component === "AutoSuggest" && _dd[k].isPointer) { - let pointer = { - __type: "Pointer", - className: _dd[k].class, - objectId: RowData[k] - }; - RowData[k] = pointer; - } - if (_dd[k].format === "date") { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - if (_dd[k].component === "DateTime") { - let newDate11; - if (!RowData[k]) { - newDate11 = new Date(); - } else { - newDate11 = new Date(RowData[k]); - } - RowData[k] = newDate11; - } - if (_dd[k].component === "CurrencyInput") { - if (_dd[k].currencyColumn) { - RowData[`${_dd[k].currencyColumn}`] = _dd[k].defaultcurrency; - } - } - if (_dd[k].data !== undefined) { - if (_dd[k].data.isPointer) { - let pointer = {}; - if (RowData[k] && RowData[k] !== "Select") { - if (_dd[k].data.class) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: _dd[k].data.class, - objectId: RowData[k] - }; - } - } else { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - - RowData[k] = pointer; - } - } - if (_dd[k].data.FolderTypeValue) { - let obj = { - __type: "Pointer", - className: _dd[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - if (_dd[k].type === "string") { - let d = RowData[k]; - if (typeof d === "string") { - RowData[k] = d.trim(); - } - } - }); - }); - - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - - var forms = Parse.Object.extend(className); - var folder = new forms(); - folder.set( - props.schema.data.FolderNameField, - formData[props.schema.data.FolderNameField] - ); - if (props.schema.data.FolderDescription) { - folder.set( - props.schema.data.FolderDescription, - formData[props.schema.data.FolderDescription] - ); - } - - folder.set("AppId", appId); - folder.set( - props.schema.data.FolderTypeField, - props.schema.data.FolderTypeValue - ); - const currentUser = Parse.User.current(); - folder.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); - if (tabList.length > 0) { - let len = tabList.length - 1; - folder.set(props.schema.data.ParentFolderField, { - __type: "Pointer", - className: props.schema.data.ClassName, - objectId: tabList[len]["objectId"] - }); - } - folder.save(RowData).then( - (result) => { - RowData = {}; - if (result) { - setIsAddField(false); - setLoader(false); - if (tabList.length > 0) { - let len = tabList.length - 1; - selectedItemList(tabList[len]); - } else { - selectFolderHandle(); - } - } - }, - (error) => { - console.log("error ", error); - setLoader(false); - } - ); - } catch (error) { - setLoader(false); - } - }; - - useEffect(() => { - if (props.formData) { - editFolderDisplay(props.formData); - } - - // eslint-disable-next-line - }, [props.formData]); - - useEffect(() => { - if (defaultState) { - selectFolderHandle(); - } - - // eslint-disable-next-line - }, [defaultState]); - const customStyles = { - content: { - top: "50%", - left: "50%", - right: "auto", - bottom: "auto", - marginRight: "-50%", - transform: "translate(-50%, -50%)", - backgroundColor: "white", - padding: 0 - }, - overlay: { - width: "100%", - backgroundColor: "rgba(0, 0, 0, 0.75)", - zIndex: 50 - } - }; - - return ( - <React.Fragment> - <LabelField - Title={props.schema.title} - Name={props.name} - Required={props.required} - HelpBody={props.schema.helpbody} - HelpLink={props.schema.helplink} - /> - <br /> - <div className="block max-w-sm bg-white border border-gray-200 shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700"> - <div - style={{ - display: "flex", - color: "black", - fontWeight: "bold", - fontSize: "13px", - padding: "2%", - alignItems: "center" - }} - > - <div style={{ width: "20%" }}> - <div - className="pull-left" - title="Select Folder" - style={{ - color: "#33bbff", - margin: "auto", - padding: "10px 10px", - textAlign: "center" - }} - > - <i - className="far fa-folder-open" - style={{ fontSize: "40px" }} - aria-hidden="true" - ></i> - </div> - </div> - <div style={{ margin: "0px 10px 0 20px", width: "80%" }}> - <div> - {selectedFolder && selectedFolder.Topic - ? selectedFolder.Topic - : "Root"} - <i - className="fa fa-pencil" - title="Select Folder" - style={{ fontSize: 17, cursor: "pointer", marginLeft: 12 }} - onClick={selectFolderHandle} - ></i> - {selectedFolder && ( - <a - className="pull-right" - onClick={() => { - setSelectedFolder(undefined); - setTabURL(undefined); - props.onChange(undefined); - }} - > - <i - className="fa fa-times-circle-o" - aria-hidden="true" - style={{ fontSize: 17 }} - ></i> - </a> - )} - </div> - {TabURL && ( - <div - style={{ fontSize: "10px", color: "gray", fontWeight: "bold" }} - > - ({TabURL}) - </div> - )} - </div> - </div> - </div> - {/* save document in folder and add new folder modal */} - <Modal - isOpen={isShowModal} - onRequestClose={() => setIsShowModal(false)} - shouldCloseOnOverlayClick={false} - contentLabel="Modal" - style={customStyles} - > - <div className="w-full min-w-[300px] md:min-w-[500px]"> - {/* header */} - <div - style={{ - display: "flex", - justifyContent: "space-between", - alignItems: "center", - backgroundColor: "rgba(203, 200, 200, 0.09)" - }} - > - <div style={{ padding: "10px" }}> - <h4 className=" text-black">Select Folder</h4> - </div> - <div style={{ padding: "10px" }}> - <button - className="btn btn-sm pull-right" - data-dismiss="modal" - title="Select Folder" - style={{ - width: "auto", - backgroundColor: "white", - border: "1px solid gray", - boxshadow: "rgba(100, 100, 111, 0.2) 0px 7px 29px 0px" - }} - onClick={(e) => { - e.preventDefault(); - setIsAddField(false); - setFolderList([]); - setEditable(false); - if (!props.formData) { - setTabList([]); - } - setIsShowModal(false); - }} - > - <span aria-hidden="true">×</span> - </button> - </div> - </div> - <hr /> - {/* body */} - <div className="p-3 space-y-6"> - <div - style={{ - color: "#ac4848", - cursor: "pointer", - fontSize: "14px", - fontWeight: "500" - }} - > - <a - onClick={() => { - setTabList([]); - setIsAddField(false); - setDefaultState(true); - setEditable(false); - }} - > - Folders - </a> - {" / "} - - {tabList && - tabList.map((tab, i) => ( - <React.Fragment key={`${tab.objectId}-${i}`}> - <a - title={tab[`${props.schema.data.FolderNameField}`]} - onClick={(e) => removeTabListItem(e, i)} - > - {tab[`${props.schema.data.FolderNameField}`]} - </a> - {" / "} - </React.Fragment> - ))} - <hr /> - </div> - {/* {editable && ( - <TreeEditForm - FormId={props.schema.data.FormId} - objectId={editId} - HideView={(cl) => { - setEditable(cl); - selectFolderHandle(); - }} - /> - )} */} - {isAddField && !loader && !editable && ( - <TreeFormComponent - Id={props.schema.data.FormId} - handleSubmit={handleSubmit} - ParentField={props.schema.parent && props.schema.parent} - ParentValue={props.schema.parent && props.parent} - ChildField={props.child && props.child} - ClassName={(cls) => setClassName(cls)} - SchemaState={(cls) => setSchemaState(cls)} - /> - )} - {loader && ( - <div - className="loader-01" - style={{ - marginTop: "50px", - marginLeft: "50%", - color: "rgb(0,28,28)", - fontSize: "35px" - }} - ></div> - )} - - {!isAddField && !editable && ( - <div - style={{ - maxHeight: "280px", - overflowY: "auto", - marginTop: "5px" - }} - > - <ul> - {folderList && - folderList.map( - (fldr) => - fldr[props.schema.data.FolderTypeField] === - props.schema.data.FolderTypeValue && ( - <li - key={`${fldr.objectId}`} - style={{ - listStyle: "none", - padding: "10px 20px", - textTransform: "capitalize", - fontWeight: 300, - border: "1px solid gray", - borderRadius: "1px", - marginTop: "8px", - transition: "all 0.75s ease", - WebkitTransition: "all 0.5s ease", - MozTransition: "all 0.5s ease", - MsTransition: "all 0.5s ease", - OTransition: "all 0.5 ease", - display: "flex", - alignItems: "center", - justifyContent: "space-between" - }} - > - <div - style={{ - display: "flex", - alignItems: "center" - }} - > - <i - className={"fa fa-folder"} - style={{ - fontSize: "1.4rem", - color: "skyblue" - }} - aria-hidden="true" - ></i> - <a - style={{ - fontWeight: "bold", - fontSize: "12px", - marginLeft: "4px", - cursor: "pointer" - }} - onClick={() => { - setTabList((tabs) => tabs.concat(fldr)); - selectedItemList(fldr); - }} - > - {fldr[`${props.schema.data.FolderNameField}`]} - </a> - </div> - - {/* {fldr[props.schema.data.FolderTypeField] === - props.schema.data.FolderTypeValue && ( - <a - className="float-right" - onClick={() => { - setEditable(true); - setEditId(fldr.objectId); - }} - > - <i - className={"fa fa-pencil"} - title={"Edit Folder"} - style={{ - fontSize: "0.9rem", - color: "purple", - cursor: "pointer" - }} - aria-hidden="true" - ></i> - </a> - )} */} - </li> - ) - )} - </ul> - </div> - )} - </div> - {/* footer */} - - <div className="flex items-center p-3 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600 justify-between"> - <button - className="btn btn-sm float-left createFolder" - title="Create New Folder" - onClick={(e) => { - e.preventDefault(); - setIsAddField(true); - }} - > - {" "} - <i - className="fa fa-plus" - style={{ fontSize: "1.5rem" }} - aria-hidden="true" - ></i> - </button> - {!isAddField && !editable && ( - <div className="flex"> - {tabList.length > 0 && ( - <button - className="btn btn-sm float-right deleteFolder" - title="Delete Folder" - onClick={onDeleteFolder} - > - {" "} - <i - className="fa fa-trash" - style={{ fontSize: "1rem" }} - aria-hidden="true" - ></i> - </button> - )} - <button - className="btn btn-sm float-right saveFolder" - title="Save Here" - onClick={onSubmitResult} - > - {" "} - {/* <i - className="fa fa-floppy-o" - style={{ fontSize: "2rem" }} - aria-hidden="true" - ></i> */} - <i - className="fas fa-save" - aria-hidden="true" - style={{ fontSize: "20px" }} - ></i> - </button> - </div> - )} - </div> - </div> - </Modal> - </React.Fragment> - ); -}; - -const mapStateToProps = (state) => { - return { - parent: state.Level1_Dropdown, - child: state.Level2_Dropdown - }; -}; - -export default connect(mapStateToProps)(TreeWidget); diff --git a/apps/OpenSign/src/components/fields/FileUpload.js b/apps/OpenSign/src/components/fields/FileUpload.js deleted file mode 100644 index e6c632a02..000000000 --- a/apps/OpenSign/src/components/fields/FileUpload.js +++ /dev/null @@ -1,312 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { SaveFileSize } from "../../constant/saveFileSize"; -import Parse from "parse"; -import sanitizeFileName from "../../primitives/sanitizeFileName"; -import DropboxChooser from "./DropboxChoose"; -const FileUpload = (props) => { - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - const [_fileupload, setFileUpload] = useState(""); - const [fileload, setfileload] = useState(false); - const [Message] = useState(false); - const [percentage, setpercentage] = useState(0); - - const REQUIRED_FIELD_SYMBOL = "*"; - - useEffect(() => { - if (!props.formData) { - setFileUpload([]); - props.onChange(undefined); - } - // eslint-disable-next-line - }, [props.formData]); - const onChange = (e) => { - try { - let files = e.target.files; - if (typeof files[0] !== "undefined") { - if (props.schema.filetypes && props.schema.filetypes.length > 0) { - var fileName = files[0].name; - var fileNameExt = fileName - .substr(fileName.lastIndexOf(".") + 1) - .toLowerCase(); - let Extensions = props.schema.filetypes.map((x) => x.toLowerCase()); - let arr = Extensions.filter((x) => x === fileNameExt); - if (arr.length > 0) { - console.log("multiple type"); - } else { - alert( - "Only these file types are accepted : " + Extensions.join(", ") - ); - } - } - if (props.schema.maxfilesizeKB && props.schema.maxfilesizeKB !== "") { - // console.log(Math.round(files[0].size / 1024)); - if ( - Math.round(Number(files[0].size) / 1024) >= - props.schema.maxfilesizeKB - ) { - alert( - `The selected file size is too large. Please select a file less than ${Math.round( - props.schema.maxfilesizeKB / 1024 - )} MB` - ); - return; - } - } - handleFileUpload(files[0]); - } else { - alert("Please select file."); - return false; - } - } catch (error) { - alert(error.message); - return false; - } - }; - - const handleFileUpload = async (file) => { - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - setfileload(true); - const size = file.size; - const fileName = file.name; - const name = sanitizeFileName(fileName); - const pdfFile = file; - const parseFile = new Parse.File(name, pdfFile); - - try { - const response = await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round((loaded * 100) / total); - // console.log("percentCompleted ", percentCompleted); - setpercentage(percentCompleted); - } - } - }); - - setFileUpload(response.url()); - props.onChange(response.url()); - setfileload(false); - // The response object will contain information about the uploaded file - // console.log("File uploaded:", response); - - // You can access the URL of the uploaded file using response.url() - // console.log("File URL:", response.url()); - if (response.url()) { - SaveFileSize(size, response.url()); - return response.url(); - } - } catch (error) { - setfileload(false); - setpercentage(0); - console.error("Error uploading file:", error); - } - }; - - const dropboxSuccess = async (files) => { - // console.log("file ", files); - setfileload(true); - const file = files[0]; - const url = file.link; - const size = file.bytes; - const mb = Math.round(file.bytes / Math.pow(1024, 2)); - - if (mb > 10) { - setTimeout(() => { - alert( - `The selected file size is too large. Please select a file less than 10 MB` - ); - }, 500); - return; - } else { - const name = sanitizeFileName(file.name); - - const parseFile = new Parse.File(name, { uri: url }); - - try { - const response = await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round((loaded * 100) / total); - // console.log("percentCompleted ", percentCompleted); - setpercentage(percentCompleted); - } - } - }); - // console.log("response.url() ", response.url()); - setFileUpload(response.url()); - props.onChange(response.url()); - setfileload(false); - - if (response.url()) { - SaveFileSize(size, response.url()); - return response.url(); - } - } catch (error) { - setfileload(false); - setpercentage(0); - console.error("Error uploading file:", error); - } - } - }; - const dropboxCancel = async () => { - console.log("cancel clicked "); - }; - let fileView = - props.formData && - props.schema.uploadtype === "s3viajw" ? null : props.formData && - props.formData ? ( - <React.Fragment> - <a - href={props.formData} - title={props.formData} - style={{ paddingBottom: "10px", color: "blue" }} - > - Download - </a> - </React.Fragment> - ) : fileload === false ? null : ( - <React.Fragment> - <a - href={_fileupload} - title={_fileupload} - style={{ paddingBottom: "10px" }} - > - Download - </a> - <br /> - </React.Fragment> - ); - - return ( - <React.Fragment> - <div style={{ display: "inline-block" }}> - <label htmlFor={props.name}> - {props.schema.title} - {props.required && ( - <span className="required">{REQUIRED_FIELD_SYMBOL}</span> - )} - {fileload ? ( - <div className="flex items-center gap-x-2"> - <div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200"> - <div - className="h-2 rounded-full bg-blue-500" - style={{ width: `${percentage}%` }} - ></div> - </div> - <span className="text-black text-sm">{percentage}%</span> - </div> - ) : ( - Message && ( - <span style={{ fontSize: "9px", marginLeft: "4px" }}> - Processing will take 5-10 mins.... - </span> - ) - )} - {props.schema.helpbody ? ( - <div className="dropdown pull-right"> - <i - className="far fa-question-circle dropdown-toggle hovereffect" - aria-hidden="true" - id="dropdownMenuButton" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" - style={{ - fontSize: "12px", - color: "purple", - cursor: "pointer !important", - position: "relative", - bottom: "0px", - left: "0px", - paddingBottom: "4px", - paddingLeft: "4px" - }} - ></i> - <div - className="dropdown-menu" - aria-labelledby="dropdownMenuButton" - style={{ - marginleft: "-121px", - margintop: "-14px", - position: "absolute", - padding: "10px", - top: "102px!important" - }} - > - <br /> - {props.schema.helplink ? ( - <a - href={props.schema.helplink} - target="_blank" - rel="noreferrer" - className="btn btn-xs btn-primary" - > - Read more.. - </a> - ) : null} - </div> - </div> - ) : null} - <span style={{ marginLeft: "10px" }}>{fileView}</span> - </label> - </div> - - <> - {props.formData ? ( - <div className="flex gap-2 justify-center items-center"> - <div className="flex justify-between items-center px-2 py-[3px] w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]"> - <div className="break-all"> - file selected : {props.formData?.split("/")[3]?.split("_")[1]} - </div> - <div - onClick={() => { - console.log("clicked"); - setFileUpload([]); - props.onChange(undefined); - }} - className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500" - > - <i className="fa-solid fa-xmark"></i> - </div> - </div> - {process.env.REACT_APP_DROPBOX_API_KEY && ( - <DropboxChooser - onSuccess={dropboxSuccess} - onCancel={dropboxCancel} - /> - )} - </div> - ) : ( - <div className="flex gap-2 justify-center items-center"> - <input - type="file" - id="hashfile" - style={{ - border: "1px solid #ccc", - color: "gray", - backgroundColor: "white", - padding: "5px 10px", - borderRadius: "4px", - fontSize: "13px", - width: "100%", - fontWeight: "bold" - }} - accept="application/pdf,application/vnd.ms-excel" - onChange={onChange} - /> - {process.env.REACT_APP_DROPBOX_API_KEY && ( - <DropboxChooser - onSuccess={dropboxSuccess} - onCancel={dropboxCancel} - /> - )} - </div> - )} - </> - </React.Fragment> - ); -}; - -export default FileUpload; diff --git a/apps/OpenSign/src/components/fields/HiddenField.js b/apps/OpenSign/src/components/fields/HiddenField.js deleted file mode 100644 index 09d582ed4..000000000 --- a/apps/OpenSign/src/components/fields/HiddenField.js +++ /dev/null @@ -1,98 +0,0 @@ -import React, { Component } from "react"; -import Parse from "parse"; -// import axios from "axios"; - -export class HiddenField extends Component { - state = { - baseUrl: localStorage.getItem("baseUrl"), - parseAppId: localStorage.getItem("parseAppId"), - _fields: "" - }; - loadData = async () => { - if (this.props.schema.default) { - this.setState({ _fields: this.props.schema.default }); - } else { - try { - Parse.serverURL = this.state.baseUrl; - Parse.initialize(this.state.parseAppId); - let currentUser = await Parse.User.current(); - if (localStorage.getItem("Extand_Class")) { - let _rdata = JSON.parse(localStorage.getItem("Extand_Class")); - let custome_Filed = ""; - let splitArray = this.props.schema.data.valueKey.split("."); - if (splitArray.length > 1) { - custome_Filed = _rdata[0][splitArray[0]][splitArray[1]]; - } else { - let _Filed = _rdata[0][splitArray[0]]; - if (typeof _Filed === "object") { - custome_Filed = { - __type: "Pointer", - className: _Filed["className"], - objectId: _Filed["objectId"] - }; - } else { - custome_Filed = _rdata[0][splitArray[0]]; - } - } - this.setState({ _fields: custome_Filed }); - } else { - if (currentUser) { - // let url = `${this.state.baseUrl}classes/${localStorage.getItem( - // "extended_class" - // )}?where={"UserId":{"__type":"Pointer","className":"_User","objectId":"${ - // currentUser.id - // }"}}&keys=${this.props.schema.data.valueKey}`; - // const headers = { - // "Content-Type": "application/json", - // "X-Parse-Application-Id": this.state.parseAppId - // }; - // await axios.get(url, { headers: headers }).then((res) => { - // let custome_Filed = ""; - // let _rdata = res.data.results; - // let splitArray = this.props.schema.data.valueKey.split("."); - // if (splitArray.length > 1) { - // custome_Filed = _rdata[0][splitArray[0]][splitArray[1]]; - // } else { - // console.log(_rdata[0][splitArray[0]]); - // custome_Filed = _rdata[0][splitArray[0]]; - // } - // this.setState({ _fields: custome_Filed }); - // }); - - const res = await Parse.Cloud.run("getUserDetails", { - email: currentUser.get("email") - }); - let custome_Filed = ""; - const result = res.toJSON(); - let _rdata = [result]; - let splitArray = this.props.schema.data.valueKey.split("."); - if (splitArray.length > 1) { - custome_Filed = _rdata[0][splitArray[0]][splitArray[1]]; - } else { - console.log(_rdata[0][splitArray[0]]); - custome_Filed = _rdata[0][splitArray[0]]; - } - this.setState({ _fields: custome_Filed }); - } - } - } catch (error) { - console.log("err", error); - } - } - }; - componentDidMount() { - this.loadData(); - } - - render() { - return ( - <input - type="hidden" - value={this.state._fields} - onChange={this.props.onChange(this.state._fields)} - /> - ); - } -} - -export default HiddenField; diff --git a/apps/OpenSign/src/components/fields/LabelField.js b/apps/OpenSign/src/components/fields/LabelField.js deleted file mode 100644 index dfa71f3cc..000000000 --- a/apps/OpenSign/src/components/fields/LabelField.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from "react"; -import parse from "html-react-parser"; -import PropTypes from "prop-types"; - -const LabelField = (props) => { - const { Title, Name, Required, HelpBody, HelpLink } = props; - const REQUIRED_FIELD_SYMBOL = "*"; - return ( - <div style={{ display: "inline-block" }}> - <label htmlFor={Name}> - {Title} - {Required && <span className="required">{REQUIRED_FIELD_SYMBOL}</span>} - {HelpBody ? ( - <div className="dropdown pull-right"> - <i - className="far fa-question-circle dropdown-toggle hovereffect pull-right" - aria-hidden="true" - id="dropdownMenuButton" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" - style={{ - fontSize: "12px", - color: "purple", - cursor: "pointer !important", - position: "relative", - bottom: "0px", - left: "0px", - paddingBottom: "4px", - paddingLeft: "4px" - }} - ></i> - <div - className="dropdown-menu" - aria-labelledby="dropdownMenuButton" - style={{ - marginleft: "-121px", - margintop: "-14px", - position: "absolute", - padding: "10px", - top: "102px!important" - }} - > - {parse(` - ${HelpBody} - `)} - <br /> - {HelpLink ? ( - <a - href={HelpLink} - target="_blank" - rel="noreferrer" - className="btn btn-xs btn-primary" - > - Read more.. - </a> - ) : null} - </div> - </div> - ) : null} - </label> - </div> - ); -}; - -LabelField.propTypes = { - Name: PropTypes.string.isRequired, - Title: PropTypes.string.isRequired -}; -export default LabelField; diff --git a/apps/OpenSign/src/components/fields/Level1Dropdown.js b/apps/OpenSign/src/components/fields/Level1Dropdown.js deleted file mode 100644 index 42228a6f6..000000000 --- a/apps/OpenSign/src/components/fields/Level1Dropdown.js +++ /dev/null @@ -1,482 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { connect } from "react-redux"; -import { onChangeLevel1Dropdown } from "../../redux/actions/index"; -import axios from "axios"; -import Parse from "parse"; -import parse from "html-react-parser"; - -const Level1Dropdown = (props) => { - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - const [Level1_DD, setLevel1_DD] = useState([]); - const [toastColor] = useState("#d9534f"); - const [toastDescription, setToastDescription] = useState(""); - const [active, setActive] = useState(false); - - const getParams = (offset) => { - const params = { - skip: offset - }; - return params; - }; - - const Level1DropdownData = async () => { - try { - if ( - props.formData && - props.uiSchema["ui:disabled"] && - props.formData !== "Select" - ) { - let url = `${parseBaseUrl}classes/${props.schema.data.class}/${props.formData}`; - if (typeof props.formData === "object") { - url = `${parseBaseUrl}classes/${props.schema.data.class}/${props.formData.objectId}`; - } - let headers1 = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - "X-Parse-Session-Token": localStorage.getItem("accesstoken") - }; - let data = []; - let response = []; - await axios.get(url, { headers: headers1 }).then((res) => { - if (res) { - data.push(res.data); - } - }); - - if (data.length > 0) { - let temp = []; - data.forEach((x) => { - let opt = ""; - if (Array.isArray(x[props.schema.data.valueKey])) { - x[props.schema.data.valueKey].forEach((tt) => { - if (typeof tt === "object") { - opt = { - objectId: tt[props.schema.data.displayKey], - option: tt[props.schema.data.displayKey] - }; - } else { - opt = { - objectId: tt, - option: tt - }; - } - temp.push(opt); - }); - } else if (props.schema.data.isPointer) { - if (props.schema.data.valueKey.includes(".")) { - let newArr = props.schema.data.valueKey.split("."); - if (newArr.length === 2) { - opt = { - objectId: x[newArr[0]][newArr[1]], - option: x[props.schema.data.displayKey] - }; - } else { - opt = { - objectId: x[newArr[0]], - option: x[props.schema.data.displayKey] - }; - } - } else { - opt = { - objectId: x[props.schema.data.valueKey], - option: x[props.schema.data.displayKey] - }; - } - temp.push(opt); - } else { - opt = { - objectId: x[props.schema.data.valueKey], - option: x[props.schema.data.displayKey] - }; - temp.push(opt); - } - }); - response = temp; - setLevel1_DD(response); - setActive(false); - if (response.length === 1) { - props.onChangeLevel1Dropdown(response[0].objectId, props.name); - props.onChange(response[0].objectId); - } else if (response.length === 0) { - props.onChangeLevel1Dropdown("", props.name); - props.onChange(""); - } - } - } else { - let response = []; - setActive(true); - Parse.serverURL = parseBaseUrl; - Parse.initialize(parseAppId); - const currentUser = Parse.User.current(); - - // eslint-disable-next-line - var reg = /(\#.*?\#)/gi; - let str = props.schema.data.query; - var test; - if (str.includes("#")) { - let res; - if (localStorage.getItem("Extand_Class")) { - let data = JSON.parse(localStorage.getItem("Extand_Class")); - res = data[0]; - } else { - const currentUser = Parse.User.current(); - res = await Parse.Cloud.run("getUserDetails", { - email: currentUser.get("email") - }); - if (res) res = res.toJSON(); - } - - if (res) { - let json = res; - let output = str.match(reg); - if (output.length === 1) { - output = output.join(); - output = output.substring(1, output.length - 1); - output = output.split("."); - if (output.length === 1) { - let out = output[0]; - if (json[out]) { - if (typeof json[out] === "object") { - test = str.replace(reg, JSON.stringify(json[out])); - } else { - test = str.replace(reg, json[out]); - } - } else { - test = str.replace(reg, currentUser.id); - } - } else if (output.length === 2) { - let out1 = json[output[0]][output[1]]; - if (out1) { - test = str.replace(reg, out1); - } - } - } else if (output.length === 2) { - let output1 = output[0]; - output1 = output1.substring(1, output1.length - 1); - output1 = output1.split("."); - if (output1.length === 1) { - let out = output1[0]; - if (json[out]) { - if (typeof json[out] === "object") { - str = str.replace(output[0], JSON.stringify(json[out])); - } else { - str = str.replace(output[0], json[out]); - } - } else { - str = str.replace(output[0], currentUser.id); - } - } else if (output1.length === 2) { - let out1 = json[output1[0]][output1[1]]; - if (out1) { - str = str.replace(output[0], out1); - } - } - let output2 = output[1]; - output2 = output2.substring(1, output2.length - 1); - output2 = output2.split("."); - if (output2.length === 1) { - let out = output2[0]; - if (json[out]) { - if (typeof json[out] === "object") { - str = str.replace(output[1], JSON.stringify(json[out])); - } else { - str = str.replace(output[1], json[out]); - } - } else { - str = str.replace(output[1], currentUser.id); - } - } else if (output2.length === 2) { - let out1 = json[output2[0]][output2[1]]; - if (out1) { - str = str.replace(output[1], out1); - } - } - test = str; - } - } else { - setToastDescription( - `User not found in ${localStorage.getItem("extended_class")}` - ); - setActive(false); - var x = document.getElementById("Level_1"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 5000); - return; - } - } else { - test = str; - } - let url = `${parseBaseUrl}classes/${props.schema.data.class}?${test}`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - "X-Parse-Session-Token": localStorage.getItem("accesstoken") - }; - let fetchCount = 0; - let offset = 0; - let data = []; - /* eslint-disable no-constant-condition */ - while (true) { - const params = getParams(offset); - await axios - .get(url, { params: params, headers: headers }) - .then((response) => { - fetchCount = response.data.results.length; - offset += response.data.results.length; - - if (fetchCount > 0) { - response.data.results.forEach((x) => { - data.push(x); - }); - } - }) - .catch((err) => { - console.error("Problem", err.response); - setToastDescription(err.response.data.message); - setActive(false); - var x = document.getElementById("Level_1"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 5000); - }); - if (fetchCount === 0 || fetchCount < 100) { - break; - } - } - if (data.length > 0) { - let temp = []; - data.forEach((x) => { - let opt = ""; - if (Array.isArray(x[props.schema.data.valueKey])) { - x[props.schema.data.valueKey].forEach((tt) => { - if (typeof tt === "object") { - if (props.schema.data.isPointer) { - opt = { - objectId: tt["objectId"], - option: tt[props.schema.data.displayKey] - }; - } else { - opt = { - objectId: tt[props.schema.data.displayKey], - option: tt[props.schema.data.displayKey] - }; - } - } else { - opt = { - objectId: tt, - option: tt - }; - } - temp.push(opt); - }); - } else if (props.schema.data.isPointer) { - if (props.schema.data.valueKey.includes(".")) { - let newArr = props.schema.data.valueKey.split("."); - if (newArr.length === 2) { - let _dis = props.schema.data.displayKey.split("."); - if (_dis.length === 2) { - opt = { - objectId: x[newArr[0]][newArr[1]], - option: x[_dis[0]][_dis[1]] - }; - } else { - opt = { - objectId: x[newArr[0]][newArr[1]], - option: x[props.schema.data.displayKey] - }; - } - } else { - opt = { - objectId: x[newArr[0]], - option: x[props.schema.data.displayKey] - }; - } - } else { - opt = { - objectId: x[props.schema.data.valueKey], - option: x[props.schema.data.displayKey] - }; - } - temp.push(opt); - } else { - opt = { - objectId: x[props.schema.data.valueKey], - option: x[props.schema.data.displayKey] - }; - temp.push(opt); - } - }); - response = temp; - setLevel1_DD(response); - setActive(false); - if (!props.formData) { - props.onChangeLevel1Dropdown("", props.name); - } - if (response.length === 1) { - props.onChangeLevel1Dropdown(response[0].objectId, props.name); - props.onChange(response[0].objectId); - } else if (response.length === 0) { - props.onChangeLevel1Dropdown("", props.name); - props.onChange(""); - } - } else { - setActive(false); - } - } - } catch (e) { - try { - setToastDescription(e.message); - setActive(false); - x = document.getElementById("Level_1"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 5000); - } catch (error) { - console.log("Err", error); - } - } - }; - - useEffect(() => { - Level1DropdownData(); - // eslint-disable-next-line - }, []); - - useEffect(() => { - if (props.formData && props.formData[`objectId`]) { - props.onChangeLevel1Dropdown(props.formData.objectId, props.name); - } else if (props.formData) { - props.onChangeLevel1Dropdown(props.formData, props.name); - } - - // eslint-disable-next-line - }, [props.formData]); - - const selectDefault = () => { - props.onChange(Level1_DD[0].objectId); - props.onChangeLevel1Dropdown(Level1_DD[0].objectId, props.name); - }; - - const REQUIRED_FIELD_SYMBOL = "*"; - return ( - <React.Fragment> - <div style={{ display: "inline-block" }}> - <label htmlFor={props.name}> - {props.schema.title} - {props.required && ( - <span className="required">{REQUIRED_FIELD_SYMBOL}</span> - )} - {props.schema.data.helpbody ? ( - <div className="dropdown pull-right"> - <i - className="far fa-question-circle dropdown-toggle hovereffect pull-right" - aria-hidden="true" - id="dropdownMenuButton" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" - style={{ - fontSize: "12px", - color: "purple", - cursor: "pointer !important", - position: "relative", - bottom: "0px", - left: "0px", - paddingBottom: "4px", - paddingLeft: "4px" - }} - ></i> - <div - className="dropdown-menu" - aria-labelledby="dropdownMenuButton" - style={{ - marginleft: "-121px", - margintop: "-14px", - position: "absolute", - padding: "10px", - top: "102px!important" - }} - > - {parse(` - ${props.schema.data.helpbody} - `)} - <br /> - {props.schema.data.helplink ? ( - <a - href={props.schema.data.helplink} - target="_blank" - rel="noreferrer" - className="btn btn-xs btn-primary" - > - Read more.. - </a> - ) : null} - </div> - </div> - ) : null} - </label> - </div> - - {Level1_DD && ( - <select - className="form-control" - name={props.name} - value={props.value} - required={props.required} - disabled={props.uiSchema["ui:disabled"]} - onChange={(e) => { - if (!e.target.value) { - if (props.schema.data.isPointer) { - localStorage.setItem("Level1", undefined); - props.onChangeLevel1Dropdown(undefined, props.name); - return props.onChange(undefined); - } else { - localStorage.setItem("Level1", e.target.value); - props.onChangeLevel1Dropdown(e.target.value, props.name); - return props.onChange(e.target.value); - } - } else { - localStorage.setItem("Level1", e.target.value); - props.onChangeLevel1Dropdown(e.target.value, props.name); - return props.onChange(e.target.value); - } - }} - readOnly={props.uiSchema["ui:disabled"] ? true : false} - defaultValue={Level1_DD.length === 1 && selectDefault} - > - <option value="">{!active ? "Select" : "loading..."}</option> - {Level1_DD && - Level1_DD.map((x, i) => ( - <React.Fragment key={i}> - {props.formData && props.formData.objectId ? ( - props.formData.objectId === x.objectId ? ( - <option value={x.objectId} selected> - {x.option} - </option> - ) : ( - <option value={x.objectId}>{x.option}</option> - ) - ) : props.formData && props.formData === x.objectId ? ( - <option value={x.objectId} selected> - {x.option} - </option> - ) : ( - <option value={x.objectId}>{x.option}</option> - )} - </React.Fragment> - ))} - </select> - )} - <div id="Level_1" style={{ backgroundColor: toastColor }}> - {toastDescription} - </div> - </React.Fragment> - ); -}; - -export default connect(null, { onChangeLevel1Dropdown })(Level1Dropdown); diff --git a/apps/OpenSign/src/components/fields/MultiSelectField.js b/apps/OpenSign/src/components/fields/MultiSelectField.js deleted file mode 100644 index 520e9398f..000000000 --- a/apps/OpenSign/src/components/fields/MultiSelectField.js +++ /dev/null @@ -1,709 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { connect } from "react-redux"; -import Select from "react-select"; -import axios from "axios"; -import LabelField from "./LabelField"; -import ReactDragListView from "react-drag-listview"; -import AppendFormInForm from "../AppendFormInForm"; -import Modal from "react-modal"; -function arrayMove(array, from, to) { - array = array.slice(); - array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]); - return array; -} - -/** - * react-sortable-hoc is depcreated not usable from react 18.x.x - * need to replace it with @dnd-kit - * code changes required - */ - -const MultiSelectField = (props) => { - Modal.setAppElement("body"); - const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); - const [parseAppId] = useState(localStorage.getItem("parseAppId")); - const [state, setState] = useState(undefined); - // const [editFormData, setEditFormData] = useState([]); - const [selected, setSelected] = React.useState([]); - const [isModal, setIsModel] = useState(false); - const onChange = (selectedOptions) => setSelected(selectedOptions); - const [modalIsOpen, setModalIsOpen] = useState(false); - - const onSortEnd = ({ oldIndex, newIndex }) => { - const newValue = arrayMove(selected, oldIndex, newIndex); - setSelected(newValue); - }; - // console.log("props",props) - const GetSelectListData = async () => { - try { - let response = []; - let str = props.schema.data.query; - let _query; - /* eslint-disable no-useless-escape */ - let reg = /(\#.*?\#)/gi; - let extclass = - localStorage.getItem("Extand_Class") && - JSON.parse(localStorage.getItem("Extand_Class")); - let extRow = extclass.length && extclass[0]; - if (str.includes("#")) { - let output = str.match(reg); - output = output.join(); - output = output.substring(1, output.length - 1); - output = output.split("."); - - if (output.length === 2) { - let out1 = extRow[output[0]][output[1]]; - _query = str.replace(reg, out1 && out1); - } else { - let out1 = extRow[output[0]]; - _query = str.replace(reg, out1 && out1); - } - } else { - _query = str; - } - let url = `${parseBaseUrl}classes/${props.schema.data.class}?${_query}`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": parseAppId, - "X-Parse-Session-Token": localStorage.getItem("accesstoken") - }; - await axios.get(url, { headers: headers }).then((res) => { - let temp = []; - let formArray = []; - let _selected = []; - if (props.schema.uiLayout === "MultiDropdownList") { - if (props.formData) { - props.formData.forEach((x) => { - if (typeof x === "object") { - formArray.push(x.objectId); - } else { - formArray.push(x); - } - }); - } - res.data.results.forEach((x) => { - let obj = {}; - if (formArray.includes(x[props.schema.data.valueKey])) { - obj = { - name: x[props.schema.data.displayKey], - value: x[props.schema.data.valueKey], - isChecked: true - }; - } else { - if (props.schema.selectAll) { - obj = { - name: x[props.schema.data.displayKey], - value: x[props.schema.data.valueKey], - isChecked: true - }; - } else { - obj = { - name: x[props.schema.data.displayKey], - value: x[props.schema.data.valueKey], - isChecked: false - }; - } - } - temp.push(obj); - }); - response = temp; - if (props.formData) { - let checkData = []; - response.forEach((x) => { - if (x.isChecked) { - checkData.push(x.value); - } - }); - setSelected(checkData); - } - setState({ [`${props.name}_DD`]: response }); - } else { - res.data.results.forEach((x) => { - let obj = {}; - if (props.formData) { - props.formData.forEach((x) => { - if (typeof x === "object") { - formArray.push(x.objectId); - } else { - formArray.push(x); - } - }); - } - - obj = { - label: x[props.schema.data.displayKey], - value: x[props.schema.data.valueKey] - }; - if (formArray.includes(x[props.schema.data.valueKey])) { - _selected.push(obj); - } - if (props.schema.selectAll) { - _selected.push(obj); - } - temp.push(obj); - }); - response = temp; - setState({ [`${props.name}_DD`]: response }); - setSelected(_selected); - } - }); - } catch (error) { - console.log("err", error); - } - }; - - const handleCheckChieldElement = (event) => { - let SelectLists = state[`${props.name}_DD`]; - let List = []; - SelectLists.forEach((select) => { - if (select.value === event.target.value) { - select.isChecked = event.target.checked; - } - if (select.isChecked) { - List.push(select.value); - } - }); - setSelected(List); - setState({ [`${props.name}_DD`]: SelectLists }); - }; - - // const Level1CheckList = async (id) => { - // try { - // let response = []; - // // eslint-disable-next-line - // let reg = /(\#.*?\#)/gi; - // let _query = props.schema.data.query; - // let output = _query.match(reg); - // if (output.length === 2) { - // let res; - // if (localStorage.getItem("Extand_Class")) { - // let data = JSON.parse(localStorage.getItem("Extand_Class")); - // res = data[0]; - // } - // output = output.filter((x) => x !== "#queryString#"); - // if (output.length === 1) { - // _query = _query.replace("#queryString#", id); - // output = output.join(); - // output = output.substring(1, output.length - 1); - // output = output.split("."); - // if (output.length > 0) { - // _query = _query.replace(reg, res[output[0]][output[1]]); - // } else { - // _query = _query.replace(reg, res[output[0]]); - // } - // } - // } else { - // _query = props.schema.data.query.replace(reg, id); - // } - - // let url = `${parseBaseUrl}classes/${props.schema.data.class}?${_query}`; - // const headers = { - // "Content-Type": "application/json", - // "X-Parse-Application-Id": parseAppId, - // "X-Parse-Session-Token": localStorage.getItem("accesstoken") - // }; - // await axios.get(url, { headers: headers }).then(async (res) => { - // let temp = []; - // let formArray = []; - // let _selected = []; - // if (editFormData.length > 0) { - // editFormData.forEach((x) => { - // if (typeof x === "object") { - // formArray.push(x.objectId); - // } else { - // formArray.push(x); - // } - // }); - // } else if ( - // props.schema.selectedData && - // Object.keys(props.schema.selectedData).length !== 0 && - // props.schema.selectedData.constructor === Object - // ) { - // try { - // let selectedDataQuery = props.schema.selectedData.query.replace( - // reg, - // id - // ); - // let selectedDataUrl = `${parseBaseUrl}classes/${props.schema.selectedData.class}?${selectedDataQuery}`; - - // await axios.get(selectedDataUrl, { headers }).then((sltres) => { - // let sltData = sltres.data.results; - // sltData.forEach((x) => { - // if (props.schema.selectedData.valueKey.includes(".")) { - // let sltArr = props.schema.selectedData.valueKey.split("."); - - // if (Array.isArray(x[sltArr[0]])) { - // x[sltArr[0]].forEach((l) => { - // formArray.push(l[sltArr[1]]); - // }); - // } else { - // formArray.push(x[sltArr[0][sltArr[1]]]); - // } - // } else { - // formArray.push(x[props.schema.selectedData.valueKey]); - // } - // }); - // }); - // } catch (error) {} - // } - // res.data.results.forEach((x) => { - // let obj = {}; - // if (props.schema.data.valueKey.includes(".")) { - // let newArr = props.schema.data.valueKey.split("."); - // if (Array.isArray(x[newArr[0]])) { - // if (props.schema.data.displayKey.includes(".")) { - // let _dis = props.schema.data.displayKey.split("."); - // x[newArr[0]].forEach((l) => { - // if (formArray.includes(l[newArr[1]])) { - // obj = { - // label: l[_dis[1]], - // value: l[newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // if (props.schema.selectAll) { - // obj = { - // label: l[_dis[1]], - // value: l[newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // obj = { - // label: l[_dis[1]], - // value: l[newArr[1]], - // isChecked: false - // }; - // } - // } - // temp.push(obj); - // }); - // } else { - // x[newArr[0]].forEach((l) => { - // if (formArray.includes(l[newArr[1]])) { - // obj = { - // label: x[props.schema.data.displayKey], - // value: l[newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // if (props.schema.selectAll) { - // obj = { - // label: x[props.schema.data.displayKey], - // value: l[newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // obj = { - // label: x[props.schema.data.displayKey], - // value: l[newArr[1]], - // isChecked: false - // }; - // } - // } - // temp.push(obj); - // }); - // } - // } else { - // if (props.schema.data.displayKey.includes(".")) { - // let disArr = props.schema.data.displayKey.split("."); - // if (formArray.includes(x[newArr[0]][newArr[1]])) { - // obj = { - // label: x[disArr[0]][disArr[1]], - // value: x[newArr[0]][newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // if (props.schema.selectAll) { - // obj = { - // label: x[disArr[0]][disArr[1]], - // value: x[newArr[0]][newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // obj = { - // label: x[disArr[0]][disArr[1]], - // value: x[newArr[0]][newArr[1]], - // isChecked: false - // }; - // } - // } - // } else { - // if (formArray.includes(x[newArr[0]][newArr[1]])) { - // obj = { - // label: x[props.schema.data.displayKey], - // value: x[newArr[0]][newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // if (props.schema.selectAll) { - // obj = { - // label: x[props.schema.data.displayKey], - // value: x[newArr[0]][newArr[1]], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // obj = { - // label: x[props.schema.data.displayKey], - // value: x[newArr[0]][newArr[1]], - // isChecked: false - // }; - // } - // } - // } - // } - // } else { - // if (Array.isArray(x[props.schema.data.valueKey])) { - // x[props.schema.data.valueKey].forEach((t) => { - // if (formArray.includes(t)) { - // obj = { - // label: t, - // value: t, - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // if (props.schema.selectAll) { - // obj = { - // label: t, - // value: t, - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // obj = { - // label: t, - // value: t, - // isChecked: false - // }; - // } - // } - // temp.push(obj); - // }); - // } else if (formArray.includes(x[props.schema.data.valueKey])) { - // obj = { - // label: x[props.schema.data.displayKey], - // value: x[props.schema.data.valueKey], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // if (props.schema.selectAll) { - // obj = { - // label: x[props.schema.data.displayKey], - // value: x[props.schema.data.valueKey], - // isChecked: true - // }; - // _selected.push(obj); - // } else { - // obj = { - // label: x[props.schema.data.displayKey], - // value: x[props.schema.data.valueKey], - // isChecked: false - // }; - // } - // } - // temp.push(obj); - // } - // }); - // response = temp; - // if (props.schema.uiLayout === "MultiDropdownList") { - // if (editFormData) { - // let checkData = []; - // response.forEach((x) => { - // if (x.isChecked) { - // checkData.push(x.value); - // } - // }); - // setSelected(checkData); - // } - // setState({ [`${props.name}_DD`]: response }); - // } else { - // setState({ [`${props.name}_DD`]: response }); - // setSelected(_selected); - // } - // }); - // } catch (error) {} - // }; - - const dragProps = { - onDragEnd(fromIndex, toIndex) { - const data = [...state[`${props.name}_DD`]]; - const item = data.splice(fromIndex, 1)[0]; - data.splice(toIndex, 0, item); - let NewList = []; - data.forEach((x) => { - if (x.isChecked) { - NewList.push(x.value); - } - }); - - setState({ [`${props.name}_DD`]: data }); - setSelected(NewList); - }, - nodeSelector: "li", - handleSelector: "a" - }; - - useEffect(() => { - if (!props.schema.parent) GetSelectListData(); - // eslint-disable-next-line - }, []); - - useEffect(() => { - if (props.schema.uiLayout === "MultiDropdownList") { - props.onChange(selected); - } else { - if (selected && selected.length) { - let newData = []; - selected.forEach((x) => { - newData.push(x.value); - }); - props.onChange(newData); - } - } - // eslint-disable-next-line - }, [selected]); - - // useState(() => { - // if (props.formData) { - // if (props.formData === "Select") { - // } else { - // setEditFormData(props.formData); - // } - // } - // // eslint-disable-next-line - // }, [props.formData]); - - const handleModalCloseClick = () => { - setIsModel(false); - setModalIsOpen(false); - }; - - const openModal = () => { - setModalIsOpen(true); - }; - - // `handleNewDetails` is used to set just save from quick form to selected option in dropdown - const handleNewDetails = (data) => { - setState({ [`${props.name}_DD`]: [...state[`${props.name}_DD`], data] }); - if (selected.length > 0) { - setSelected([...selected, data]); - } else { - setSelected([data]); - } - }; - if (props.schema.uiLayout === "MultiDropdownList") { - return ( - <React.Fragment> - <LabelField - Title={props.schema.title} - Name={props.name} - Required={props.required} - HelpBody={props.schema.helpbody} - HelpLink={props.schema.helplink} - /> - <ReactDragListView {...dragProps}> - <ul - style={{ - listStyleType: "square", - listStylePosition: "outside", - maxHeight: "250px", - overflow: "auto", - paddingTop: "10px", - paddingBottom: "10px", - border: "0px solid #b3b3b3", - borderRadius: "5px" - }} - > - {state && state[`${props.name}_DD`].length > 0 ? ( - state[`${props.name}_DD`].map((x, i) => { - return ( - <li key={i} className="multiSelectList"> - <input - key={x.value} - onClick={handleCheckChieldElement} - type="checkbox" - checked={x.isChecked} - style={{ marginTop: "7px" }} - value={x.value} - disabled={props.disabled} - />{" "} - <span style={{ marginTop: "7px" }}>{x.name}</span> - {props.schema.isSortable && !props.disabled && ( - <a - onClick={(e) => e.preventDefault()} - className="pull-right" - title="Sort List" - style={{ textDecoration: "none" }} - > - <i - className="fa fa-bars" - style={{ - fontSize: "30px", - color: "skyblue", - paddingTop: "11px" - }} - ></i> - </a> - )} - </li> - ); - }) - ) : ( - <li className="multiSelectList">No Record Found</li> - )} - </ul> - </ReactDragListView> - </React.Fragment> - ); - } - - return ( - <React.Fragment> - <LabelField - Title={props.schema.title} - Name={props.name} - Required={props.required} - HelpBody={props.schema.helpbody} - HelpLink={props.schema.helplink} - /> - <div style={{ display: "flex", gap: 5 }}> - <div style={{ flexWrap: "wrap", width: "100%" }}> - <Select - onSortEnd={onSortEnd} - distance={4} - isMulti - options={(state && state[`${props.name}_DD`]) || []} - value={selected} - onChange={onChange} - closeMenuOnSelect={false} - /> - </div> - - {props.schema.data.quickAddFormId && ( - <div - onClick={() => { - setIsModel(true); - openModal(); - }} - style={{ - cursor: "pointer", - borderRadius: 4, - border: "1px solid #ccc", - minHeight: 38, - minWidth: 48, - display: "flex", - justifyContent: "center", - alignItems: "center" - }} - > - <i className="fas fa-plus"></i> - </div> - )} - {/* {props.schema.data.quickAddFormId && ( - <div - className="modal fade" - id={"multiSelectModal" + props.schema.data.quickAddFormId} - tabIndex="-1" - role="dialog" - aria-labelledby="exampleModalLabel" - aria-hidden="true" - > - <div className="modal-dialog modal-lg" role="document"> - <div className="modal-content"> - <div className="modal-header"> - <button - type="button" - className="close" - data-dismiss="modal" - aria-label="Close" - onClick={handleModalCloseClick} - > - <i className="fa fa-times-circle" aria-hidden="true"></i> - </button> - </div> - <div className="modal-body"> - {isModal && ( - <AppendFormInForm - id={props.schema.data.quickAddFormId} - valueKey={props.schema.data.valueKey} - displayKey={props.schema.data.displayKey} - details={handleNewDetails} - closePopup={handleModalCloseClick} - /> - )} - </div> - </div> - </div> - </div> - )} */} - <Modal - isOpen={modalIsOpen} - onRequestClose={handleModalCloseClick} - shouldCloseOnOverlayClick={false} - contentLabel="Modal" - style={{ - content: { - top: "50%", - left: "50%", - right: "auto", - bottom: "auto", - transform: "translate(-50%, -50%)", - padding: 0 - }, - overlay: { - width: "100%", - backgroundColor: "rgba(0, 0, 0, 0.75)", - zIndex: 50 - } - }} - > - <div className="min-w-full md:min-w-[500px]"> - <div - type="button" - className="flex justify-between items-center p-3 border-b-[1px] border-gray-300" - > - <div className=" text-black text-xl font-semibold pl-3"> - Add Signer - </div> - <button onClick={handleModalCloseClick}> - <i - style={{ fontSize: 25 }} - className="fa fa-times-circle" - aria-hidden="true" - ></i> - </button> - </div> - - {isModal && ( - <AppendFormInForm - id={props.schema.data.quickAddFormId} - valueKey={props.schema.data.valueKey} - displayKey={props.schema.data.displayKey} - details={handleNewDetails} - closePopup={handleModalCloseClick} - /> - )} - </div> - </Modal> - </div> - </React.Fragment> - ); -}; - -const mapStateToProps = (state) => { - return { - Level1_Dropdown: state.Level1_Dropdown, - Level2_Dropdown: state.Level2_Dropdown, - Level3_Dropdown: state.Level3_Dropdown - }; -}; -export default connect(mapStateToProps, null)(MultiSelectField); diff --git a/apps/OpenSign/src/components/fields/Rjsf-layout.js b/apps/OpenSign/src/components/fields/Rjsf-layout.js deleted file mode 100644 index a48be8190..000000000 --- a/apps/OpenSign/src/components/fields/Rjsf-layout.js +++ /dev/null @@ -1,92 +0,0 @@ -import React from "react"; -import ObjectField from "@rjsf/core/lib/components/fields/ObjectField"; -import validator from "@rjsf/validator-ajv8"; -import { Col } from "react-bootstrap"; -import { retrieveSchema } from "@rjsf/utils"; - -class GridField extends ObjectField { - state = {}; - render() { - const { - uiSchema, - errorSchema, - idSchema, - - disabled, - readonly, - onBlur, - formData - } = this.props; - const { fields, rootSchema } = this.props.registry; - - const { SchemaField } = fields; - const schema = retrieveSchema(validator, this.props.schema, rootSchema); - const title = schema.title === undefined ? "" : schema.title; - const description = - schema && schema.description === undefined ? "" : schema.description; - // console.log('this.props.schema ', this.props.schema) - // console.log("schema ", schema); - const layout = uiSchema["ui:layout"]; - - return ( - <fieldset> - {title ? <h4>{title}</h4> : null} - {description ? <h6>{description}</h6> : null} - {layout.map((row, index) => { - return ( - <div className="row" key={index}> - {Object.keys(row).map((name, index) => { - const { doShow, ...rowProps } = row[name]; - let style = {}; - if (doShow && !doShow({ formData })) { - style = { display: "none" }; - } - if (schema.properties[name]) { - return ( - <Col {...rowProps} key={index} style={style}> - <SchemaField - name={name} - required={this.isRequired(name)} - schema={schema.properties[name]} - uiSchema={uiSchema[name]} - errorSchema={errorSchema[name]} - idSchema={idSchema[name]} - formData={formData[name]} - onChange={this.onPropertyChange(name)} - onBlur={onBlur} - registry={this.props.registry} - disabled={disabled} - readonly={readonly} - /> - </Col> - ); - } else { - const { render, ...rowProps } = row[name]; - let UIComponent = () => null; - - if (render) { - UIComponent = render; - } - - return ( - <Col {...rowProps} key={index} style={style}> - <UIComponent - name={name} - formData={formData} - errorSchema={errorSchema} - uiSchema={uiSchema} - schema={schema} - registry={this.props.registry} - /> - </Col> - ); - } - })} - </div> - ); - })} - </fieldset> - ); - } -} -export default GridField; diff --git a/apps/OpenSign/src/components/fields/SignersInput.js b/apps/OpenSign/src/components/fields/SignersInput.js index 0e9697965..af6016931 100644 --- a/apps/OpenSign/src/components/fields/SignersInput.js +++ b/apps/OpenSign/src/components/fields/SignersInput.js @@ -113,6 +113,7 @@ const SignersInput = (props) => { value={selected} onChange={onChange} closeMenuOnSelect={false} + required={props.required} /> </div> <div diff --git a/apps/OpenSign/src/components/fields/TimeWidget.js b/apps/OpenSign/src/components/fields/TimeWidget.js deleted file mode 100644 index 660840fa7..000000000 --- a/apps/OpenSign/src/components/fields/TimeWidget.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; - -function TimeWidget(props) { - const { - onChange, - registry: { - widgets: { BaseInput } - } - } = props; - return ( - <BaseInput - type="time" - {...props} - onChange={(value) => onChange(value || undefined)} - /> - ); -} - -if (process.env.NODE_ENV !== "production") { - TimeWidget.propTypes = { - value: PropTypes.string - }; -} - -export default TimeWidget; diff --git a/apps/OpenSign/src/constant/const.js b/apps/OpenSign/src/constant/const.js index 33e711591..b2401db56 100644 --- a/apps/OpenSign/src/constant/const.js +++ b/apps/OpenSign/src/constant/const.js @@ -1,5 +1,6 @@ export const contactCls = "contracts_Contactbook"; export const templateCls = "contracts_Template"; +export const documentCls = "contracts_Document"; export const rejectBtn = "bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]"; export const submitBtn = diff --git a/apps/OpenSign/src/json/FormJson.js b/apps/OpenSign/src/json/FormJson.js index eaa5818b3..a8f8bc792 100644 --- a/apps/OpenSign/src/json/FormJson.js +++ b/apps/OpenSign/src/json/FormJson.js @@ -1,249 +1,34 @@ -import Parse from "parse"; +import { documentCls, templateCls } from "../constant/const"; export const formJson = (id) => { let formData; //json form for signYourself if (id === "sHAnZphf69") { formData = { - jsonSchema: { - title: "Sign Yourself", - description: "", - type: "object", - required: ["URL", "Name"], - properties: { - URL: { - type: "string", - title: "Select Document", - filetypes: [], - maxfilesizeKB: "10000", - uploadtype: "regular", - helpbody: "", - helplink: "" - }, - Name: { - type: "string", - title: "Title", - maxLength: 50 - }, - Description: { - type: "string", - title: "Description", - maxLength: 500 - }, - Folder: { - title: "Folder", - parent: null, - data: { - ClassName: "contracts_Document", - FolderNameField: "Name", - FolderTypeField: "Type", - FolderTypeValue: "Folder", - FolderDescription: "Description", - ParentFolderField: "Folder", - FormId: "YjIB7W7Xs6", - Query: 'where={"Folder":{"$exists":false},"Type":"Folder"}' - } - }, - ExtUserPtr: { - data: { - valueKey: "objectId", - isPointer: true - } - } - } - }, - uiSchema: { - URL: { - "ui:field": "FileUpload" - }, - Description: { - "ui:widget": "textarea", - "ui:options": { - rows: 2 - } - }, - Note: { - "ui:widget": "textarea", - "ui:options": { - rows: 2 - } - }, - Folder: { - "ui:field": "FolderComponent" - }, - ExtUserPtr: { - "ui:field": "HiddenField" - } - }, - userSchema: {}, - rules: null, - noValidate: false, - liveValidate: false, - isRegisterForm: false, - help: { htmlbody: "" }, - description: "", - class: "contracts_Document", - buttons: { - add: { - resetText: "Reset", - submitText: "Submit" - }, - edit: { submitText: "Update", cancelText: "Cancel" } - }, - formACL: { - "#currentUser#": { read: true, write: true }, - "*": { read: true, write: true } - }, - redirect_id: - "remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/signaturePdf", - success_message: "Success!", - success_redirect: "Microapp", - validFunction: - "ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ==" + title: "Sign Yourself", + redirectRoute: "signaturePdf", + msgVar: "Document", + Cls: documentCls }; - return formData; } //json form for request signature else if (id === "8mZzFxbG1z") { - const user = Parse.User.current(); - const userPtr = JSON.stringify({ - __type: "Pointer", - className: "_User", - objectId: user.id - }); formData = { - jsonSchema: { - title: "Request signatures", - description: "", - type: "object", - required: ["URL", "Name", "Note", "TimeToCompleteDays", "Signers"], - properties: { - URL: { - type: "string", - title: "Select Document", - filetypes: [], - maxfilesizeKB: "5000", - uploadtype: "regular", - helpbody: "", - helplink: "" - }, - Name: { - type: "string", - title: "Title", - maxLength: 100 - }, - Description: { - type: "string", - title: "Description", - maxLength: 500 - }, - Signers: { - type: "array", - title: "Signers", - isSortable: false, - selectAll: false, - selectedData: null, - data: { - class: "contracts_Contactbook", - displayKey: "Name", - valueKey: "objectId", - query: `where={"CreatedBy":${userPtr},"IsDeleted":{"$ne":true}}&keys=Name`, - isPointer: true, - helpbody: "", - helplink: "", - quickAddFormId: "qUGywSWd8e" - } - }, - Note: { - type: "string", - title: "Note", - default: "Please review and sign this document", - maxLength: 500 - }, - Folder: { - title: "Folder", - data: { - ClassName: "contracts_Document", - FolderNameField: "Name", - FolderTypeField: "Type", - FolderTypeValue: "Folder", - FolderDescription: "Description", - ParentFolderField: "Folder", - FormId: "YjIB7W7Xs6", - Query: 'where={"Folder":{"$exists":false},"Type":"Folder"}' - } - }, - TimeToCompleteDays: { - type: "number", - title: "Time To Complete (Days)", - default: 15, - maxLength: 5000 - }, - ExtUserPtr: { - data: { - valueKey: "objectId", - isPointer: true - } - } - } - }, - uiSchema: { - URL: { - "ui:field": "FileUpload" - }, - Description: { - "ui:widget": "textarea", - "ui:options": { - rows: 2 - } - }, - Note: { - "ui:widget": "textarea", - "ui:options": { - rows: 2 - } - }, - Signers: { - "ui:field": "MultiSelectField" - }, - Folder: { - "ui:field": "FolderComponent" - }, - TimeToCompleteDays: { - "ui:placeholder": "No. of days", - "ui:widget": "updown" - }, - ExtUserPtr: { - "ui:field": "HiddenField" - } - }, - userSchema: {}, - rules: null, - noValidate: false, - liveValidate: false, - isRegisterForm: false, - help: { htmlbody: "" }, - description: "", - class: "contracts_Document", - buttons: { - add: { - resetText: "Reset", - submitText: "Submit" - }, - edit: { submitText: "Update", cancelText: "Cancel" } - }, - formACL: { - "#currentUser#": { read: true, write: true }, - "*": { read: true, write: true } - }, - redirect_id: - "remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/placeHolderSign", - success_message: "Success!", - success_redirect: "Microapp", - validFunction: - "ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ==" + title: "Request Signature", + msgVar: "Document", + redirectRoute: "placeHolderSign", + Cls: documentCls, + signers: true + }; + return formData; + } //json form for template + else if (id === "template") { + formData = { + title: "New Template", + redirectRoute: "template", + msgVar: "Template", + Cls: templateCls }; - return formData; } //json form for create new folder diff --git a/apps/OpenSign/src/primitives/TemplateForm.js b/apps/OpenSign/src/primitives/TemplateForm.js deleted file mode 100644 index 5fa592870..000000000 --- a/apps/OpenSign/src/primitives/TemplateForm.js +++ /dev/null @@ -1,336 +0,0 @@ -import React, { useState } from "react"; -import sanitizeFileName from "./sanitizeFileName"; -import Parse from "parse"; -import DropboxChooser from "../components/fields/DropboxChoose"; -import Alert from "./Alert"; -import SelectFolder from "../components/fields/SelectFolder"; -// import SignersInput from "../components/fields/SignersInput"; -import Title from "../components/Title"; -import { useNavigate } from "react-router-dom"; -import { templateCls } from "../constant/const"; - -const TemplateForm = () => { - const navigate = useNavigate(); - const [signers, setSigners] = useState([]); - const [folder, setFolder] = useState({ ObjectId: "", Name: "" }); - const [formData, setFormData] = useState({ - Name: "", - Description: "", - Note: "Please review and sign this document" - }); - const [fileupload, setFileUpload] = useState([]); - const [fileload, setfileload] = useState(false); - const [percentage, setpercentage] = useState(0); - const [isAlert, setIsAlert] = useState(false); - const [isSubmit, setIsSubmit] = useState(false); - const [isErr, setIsErr] = useState(""); - const handleStrInput = (e) => { - setFormData({ ...formData, [e.target.name]: e.target.value }); - }; - - const handleFileInput = (e) => { - setpercentage(0); - try { - let files = e.target.files; - if (typeof files[0] !== "undefined") { - const mb = Math.round(files[0].bytes / Math.pow(1024, 2)); - if (mb > 10) { - alert( - `The selected file size is too large. Please select a file less than ${Math.round( - 10 - )} MB` - ); - return; - } - - handleFileUpload(files[0]); - } else { - alert("Please select file."); - return false; - } - } catch (error) { - alert(error.message); - return false; - } - }; - - const handleFileUpload = async (file) => { - Parse.serverURL = process.env.REACT_APP_SERVERURL; - Parse.initialize(process.env.REACT_APP_APPID); - setfileload(true); - const fileName = file.name; - const name = sanitizeFileName(fileName); - const pdfFile = file; - const parseFile = new Parse.File(name, pdfFile); - - try { - const response = await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round((loaded * 100) / total); - setpercentage(percentCompleted); - } - } - }); - - // The response object will contain information about the uploaded file - // You can access the URL of the uploaded file using response.url() - setFileUpload(response.url()); - setfileload(false); - if (response.url()) { - return response.url(); - } - } catch (error) { - setfileload(false); - setpercentage(0); - console.error("Error uploading file:", error); - } - }; - - const dropboxSuccess = async (files) => { - setfileload(true); - const file = files[0]; - const url = file.link; - const mb = Math.round(file.bytes / Math.pow(1024, 2)); - - if (mb > 10) { - setTimeout(() => { - alert( - `The selected file size is too large. Please select a file less than 10 MB` - ); - }, 500); - return; - } else { - const name = sanitizeFileName(file.name); - - const parseFile = new Parse.File(name, { uri: url }); - - try { - const response = await parseFile.save({ - progress: (progressValue, loaded, total, { type }) => { - if (type === "upload" && progressValue !== null) { - const percentCompleted = Math.round((loaded * 100) / total); - setpercentage(percentCompleted); - } - } - }); - setFileUpload(response.url()); - setfileload(false); - - if (response.url()) { - return response.url(); - } - } catch (error) { - setfileload(false); - setpercentage(0); - console.error("Error uploading file:", error); - } - } - }; - const dropboxCancel = async () => {}; - const handleSubmit = async (e) => { - e.preventDefault(); - setIsSubmit(true); - try { - const currentUser = Parse.User.current(); - const template = new Parse.Object(templateCls); - Object.entries(formData).forEach((item) => - template.set(item[0], item[1]) - ); - template.set("URL", fileupload); - template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); - if (folder && folder.ObjectId) { - template.set("Folder", { - __type: "Pointer", - className: templateCls, - objectId: folder.ObjectId - }); - } - if (signers && signers.length > 0) { - template.set("Signers", signers); - } - const ExtCls = JSON.parse(localStorage.getItem("Extand_Class")); - template.set("ExtUserPtr", { - __type: "Pointer", - className: "contracts_Users", - objectId: ExtCls[0].objectId - }); - - const res = await template.save(); - if (res) { - setSigners([]); - setFolder({ ObjectId: "", Name: "" }); - setFormData({ - Name: "", - Description: "", - Note: "" - }); - setFileUpload([]); - setpercentage(0); - navigate( - "/asmf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/template/" + - res.id - ); - } - } catch (err) { - console.log("err ", err); - setIsErr(true); - } finally { - setIsAlert(true); - setTimeout(() => { - setIsAlert(false); - }, 1000); - setIsSubmit(false); - } - }; - - const handleFolder = (data) => { - setFolder(data); - }; - // const handleSigners = (data) => { - // if (data && data.length > 0) { - // const updateSigners = data.map((x) => ({ - // __type: "Pointer", - // className: "contracts_Contactbook", - // objectId: x - // })); - // setSigners(updateSigners); - // } - // }; - - const handleReset = () => { - setSigners([]); - setFolder({ ObjectId: "", Name: "" }); - setFormData({ - Name: "", - Description: "", - Note: "" - }); - setFileUpload([]); - setpercentage(0); - }; - return ( - <div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50"> - <Title title="New Template" /> - {isAlert && ( - <Alert type={isErr ? "danger" : "success"}> - {isErr - ? "Something went wrong please try again!" - : "Template created successfully!"} - </Alert> - )} - <form onSubmit={handleSubmit}> - <h1 className="text-[20px] font-semibold mb-4">New Template</h1> - {fileload && ( - <div className="flex items-center gap-x-2"> - <div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200"> - <div - className="h-2 rounded-full bg-blue-500" - style={{ width: `${percentage}%` }} - ></div> - </div> - <span className="text-black text-sm">{percentage}%</span> - </div> - )} - <div className="text-xs"> - <label className="block"> - File<span className="text-red-500 text-[13px]">*</span> - </label> - {fileupload.length > 0 ? ( - <div className="flex gap-2 justify-center items-center"> - <div className="flex justify-between items-center px-2 py-2 w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]"> - <div className="break-all"> - file selected : {fileupload?.split("/")[3]?.split("_")[1]} - </div> - <div - onClick={() => { - setFileUpload([]); - }} - className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500" - > - <i className="fa-solid fa-xmark"></i> - </div> - </div> - {process.env.REACT_APP_DROPBOX_API_KEY && ( - <DropboxChooser - onSuccess={dropboxSuccess} - onCancel={dropboxCancel} - /> - )} - </div> - ) : ( - <div className="flex gap-2 justify-center items-center"> - <input - type="file" - className="bg-white px-2 py-1.5 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" - onChange={(e) => handleFileInput(e)} - accept="application/pdf,application/vnd.ms-excel" - required - /> - {process.env.REACT_APP_DROPBOX_API_KEY && ( - <DropboxChooser - onSuccess={dropboxSuccess} - onCancel={dropboxCancel} - /> - )} - </div> - )} - </div> - <div className="text-xs mt-2"> - <label className="block"> - Title<span className="text-red-500 text-[13px]">*</span> - </label> - <input - name="Name" - className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" - value={formData.Name} - onChange={(e) => handleStrInput(e)} - required - /> - </div> - <div className="text-xs mt-2"> - <label className="block"> - Note<span className="text-red-500 text-[13px]">*</span> - </label> - <input - name="Note" - className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" - value={formData.Note} - onChange={(e) => handleStrInput(e)} - required - /> - </div> - <div className="text-xs mt-2"> - <label className="block">Description</label> - <input - name="Description" - className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" - value={formData.Description} - onChange={(e) => handleStrInput(e)} - /> - </div> - {/* <SignersInput onChange={handleSigners} /> */} - <SelectFolder onSuccess={handleFolder} folderCls={templateCls} /> - <div className="flex items-center mt-3 gap-2 text-white"> - <button - className={`${ - isSubmit && "cursor-progress" - } bg-[#1ab6ce] rounded-sm shadow-md text-[14px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`} - type="submit" - disabled={isSubmit} - > - Submit - </button> - <div - className="bg-[#188ae2] rounded-sm shadow-md text-[14px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none" - onClick={() => handleReset()} - > - Reset - </div> - </div> - </form> - </div> - ); -}; - -export default TemplateForm; diff --git a/apps/OpenSign/src/redux/actions/index.js b/apps/OpenSign/src/redux/actions/index.js index afec8161d..fae7642ed 100644 --- a/apps/OpenSign/src/redux/actions/index.js +++ b/apps/OpenSign/src/redux/actions/index.js @@ -124,8 +124,7 @@ export const login = (username, password) => async (dispatch) => { const currentUser = Parse.User.current(); await Parse.Cloud.run("getUserDetails", { email: currentUser.get("email") - }) - .then( + }).then( (results) => { let userinfo = results.toJSON(); if (userinfo.TenantId) { @@ -257,12 +256,6 @@ export const removeFromCart = (val) => async (dispatch) => { }); }; -export const onChangeLevel1Dropdown = (id, name) => async (dispatch) => { - localStorage.setItem(`_dd${name}`, id); - let _data = { [name]: `${id}` }; - dispatch({ type: "Level1_Dropdown", payload: _data }); -}; - export const onChangeLevel2Dropdown = (id, name) => async (dispatch) => { localStorage.setItem(`_dd${name}`, id); let _data = { [name]: `${id}` }; diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index 2c6c67709..da272e27f 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -1,1244 +1,243 @@ -import React, { Component } from "react"; -import { connect } from "react-redux"; -import { - removeState, - removeLevel2State, - removeLevel3State -} from "../redux/actions/index"; -import Engine from "json-rules-engine-simplified"; -import applyRules from "rjsf-conditionals"; -import Form from "@rjsf/core"; -import validator from "@rjsf/validator-ajv8"; -import LayoutField from "../components/fields/Rjsf-layout"; -import "../styles/form.css"; -import "../styles/toast.css"; -import Parse from "parse"; -import "../styles/loader.css"; -import TimeWidget from "../components/fields/TimeWidget"; -import axios from "axios"; +import React, { useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import HiddenField from "../components/fields/HiddenField"; -import MultiSelectField from "../components/fields/MultiSelectField"; -import ErrorBoundary from "../components/ErrorBoundary"; -import FileUpload from "../components/fields/FileUpload"; -import TreeWidget from "../components/TreeWidget"; -import parse from "html-react-parser"; -import Title from "../components/Title"; import { formJson } from "../json/FormJson"; -import TemplateForm from "../primitives/TemplateForm"; -const widget = { - TimeWidget: TimeWidget -}; -const fields = () => { - return { - layout: LayoutField, - FileUpload: FileUpload, - HiddenField: HiddenField, - MultiSelectField: MultiSelectField, - FolderComponent: TreeWidget - }; -}; +import AddUser from "../components/AddUser"; +import sanitizeFileName from "../primitives/sanitizeFileName"; +import Parse from "parse"; +import DropboxChooser from "../components/fields/DropboxChoose"; +import Alert from "../primitives/Alert"; +import SelectFolder from "../components/fields/SelectFolder"; +import SignersInput from "../components/fields/SignersInput"; +import Title from "../components/Title"; -function FormBuilderFn(props) { +function Form() { const { id } = useParams(); - const navigate = useNavigate(); - if (id === "template") { - return <TemplateForm />; + + if (id === "lM0xRnM3iE") { + return <AddUser />; } else { - return ( - <FormBuilder - removeState={props.removeState} - removeLevel2State={props.removeLevel2State} - removeLevel3State={props.removeLevel3State} - id={id} - navigate={navigate} - /> - ); + const config = formJson(id) || {}; + return <Forms {...config} />; } } -class FormBuilder extends Component { - state = { - schema: {}, - ui_schema: {}, - extraActions: undefined, - rules: [], - isAppRequest: false, - formData: {}, - persistentFields: [], - successMassage: "Record inserted successfully.", - title: "", - active: true, - buttons: {}, - schemaState: {}, - noValidate: false, - liveValidate: false, - _validate: null, - userSchema: {}, - loading: false, - parseBaseUrl: localStorage.getItem("baseUrl"), - parseAppId: localStorage.getItem("parseAppId"), - toastColor: "#5cb85c", - toastDescription: "", - redirect_type: "", - redirect_id: "", - FormACL: null, - help: "", - link: "" + +const Forms = (props) => { + const navigate = useNavigate(); + const [signers, setSigners] = useState([]); + const [folder, setFolder] = useState({ ObjectId: "", Name: "" }); + const [formData, setFormData] = useState({ + Name: "", + Description: "", + Note: "Please review and sign this document", + TimeToCompleteDays: 15 + }); + const [fileupload, setFileUpload] = useState([]); + const [fileload, setfileload] = useState(false); + const [percentage, setpercentage] = useState(0); + const [isAlert, setIsAlert] = useState(false); + const [isSubmit, setIsSubmit] = useState(false); + const [isErr, setIsErr] = useState(""); + const handleStrInput = (e) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); }; - async getForm(id) { - this.setState({ - loading: true - }); + const handleFileInput = (e) => { + setpercentage(0); try { - const results = formJson(id); - // console.log("custom result",results) - if (results) { - const resultjson = results; - if (resultjson.userSchema !== undefined) { - this.setState({ - userSchema: resultjson.userSchema - }); - } - for (let [value] of Object.entries(resultjson.jsonSchema.properties)) { - if (typeof value === "object") { - for (let [k, v] of Object.entries(value)) { - if (k === "format" && v === "date") { - let today = new Date(); - let date = - today.getFullYear() + - "-" + - ("0" + (today.getMonth() + 1)).slice(-2) + - "-" + - ("0" + today.getDate()).slice(-2); - value.default = date; - } - if (k === "component" && v === "DateTime") { - value.default = new Date().toISOString(); - } - } - } + let files = e.target.files; + if (typeof files[0] !== "undefined") { + const mb = Math.round(files[0].bytes / Math.pow(1024, 2)); + if (mb > 10) { + alert( + `The selected file size is too large. Please select a file less than ${Math.round( + 10 + )} MB` + ); + return; } - let txt, - link, - successMsg, - _rules = [], - persistentFields = [], - _extraActions = {}; - if (resultjson.help) { - if (resultjson.help.htmlbody) { - txt = resultjson.help.htmlbody; - } - if (resultjson.help.link) { - link = resultjson.help.link; - } - } - if (resultjson.rules) { - _rules = resultjson.rules; - } - if (resultjson.persistentFields) { - persistentFields = resultjson.persistentFields; - } - if (resultjson.extraActions) { - _extraActions = this.setExtraActions(resultjson.extraActions); - } - if (resultjson.success_message) { - successMsg = resultjson.success_message; - } else { - successMsg = this.state.successMassage; - } - let _jsonSchema = JSON.stringify(resultjson.jsonSchema); - _jsonSchema = _jsonSchema.replace("#$", "$"); - _jsonSchema = _jsonSchema.replace("#*", "$"); - _jsonSchema = _jsonSchema.replace("_DOT_", "."); - let _replaceJSONSchema = JSON.parse(_jsonSchema); - this.setState({ - redirect_type: resultjson.success_redirect, - redirect_id: resultjson.redirect_id, - FormACL: resultjson.formACL, - help: txt, - link: link, - persistentFields: persistentFields, - successMassage: successMsg, - buttons: resultjson.buttons.add, - schemaState: _replaceJSONSchema, - ui_schema: resultjson.uiSchema, - rules: _rules, - extraActions: _extraActions, - title: resultjson.class, - _validate: resultjson.validFunction, - noValidate: resultjson.noValidate, - liveValidate: resultjson.liveValidate && resultjson.liveValidate, - loading: false - }); - localStorage.setItem( - "jsonschema", - JSON.stringify(resultjson.jsonSchema) - ); + handleFileUpload(files[0]); } else { - alert("form not found"); - } - } catch (e) { - if (e.message === "Invalid session token") { - let appdata = localStorage.getItem("userSettings"); - let applogo = localStorage.getItem("appLogo"); - let appName = localStorage.getItem("appName"); - let defaultmenuid = localStorage.getItem("defaultmenuid"); - let PageLanding = localStorage.getItem("PageLanding"); - let domain = localStorage.getItem("domain"); - let _appName = localStorage.getItem("_appName"); - let baseUrl = localStorage.getItem("BaseUrl12"); - let appid = localStorage.getItem("AppID12"); - localStorage.clear(); - localStorage.setItem("appLogo", applogo); - localStorage.setItem("appName", appName); - localStorage.setItem("_appName", _appName); - localStorage.setItem("defaultmenuid", defaultmenuid); - localStorage.setItem("PageLanding", PageLanding); - localStorage.setItem("domain", domain); - localStorage.setItem("userSettings", appdata); - localStorage.setItem("BaseUrl12", baseUrl); - localStorage.setItem("AppID12", appid); - this.props.navigate(`/`); + alert("Please select file."); + return false; } - console.log(e.message); - console.error("Problem", e); - this.setState({ - loading: false - }); - } - } - - wrap = (s) => "{ return " + s + " };"; - - // func = new Function(wrap(body)); - - dynamicValidate = (formData, errors) => { - try { - let body = atob(this.state._validate); - let res = new Function(this.wrap(body)) - .call(null) - .call(null, formData, errors); - return res; } catch (error) { - console.log(error); + alert(error.message); + return false; } }; - setExtraActions = (actions) => { + const handleFileUpload = async (file) => { + Parse.serverURL = process.env.REACT_APP_SERVERURL; + Parse.initialize(process.env.REACT_APP_APPID); + setfileload(true); + const fileName = file.name; + const name = sanitizeFileName(fileName); + const pdfFile = file; + const parseFile = new Parse.File(name, pdfFile); + try { - let result = {}; - Object.entries(actions).forEach(([key, value]) => { - let body = atob(value); - let res = new Function(this.wrap(body)).call(null); - result[key] = res; + const response = await parseFile.save({ + progress: (progressValue, loaded, total, { type }) => { + if (type === "upload" && progressValue !== null) { + const percentCompleted = Math.round((loaded * 100) / total); + setpercentage(percentCompleted); + } + } }); - return result; + + // The response object will contain information about the uploaded file + // You can access the URL of the uploaded file using response.url() + setFileUpload(response.url()); + setfileload(false); + if (response.url()) { + return response.url(); + } } catch (error) { - console.log(error); + setfileload(false); + setpercentage(0); + console.error("Error uploading file:", error); } }; - handleSubmit = async ({ formData }) => { - this.setState({ active: false, loading: true }); - if ( - this.state.userSchema && - Object.entries(this.state.userSchema).length !== 0 && - this.state.userSchema.constructor === Object - ) { - try { - let RowData = formData; - RowData && - Object.entries(RowData).forEach(([key, value]) => { - if (typeof value === "string") { - RowData[key] = value.trim(); - } - }); - let UserData = {}; - let RoleField = ""; - let _scanData = this.state.schemaState; - if (_scanData.dependencies) { - Object.keys(_scanData.dependencies).forEach((key) => { - if (_scanData.dependencies[key].oneOf) { - _scanData.dependencies[key].oneOf.forEach((val) => { - Object.keys(val.properties).forEach((k) => { - if (typeof val.properties[k] === "object") { - if (val.properties[k].format === "date") { - if (RowData[k]) { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - } - if (val.properties[k].component === "HtmlEditor") { - if (RowData[k]) { - let newHtml = RowData[k] - .replace(/<p[^>]*>/g, "") - .replace(/<\/p>/g, " "); - RowData[k] = newHtml; - } - } - if (val.properties[k].component === "DateTime") { - if (RowData[k]) { - let newDate11 = new Date(RowData[k]); - RowData[k] = newDate11; - } - } - if (val.properties[k].component === "CurrencyInput") { - if (val.properties[k].currencyColumn) { - RowData[`${val.properties[k].currencyColumn}`] = - val.properties[k].defaultcurrency; - } - } - if (val.properties[k].type === "string") { - if (typeof RowData[k] === "string") - RowData[k] = RowData[k].trim(); - } - if (val.properties[k].data !== undefined) { - if (val.properties[k].data.isPointer) { - let pointer = undefined; - if (val.properties[k].data.class) { - if (val.properties[k].data.savePointerClass) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: - val.properties[k].data.savePointerClass, - objectId: RowData[k] - }; - } - } else { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: val.properties[k].data.class, - objectId: RowData[k] - }; - } - } - } else { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - } - RowData[k] = pointer; - } - if (val.properties[k].data.FolderTypeValue) { - if (RowData[k]) { - let obj = { - __type: "Pointer", - className: val.properties[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - } - } - }); - }); - } - }); - } - let _userScheama = this.state.userSchema; - Object.keys(_scanData).forEach(function (key) { - let _dd = _scanData[key]; - typeof _dd === "object" && - Object.keys(_dd).forEach(function (k) { - if (_dd[k].type === "array" && _dd[k].items) { - let _prop = _dd[k].items.properties; - - if (_prop && Array.isArray(RowData[k])) { - let newRow = []; - RowData[k].forEach((t) => { - let _newObj = t; - if (typeof t === "object") { - Object.keys(_prop).forEach(function (l) { - if (_prop[l].data && _prop[l].data.isPointer) { - if (typeof t[l] === "object") { - let obj = { - __type: "Pointer", - className: _prop[l].data.class, - objectId: t[l].objectId - }; - _newObj = { ..._newObj, [l]: obj }; - } else { - let obj = { - __type: "Pointer", - className: _prop[l].data.class, - objectId: t[l] - }; - _newObj = { ..._newObj, [l]: obj }; - } - } - }); - } - newRow.push(_newObj); - }); - RowData[k] = newRow; - } - } - - if (_dd[k].component === "AutoSuggest" && _dd[k].isPointer) { - if (RowData[k]) { - let pointer = { - __type: "Pointer", - className: _dd[k].class, - objectId: RowData[k] - }; - RowData[k] = pointer; - } - } - if (_dd[k].format === "date") { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - if (_dd[k].component === "CurrencyInput") { - RowData[`${_dd[k].currencyColumn}`] = _dd[k].defaultcurrency; - } - if (_dd[k].component === "HtmlEditor") { - if (RowData[k]) { - let newHtml = RowData[k] - .replace(/<p[^>]*>/g, "") - .replace(/<\/p>/g, " "); - RowData[k] = newHtml; - } - } - if (_dd[k].component === "DateTime") { - let newDate; - if (!RowData[k]) { - newDate = new Date(); - } else { - newDate = new Date(RowData[k]); - } - RowData[k] = newDate; - } - if (_dd[k].data !== undefined) { - if (_dd[k].data.isPointer) { - let pointer = undefined; - if (_dd[k].data.savePointerClass) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: _dd[k].data.savePointerClass, - objectId: RowData[k] - }; - RowData[k] = pointer; - } - } else if (RowData[k]) { - if (_dd[k].data.class) { - pointer = { - __type: "Pointer", - className: _dd[k].data.class, - objectId: RowData[k] - }; - } else { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - - RowData[k] = pointer; - } - } - if (_dd[k].data.FolderTypeValue) { - if (RowData[k]) { - let obj = { - __type: "Pointer", - className: _dd[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - } - if (_dd[k].type === "string") { - let d = RowData[k]; - if (typeof d === "string") { - RowData[k] = d.trim(); - } - } - }); - }); + const dropboxSuccess = async (files) => { + setfileload(true); + const file = files[0]; + const url = file.link; + const mb = Math.round(file.bytes / Math.pow(1024, 2)); - Object.keys(_userScheama).forEach(function (kkey) { - Object.keys(RowData).forEach(function (_k) { - if (_userScheama[kkey].startsWith("$")) { - let _uuu = _userScheama[kkey].replace("$", ""); - if (kkey === "Role" || kkey === "role") { - if (RowData[_uuu] === RowData[_k]) { - RoleField = RowData[_uuu]; - } - } else if (_uuu === _k) { - UserData[kkey] = RowData[_k]; - } - } else { - RoleField = _userScheama[kkey]; - } - }); - }); - Parse.serverURL = this.state.parseBaseUrl; - Parse.initialize(this.state.parseAppId); - var _users = Parse.Object.extend("User"); - var _user = new _users(); - let _uname = UserData.name; - _user.set("name", _uname.toString().trim()); - if (UserData.username) { - let _u_un = UserData.username; - _user.set("username", _u_un.toString().trim()); - if (UserData.email) { - let _email = UserData.email; - _user.set("email", _email.trim()); - } - } else if (UserData.email) { - let _email = UserData.email; - _user.set("email", _email.trim()); - _user.set("username", _email.trim()); - } else { - _user.set("username", UserData.phone.toString().trim()); - } - _user.set("phone", UserData.phone); - _user.set("password", UserData.password); - _user.save().then( - (u) => { - let roleurl = `${this.state.parseBaseUrl}functions/AddUserToRole`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": this.state.parseAppId, - sessionToken: localStorage.getItem("accesstoken") - }; - let body = { - appName: localStorage.getItem("_appName"), - roleName: RoleField, - userId: u.id - }; - axios.post(roleurl, body, { headers: headers }).then(() => { - const currentUser = Parse.User.current(); - let _fname = this.state.title; - var forms = Parse.Object.extend(_fname); - var form = new forms(); - form.set( - "CreatedBy", - Parse.User.createWithoutData(currentUser.id) - ); - if (localStorage.getItem("TenetId")) { - form.set("TenantId", { - __type: "Pointer", - className: "partners_Tenant", - objectId: localStorage.getItem("TenetId") - }); - } - form.set("UserId", u); - form.set("UserRole", RoleField); - if (this.state["FormACL"]) { - let ACL = {}; - for (let [key, value] of Object.entries( - this.state["FormACL"] - )) { - if (key === "*") { - ACL[key] = value; - } - if (key === "#currentUser#") { - ACL[Parse.User.current().id] = value; - } - if (key.startsWith("role")) { - ACL[key] = value; - } - } - form.setACL(new Parse.ACL(ACL)); - } - form.save(RowData).then( - () => { - let filtered = {}; - if (this.state.redirect_type === "clearData") { - if ( - this.state.persistentFields && - this.state.persistentFields.length - ) { - filtered = Object.keys(RowData) - .filter((key) => - this.state.persistentFields.includes(key) - ) - .reduce((obj, key) => { - obj[key] = RowData[key]; - return obj; - }, {}); - } - } else { - RowData = {}; - } - this.setState( - { - formData: filtered, - active: true, - loading: false, - toastColor: "#5cb85c", - toastDescription: this.state.successMassage - }, - () => { - let redirect_type = this.state.redirect_type; - let redirect_id = this.state.redirect_id; - this.props.removeState(); - this.props.removeLevel2State(); - this.props.removeLevel3State(); - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - if (redirect_type === "Form") { - this.props.navigate(`/form/${redirect_id}`); - } else if (redirect_type === "Report") { - this.props.navigate(`/report/${redirect_id}`); - } else if (redirect_type === "Dashboard") { - this.props.navigate(`/dashboard/${redirect_id}`); - } else if (redirect_type === "Url") { - window.location = redirect_id; - } else if (redirect_type === "Microapp") { - this.props.navigate(`/asmf/${redirect_id}`); - } - }, 2000); - } - ); - }, - (error) => { - console.log("error", error.message); - this.setState({ - loading: false, - active: true, - toastColor: "#d9534f", - toastDescription: error.message - }); - - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 2000); - } - ); - }); - }, - async (error) => { - if (error.code === 202) { - let params; - if (UserData.username) { - params = { username: UserData.username }; - } else if (UserData.email) { - params = { email: UserData.email }; - } else { - params = { username: UserData.phone }; - } - const userRes = await Parse.Cloud.run("getUserId", params); - try { - let _emp = { - __type: "Pointer", - className: "_User", - objectId: userRes.id - }; - let roleurl = `${this.state.parseBaseUrl}functions/AddUserToRole`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": this.state.parseAppId, - sessionToken: localStorage.getItem("accesstoken") - }; - let body = { - appName: localStorage.getItem("_appName"), - roleName: RoleField, - userId: userRes.id - }; - await axios - .post(roleurl, body, { headers: headers }) - .then(() => { - const currentUser = Parse.User.current(); - let _fname = this.state.title; - var forms = Parse.Object.extend(_fname); - var form = new forms(); - form.set( - "CreatedBy", - Parse.User.createWithoutData(currentUser.id) - ); - if (localStorage.getItem("TenetId")) { - form.set("TenantId", { - __type: "Pointer", - className: "partners_Tenant", - objectId: localStorage.getItem("TenetId") - }); - } - form.set("UserId", _emp); - form.set("UserRole", RoleField); - if (this.state["FormACL"]) { - let ACL = {}; - for (let [key, value] of Object.entries( - this.state["FormACL"] - )) { - if (key === "*") { - ACL[key] = value; - } - if (key === "#currentUser#") { - ACL[Parse.User.current().id] = value; - } - if (key.startsWith("role")) { - ACL[key] = value; - } - } - form.setACL(new Parse.ACL(ACL)); - } - form.save(RowData).then( - () => { - let filtered = {}; - if (this.state.redirect_type === "clearData") { - if ( - this.state.persistentFields && - this.state.persistentFields.length - ) { - filtered = Object.keys(RowData) - .filter((key) => - this.state.persistentFields.includes(key) - ) - .reduce((obj, key) => { - obj[key] = RowData[key]; - return obj; - }, {}); - } - } else { - RowData = {}; - } - this.setState( - { - formData: filtered, - active: true, - loading: false, - toastColor: "#5cb85c", - toastDescription: this.state.successMassage - }, - () => { - let redirect_type = this.state.redirect_type; - let redirect_id = this.state.redirect_id; - this.props.removeState(); - this.props.removeLevel2State(); - this.props.removeLevel3State(); - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - if (redirect_type === "Form") { - this.props.navigate(`/form/${redirect_id}`); - } else if (redirect_type === "Report") { - this.props.navigate(`/report/${redirect_id}`); - } else if (redirect_type === "Dashboard") { - this.props.navigate( - `/dashboard/${redirect_id}` - ); - } else if (redirect_type === "Url") { - window.location = redirect_id; - } else if (redirect_type === "Microapp") { - this.props.navigate(`/asmf/${redirect_id}`); - } - }, 2000); - } - ); - }, - (error) => { - this.setState({ - loading: false, - active: true, - toastColor: "#d9534f", - toastDescription: error.message - }); - - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 2000); - } - ); - }); - } catch (error) { - this.setState({ - loading: false, - active: true, - toastColor: "#d9534f", - toastDescription: error.message - }); - - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 2000); - } - } - } + if (mb > 10) { + setTimeout(() => { + alert( + `The selected file size is too large. Please select a file less than 10 MB` ); - } catch (e) { - console.log("Problem", e.message); - this.setState({ loading: false, active: true }); - } + }, 500); + return; } else { - try { - let RowData = formData; - let _scanData = this.state.schemaState; - if (_scanData.dependencies) { - Object.keys(_scanData.dependencies).forEach((key) => { - if (_scanData.dependencies[key].oneOf) { - _scanData.dependencies[key].oneOf.forEach((val) => { - Object.keys(val.properties).forEach((k) => { - if (typeof val.properties[k] === "object") { - if (val.properties[k].format === "date") { - if (RowData[k]) { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - } - if (val.properties[k].component === "HtmlEditor") { - if (RowData[k]) { - let newHtml = RowData[k] - .replace(/<p[^>]*>/g, "") - .replace(/<\/p>/g, " "); - RowData[k] = newHtml; - } - } - if (val.properties[k].component === "DateTime") { - if (RowData[k]) { - let newDate11 = new Date(RowData[k]); - RowData[k] = newDate11; - } - } - if (val.properties[k].component === "CurrencyInput") { - if (val.properties[k].currencyColumn) { - RowData[`${val.properties[k].currencyColumn}`] = - val.properties[k].defaultcurrency; - } - } - if (val.properties[k].type === "string") { - if (typeof RowData[k] === "string") - RowData[k] = RowData[k].trim(); - } - if (val.properties[k].data !== undefined) { - if (val.properties[k].data.isPointer) { - let pointer = undefined; - if (val.properties[k].data.savePointerClass) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: - val.properties[k].data.savePointerClass, - objectId: RowData[k] - }; - } - } else if (val.properties[k].data.class) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: val.properties[k].data.class, - objectId: RowData[k] - }; - } - } else { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - } - - RowData[k] = pointer; - } - if (val.properties[k].data.FolderTypeValue) { - if (RowData[k]) { - let obj = { - __type: "Pointer", - className: val.properties[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - } - } - }); - }); - } - }); - } - Object.keys(_scanData).forEach(function (key) { - let _dd = _scanData[key]; - if (typeof _dd === "object") { - Object.keys(_dd).forEach(function (k) { - if (_dd[k].type === "array" && _dd[k].items) { - let _prop = _dd[k].items.properties; - if (_prop && Array.isArray(RowData[k])) { - let newRow = []; - RowData[k].forEach((t) => { - let _newObj = t; - if (typeof t === "object") { - Object.keys(_prop).forEach(function (l) { - if (_prop[l].data && _prop[l].data.isPointer) { - if (typeof t[l] === "object") { - let obj = { - __type: "Pointer", - className: _prop[l].data.class, - objectId: t[l].objectId - }; - _newObj = { ..._newObj, [l]: obj }; - } else { - let obj = { - __type: "Pointer", - className: _prop[l].data.class, - objectId: t[l] - }; - _newObj = { ..._newObj, [l]: obj }; - } - } - }); - } - newRow.push(_newObj); - }); - RowData[k] = newRow; - } - } + const name = sanitizeFileName(file.name); - if (_dd[k].component === "AutoSuggest" && _dd[k].isPointer) { - if (RowData[k]) { - let pointer = { - __type: "Pointer", - className: _dd[k].class, - objectId: RowData[k] - }; - RowData[k] = pointer; - } - } - if (_dd[k].format === "date") { - let newdate = new Date(RowData[k]); - RowData[k] = newdate; - } - if (_dd[k].component === "HtmlEditor") { - if (RowData[k]) { - let newHtml = RowData[k] - .replace(/<p[^>]*>/g, "") - .replace(/<\/p>/g, " "); - RowData[k] = newHtml; - } - } - if (_dd[k].component === "DateTime") { - let newDate11; - if (!RowData[k]) { - newDate11 = new Date(); - } else { - newDate11 = new Date(RowData[k]); - } - RowData[k] = newDate11; - } - if (_dd[k].component === "CurrencyInput") { - if (_dd[k].currencyColumn) { - RowData[`${_dd[k].currencyColumn}`] = _dd[k].defaultcurrency; - } - } - if (_dd[k].data !== undefined) { - if (_dd[k].data.isPointer) { - let pointer = undefined; - if (RowData[k] && RowData[k] !== "Select") { - if (_dd[k].type === "array") { - pointer = []; - RowData[k] && - RowData[k].forEach((a) => { - let _kk = {}; - if (_dd[k].data.savePointerClass) { - _kk = { - __type: "Pointer", - className: _dd[k].data.savePointerClass, - objectId: a - }; - } else { - _kk = { - __type: "Pointer", - className: _dd[k].data.class, - objectId: a - }; - } + const parseFile = new Parse.File(name, { uri: url }); - pointer.push(_kk); - }); - } else if (_dd[k].data.class) { - if (_dd[k].data.savePointerClass) { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: _dd[k].data.savePointerClass, - objectId: RowData[k] - }; - } - } else if (RowData[k]) { - pointer = { - __type: "Pointer", - className: _dd[k].data.class, - objectId: RowData[k] - }; - } - } else { - if (RowData[k]) { - pointer = { - __type: "Pointer", - className: localStorage.getItem("extended_class"), - objectId: RowData[k] - }; - } - } - - RowData[k] = pointer; - } - } - if (_dd[k].data.FolderTypeValue) { - if (RowData[k]) { - let obj = { - __type: "Pointer", - className: _dd[k].data.ClassName, - objectId: RowData[k] - }; - RowData[k] = obj; - } - } - } - if (_dd[k].type === "string") { - let d = RowData[k]; - if (typeof d === "string") { - RowData[k] = d.trim(); - } - } - }); + try { + const response = await parseFile.save({ + progress: (progressValue, loaded, total, { type }) => { + if (type === "upload" && progressValue !== null) { + const percentCompleted = Math.round((loaded * 100) / total); + setpercentage(percentCompleted); + } } }); - Parse.serverURL = this.state.parseBaseUrl; - Parse.initialize(this.state.parseAppId); - const currentUser = Parse.User.current(); - let _fname = this.state.title; - var forms = Parse.Object.extend(_fname); - - var form = new forms(); + setFileUpload(response.url()); + setfileload(false); - form.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); - - if (this.state["FormACL"]) { - let ACL = {}; - for (let [key, value] of Object.entries(this.state["FormACL"])) { - if (key === "*") { - ACL[key] = value; - } - if (key === "#currentUser#") { - ACL[Parse.User.current().id] = value; - } else if (key.startsWith("#")) { - let arr = key.split("#"); - let new_arr = arr.filter((x) => x !== ""); - if (new_arr.length === 2) { - let l = RowData[new_arr[0]]; - try { - const Agent = Parse.Object.extend(l.className); - const qu = new Parse.Query(Agent); - qu.equalTo("objectId", l.objectId); - qu.include(new_arr[1]); - await qu.first(); - } catch (err) { - console.error("Error while fetching Agent", err.massage); - } - } - } - if (key.startsWith("role")) { - ACL[key] = value; - } - } - form.setACL(new Parse.ACL(ACL)); + if (response.url()) { + return response.url(); } - - form.save(RowData).then( - (form) => { - let filtered = {}; - if (this.state.redirect_type === "clearData") { - if ( - this.state.persistentFields && - this.state.persistentFields.length - ) { - filtered = Object.keys(RowData) - .filter((key) => this.state.persistentFields.includes(key)) - .reduce((obj, key) => { - obj[key] = RowData[key]; - return obj; - }, {}); - } - } else { - RowData = {}; - } - - this.setState( - { - formData: filtered, - active: true, - loading: false, - toastColor: "#5cb85c", - toastDescription: this.state.successMassage - }, - () => { - let redirect_type = this.state.redirect_type; - let redirect_id = this.state.redirect_id; - var x = document.getElementById("snackbar"); - this.props.removeState(); - this.props.removeLevel2State(); - this.props.removeLevel3State(); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 2000); - if (redirect_type === "Form") { - this.props.navigate(`/form/${redirect_id}`); - } else if (redirect_type === "Report") { - this.props.navigate(`/report/${redirect_id}`); - } else if (redirect_type === "Dashboard") { - this.props.navigate(`/dashboard/${redirect_id}`); - } else if (redirect_type === "Url") { - window.location = redirect_id; - } else if (redirect_type === "Microapp") { - window.localStorage.setItem( - "rowlevel", - JSON.stringify({ ...formData, ...form }) - ); - this.props.navigate(`/asmf/${redirect_id}`); - } - } - ); - }, - (error) => { - this.setState({ - loading: false, - active: true, - toastColor: "#d9534f", - toastDescription: error.message - }); - - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 2000); - } - ); } catch (error) { - this.setState({ - loading: false, - active: true, - toastColor: "#d9534f", - toastDescription: error.message - }); - - var x = document.getElementById("snackbar"); - x.className = "show"; - setTimeout(function () { - x.className = x.className.replace("show", ""); - }, 2000); + setfileload(false); + setpercentage(0); + console.error("Error uploading file:", error); } } }; + const dropboxCancel = async () => {}; + const handleSubmit = async (e) => { + e.preventDefault(); + setIsSubmit(true); + try { + const currentUser = Parse.User.current(); + const object = new Parse.Object(props.Cls); + object.set("Name", formData?.Name); + object.set("Description", formData?.Description); + object.set("Note", formData?.Note); + if (props.title === "Request Signature") { + object.set( + "TimeToCompleteDays", + parseInt(formData?.TimeToCompleteDays) + ); + } + object.set("URL", fileupload); + object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); + if (folder && folder.ObjectId) { + object.set("Folder", { + __type: "Pointer", + className: props.Cls, + objectId: folder.ObjectId + }); + } + if (signers && signers.length > 0) { + object.set("Signers", signers); + } + const ExtCls = JSON.parse(localStorage.getItem("Extand_Class")); + object.set("ExtUserPtr", { + __type: "Pointer", + className: "contracts_Users", + objectId: ExtCls[0].objectId + }); - saveUrlParamToFormdata = () => { - let url = window.location.hash; - let paramString = url.split("?")[1]; - let queryString = new URLSearchParams(paramString); - let obj = {}; - for (const [key, value] of queryString.entries()) { - obj = { ...obj, [key]: value }; + const res = await object.save(); + if (res) { + setSigners([]); + setFolder({ ObjectId: "", Name: "" }); + setFormData({ + Name: "", + Description: "", + Note: "" + }); + setFileUpload([]); + setpercentage(0); + navigate( + `/asmf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/${props?.redirectRoute}/${res.id}` + ); + } + } catch (err) { + console.log("err ", err); + setIsErr(true); + } finally { + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + setIsSubmit(false); } - this.setState({ formData: obj }); }; - componentDidMount() { - let url = window.location.hash; - if (url.includes("_app")) { - this.setState({ isAppRequest: true }); - } - let id = this.props.id; - this.getForm(id); - this.saveUrlParamToFormdata(); - } - - UNSAFE_componentWillReceiveProps(newProps) { - let id = newProps.id; - this.getForm(id); - } - - render() { - if (localStorage.getItem("accesstoken") === null) { - this.props.navigate(`/`); + const handleFolder = (data) => { + setFolder(data); + }; + const handleSigners = (data) => { + if (data && data.length > 0) { + const updateSigners = data.map((x) => ({ + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x + })); + setSigners(updateSigners); } + }; - let schema = this.state.schemaState; - let uiSchema = this.state.ui_schema; - let rules = this.state.rules; - let extraActions = this.state.extraActions; - - let FormToDisplay = applyRules( - schema, - uiSchema, - rules, - Engine, - extraActions - )(Form); - let formView = ( - <React.Fragment> - <FormToDisplay - validate={this.state.noValidate && this.dynamicValidate} - showErrorList={false} - widgets={widget} - fields={fields()} - formData={this.state.formData} - liveValidate={this.state.liveValidate} - onSubmit={this.handleSubmit} - validator={validator} - > - <div> - {this.state.active && this.state.buttons.submitText ? ( - <button className="btn btn-info submiBtn" type="submit"> - {this.state.buttons.submitText} - </button> - ) : ( - this.state.buttons.submitText && ( - <button className="btn submiBtn" type="submit" disabled> - {this.state.buttons.submitText} - </button> - ) - )} -    - {this.state.buttons.resetText && ( - <button - className="btn resetBtn" - onClick={(e) => { - e.preventDefault(); - this.setState({ - loading: true, - formData: {} - }); - setTimeout(() => { - this.setState({ loading: false }); - }, 1000); - }} - type="button" - > - {this.state.buttons.resetText} - </button> - )} - </div> - </FormToDisplay> - </React.Fragment> - ); - - if (this.state.loading) { - formView = ( + const handleReset = () => { + setSigners([]); + setFolder({ ObjectId: "", Name: "" }); + setFormData({ + Name: "", + Description: "", + Note: "" + }); + setFileUpload([]); + setpercentage(0); + }; + return ( + <div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50"> + <Title title={props?.title} /> + {isAlert && ( + <Alert type={isErr ? "danger" : "success"}> + {isErr + ? "Something went wrong please try again!" + : `${props.msgVar} created successfully!`} + </Alert> + )} + {isSubmit ? ( <div style={{ height: "300px" }}> <div style={{ @@ -1250,85 +249,136 @@ class FormBuilder extends Component { className="loader-37" ></div> </div> - ); - } - return ( - <React.Fragment> - <Title - title={ - this.state.schemaState.title ? this.state.schemaState.title : "" - } - /> - <ErrorBoundary> - <div className="row"> - <div className="col-md-12"> - <div className="card"> - <div className="card-body no-padding height-9"> - {this.state.help ? ( - <div className="dropdown" style={{ marginTop: "-30px" }}> - <i - className="far fa-question-circle dropdown-toggle hovereffect" - aria-hidden="true" - id="dropdownMenuButton" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" - style={{ - fontSize: "18px", - color: "purple", - cursor: "pointer !important", - position: "relative", - top: "40px", - left: "98%" - }} - ></i> - <div - className="dropdown-menu" - aria-labelledby="dropdownMenuButton" - style={{ - marginleft: "-121px", - margintop: "-14px", - position: "absolute", - padding: "10px", - width: "300px", - top: "102px!important" - }} - > - {parse(` - ${this.state.help} - `)} - <br /> - {this.state.link ? ( - <a - onClick={(e) => { - e.preventDefault(); - window.location.href = this.state.link; - }} - target="_blank" - className="btn btn-xs btn-primary" - > - Read more.. - </a> - ) : null} - </div> - </div> - ) : null} - <div style={{ fontSize: "13px" }}>{formView}</div> - </div> + ) : ( + <form onSubmit={handleSubmit}> + <h1 className="text-[20px] font-semibold mb-4">{props?.title}</h1> + {fileload && ( + <div className="flex items-center gap-x-2"> + <div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200"> + <div + className="h-2 rounded-full bg-blue-500" + style={{ width: `${percentage}%` }} + ></div> </div> + <span className="text-black text-sm">{percentage}%</span> </div> + )} + <div className="text-xs"> + <label className="block"> + File<span className="text-red-500 text-[13px]">*</span> + </label> + {fileupload.length > 0 ? ( + <div className="flex gap-2 justify-center items-center"> + <div className="flex justify-between items-center px-2 py-2 w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]"> + <div className="break-all"> + file selected : {fileupload?.split("/")[3]?.split("_")[1]} + </div> + <div + onClick={() => { + setFileUpload([]); + }} + className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500" + > + <i className="fa-solid fa-xmark"></i> + </div> + </div> + {process.env.REACT_APP_DROPBOX_API_KEY && ( + <DropboxChooser + onSuccess={dropboxSuccess} + onCancel={dropboxCancel} + /> + )} + </div> + ) : ( + <div className="flex gap-2 justify-center items-center"> + <input + type="file" + className="bg-white px-2 py-1.5 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + onChange={(e) => handleFileInput(e)} + accept="application/pdf" + required + /> + {process.env.REACT_APP_DROPBOX_API_KEY && ( + <DropboxChooser + onSuccess={dropboxSuccess} + onCancel={dropboxCancel} + /> + )} + </div> + )} </div> - <div id="snackbar" style={{ backgroundColor: this.state.toastColor }}> - {this.state.toastDescription} + <div className="text-xs mt-2"> + <label className="block"> + Title<span className="text-red-500 text-[13px]">*</span> + </label> + <input + name="Name" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + value={formData.Name} + onChange={(e) => handleStrInput(e)} + required + /> </div> - </ErrorBoundary> - </React.Fragment> - ); - } -} - -export default connect(null, { - removeState, - removeLevel2State, - removeLevel3State -})(FormBuilderFn); + <div className="text-xs mt-2"> + <label className="block">Description</label> + <input + name="Description" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + value={formData.Description} + onChange={(e) => handleStrInput(e)} + /> + </div> + {props.signers && <SignersInput onChange={handleSigners} required />} + <div className="text-xs mt-2"> + <label className="block"> + Note<span className="text-red-500 text-[13px]">*</span> + </label> + <input + name="Note" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + value={formData.Note} + onChange={(e) => handleStrInput(e)} + required + /> + </div> + <SelectFolder onSuccess={handleFolder} folderCls={props.Cls} /> + + {props.title === "Request Signature" && ( + <div className="text-xs mt-2"> + <label className="block"> + Time To Complete (Days) + <span className="text-red-500 text-[13px]">*</span> + </label> + <input + type="number" + name="TimeToCompleteDays" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + value={formData.TimeToCompleteDays} + onChange={(e) => handleStrInput(e)} + required + /> + </div> + )} + <div className="flex items-center mt-3 gap-2 text-white"> + <button + className={`${ + isSubmit && "cursor-progress" + } bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`} + type="submit" + disabled={isSubmit} + > + Submit + </button> + <div + className="bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none" + onClick={() => handleReset()} + > + Reset + </div> + </div> + </form> + )} + </div> + ); +}; +export default Form; diff --git a/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js b/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js index 2e50b25a8..671b91d9d 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js +++ b/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js @@ -1,9 +1,13 @@ async function getUserDetails(request) { try { + const userId = request.params.userId; const userQuery = new Parse.Query('contracts_Users'); userQuery.equalTo('Email', request.params.email); userQuery.include('TenantId'); - userQuery.include('UserId') + userQuery.include('UserId'); + if (userId) { + userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId }); + } const res = await userQuery.first({ useMasterKey: true }); return res; } catch (err) { From bea158b8f281957309788dc11f727257409de865 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Sat, 3 Feb 2024 18:19:59 +0530 Subject: [PATCH 46/73] refactor: remove unnecessary css --- apps/OpenSign/src/redux/actions/index.js | 79 - apps/OpenSign/src/styles/loader.css | 2273 +--------------------- apps/OpenSign/src/styles/toast.css | 249 +-- 3 files changed, 114 insertions(+), 2487 deletions(-) diff --git a/apps/OpenSign/src/redux/actions/index.js b/apps/OpenSign/src/redux/actions/index.js index fae7642ed..3e9e2816a 100644 --- a/apps/OpenSign/src/redux/actions/index.js +++ b/apps/OpenSign/src/redux/actions/index.js @@ -214,89 +214,10 @@ export const fetchRoleEnum = (name) => async (dispatch) => { dispatch({ type: "FETCH_ROLE", payload: response }); }; -export const setEnableCart = (val) => async (dispatch) => { - dispatch({ - type: "ENABLE_CART", - payload: val - }); -}; - -export const setCartUpdateData = (val) => async (dispatch) => { - dispatch({ - type: "UPDATE_CART", - payload: val - }); -}; - -export const addItemsToCart = (val) => async (dispatch) => { - dispatch({ - type: "ADD_CART", - payload: val - }); -}; - -export const clearCartData = () => async (dispatch) => { - dispatch({ - type: "CLEAR_CART", - payload: [] - }); -}; - -export const SaveMultipleCart = (val) => async (dispatch) => { - dispatch({ - type: "MULTI_CART", - payload: val - }); -}; - -export const removeFromCart = (val) => async (dispatch) => { - dispatch({ - type: "REMOVE_CART", - payload: val - }); -}; - -export const onChangeLevel2Dropdown = (id, name) => async (dispatch) => { - localStorage.setItem(`_dd${name}`, id); - let _data = { [name]: `${id}` }; - dispatch({ type: "Level2_Dropdown", payload: _data }); -}; - -export const onChangeLevel3Dropdown = (id, name) => async (dispatch) => { - localStorage.setItem(`_dd${name}`, id); - let _data = { [name]: `${id}` }; - dispatch({ type: "Level3_Dropdown", payload: _data }); -}; - -export const removeState = () => async (dispatch) => { - dispatch({ type: "REMOVE_STATE", payload: {} }); -}; -export const removeLevel2State = () => async (dispatch) => { - dispatch({ type: "removeLevel2", payload: {} }); -}; - -export const removeLevel3State = () => async (dispatch) => { - dispatch({ type: "removeLevel3", payload: {} }); -}; - export const showTenantName = (name) => async (dispatch) => { dispatch({ type: "SHOW_TENANT", payload: name || null }); }; -export const saveDependantDDValue = (id, value) => async (dispatch) => { - let _data = { [`${id}_dd`]: value }; - dispatch({ type: "SAVE_DEPENDANTDD", payload: _data }); -}; - -export const removeDependantDDValue = (id, value) => async (dispatch) => { - let _data = { [`${id}_dd`]: value }; - dispatch({ type: "REMOVE_DEPENDANTDD", payload: _data }); -}; - -export const remove_AlldependantDD = () => async (dispatch) => { - dispatch({ type: "REMOVE_ALLDEPENDANTDD", payload: {} }); -}; - export const save_tourSteps = (steps) => async (dispatch) => { dispatch({ type: "SAVE_TOURSTEPS", payload: steps }); }; diff --git a/apps/OpenSign/src/styles/loader.css b/apps/OpenSign/src/styles/loader.css index e6e1624f8..940d1c557 100644 --- a/apps/OpenSign/src/styles/loader.css +++ b/apps/OpenSign/src/styles/loader.css @@ -1,2215 +1,66 @@ - fieldset { - border: 0 !important; - margin: 0 !important; - padding: 0 !important; - } - - [class*="loader-"] { - display: inline-block; - width: 1em; - height: 1em; - color: inherit; - vertical-align: middle; - pointer-events: none; - } - - .loader-01 { - border: 0.2em dotted currentcolor; - border-radius: 50%; - -webkit-animation: 1s loader-01 linear infinite; - animation: 1s loader-01 linear infinite; - } - - @-webkit-keyframes loader-01 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-01 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-02 { - border: 0.2em solid transparent; - border-left-color: currentcolor; - border-right-color: currentcolor; - border-radius: 50%; - -webkit-animation: 1s loader-02 linear infinite; - animation: 1s loader-02 linear infinite; - } - - @-webkit-keyframes loader-02 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-02 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-03 { - border: 0.2em solid currentcolor; - border-bottom-color: transparent; - border-radius: 50%; - -webkit-animation: 1s loader-03 linear infinite; - animation: 1s loader-03 linear infinite; - position: relative; - } - - @-webkit-keyframes loader-03 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-03 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-04 { - border: 1px solid currentcolor; - border-radius: 50%; - -webkit-animation: 1s loader-04 linear infinite; - animation: 1s loader-04 linear infinite; - position: relative; - } - .loader-04:before { - content: ""; - display: block; - width: 0; - height: 0; - position: absolute; - top: -0.2em; - left: 50%; - border: 0.2em solid currentcolor; - border-radius: 50%; - } - - @-webkit-keyframes loader-04 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-04 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-05 { - border: 0.2em solid transparent; - border-top-color: currentcolor; - border-radius: 50%; - -webkit-animation: 1s loader-05 linear infinite; - animation: 1s loader-05 linear infinite; - position: relative; - } - .loader-05:before { - content: ""; - display: block; - width: inherit; - height: inherit; - position: absolute; - top: -0.2em; - left: -0.2em; - border: 0.2em solid currentcolor; - border-radius: 50%; - opacity: 0.5; - } - - @-webkit-keyframes loader-05 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-05 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-06 { - border: 0.2em solid currentcolor; - border-radius: 50%; - -webkit-animation: loader-06 1s ease-out infinite; - animation: loader-06 1s ease-out infinite; - } - - @-webkit-keyframes loader-06 { - 0% { - -webkit-transform: scale(0); - transform: scale(0); - opacity: 0; - } - 50% { - opacity: 1; - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - opacity: 0; - } - } - - @keyframes loader-06 { - 0% { - -webkit-transform: scale(0); - transform: scale(0); - opacity: 0; - } - 50% { - opacity: 1; - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - opacity: 0; - } - } - .loader-07 { - border: 0 solid transparent; - border-radius: 50%; - position: relative; - } - .loader-07:before, .loader-07:after { - content: ""; - border: 0.2em solid currentcolor; - border-radius: 50%; - width: inherit; - height: inherit; - position: absolute; - top: 0; - left: 0; - -webkit-animation: loader-07 1s linear infinite; - animation: loader-07 1s linear infinite; - opacity: 0; - } - .loader-07:before { - -webkit-animation-delay: 1s; - animation-delay: 1s; - } - .loader-07:after { - -webkit-animation-delay: 0.5s; - animation-delay: 0.5s; - } - - @-webkit-keyframes loader-07 { - 0% { - -webkit-transform: scale(0); - transform: scale(0); - opacity: 0; - } - 50% { - opacity: 1; - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - opacity: 0; - } - } - - @keyframes loader-07 { - 0% { - -webkit-transform: scale(0); - transform: scale(0); - opacity: 0; - } - 50% { - opacity: 1; - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - opacity: 0; - } - } - .loader-08 { - position: relative; - } - .loader-08:before, .loader-08:after { - content: ""; - width: inherit; - height: inherit; - border-radius: 50%; - background-color: currentcolor; - opacity: 0.6; - position: absolute; - top: 0; - left: 0; - -webkit-animation: loader-08 2s infinite ease-in-out; - animation: loader-08 2s infinite ease-in-out; - } - .loader-08:after { - -webkit-animation-delay: -1s; - animation-delay: -1s; - } - - @-webkit-keyframes loader-08 { - 0%, - 100% { - -webkit-transform: scale(0); - transform: scale(0); - } - 50% { - -webkit-transform: scale(1); - transform: scale(1); - } - } - - @keyframes loader-08 { - 0%, - 100% { - -webkit-transform: scale(0); - transform: scale(0); - } - 50% { - -webkit-transform: scale(1); - transform: scale(1); - } - } - .loader-09 { - background-color: currentcolor; - border-radius: 50%; - -webkit-animation: loader-09 1s infinite ease-in-out; - animation: loader-09 1s infinite ease-in-out; - } - - @-webkit-keyframes loader-09 { - 0% { - -webkit-transform: scale(0); - transform: scale(0); - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - opacity: 0; - } - } - - @keyframes loader-09 { - 0% { - -webkit-transform: scale(0); - transform: scale(0); - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - opacity: 0; - } - } - .loader-10 { - position: relative; - -webkit-animation: loader-10-1 2s infinite linear; - animation: loader-10-1 2s infinite linear; - } - .loader-10:before, .loader-10:after { - content: ""; - width: 0; - height: 0; - border: 0.5em solid currentcolor; - display: block; - position: absolute; - border-radius: 100%; - -webkit-animation: loader-10-2 2s infinite ease-in-out; - animation: loader-10-2 2s infinite ease-in-out; - } - .loader-10:before { - top: 0; - left: 50%; - } - .loader-10:after { - bottom: 0; - right: 50%; - -webkit-animation-delay: -1s; - animation-delay: -1s; - } - - @-webkit-keyframes loader-10-1 { - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-10-1 { - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - @-webkit-keyframes loader-10-2 { - 0%, - 100% { - -webkit-transform: scale(0); - transform: scale(0); - } - 50% { - -webkit-transform: scale(1); - transform: scale(1); - } - } - @keyframes loader-10-2 { - 0%, - 100% { - -webkit-transform: scale(0); - transform: scale(0); - } - 50% { - -webkit-transform: scale(1); - transform: scale(1); - } - } - .loader-11 { - background-color: currentcolor; - -webkit-animation: loader-11 1.2s infinite ease-in-out; - animation: loader-11 1.2s infinite ease-in-out; - } - - @-webkit-keyframes loader-11 { - 0% { - -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg); - transform: perspective(120px) rotateX(0deg) rotateY(0deg); - } - 50% { - -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); - transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); - } - 100% { - -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); - transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); - } - } - - @keyframes loader-11 { - 0% { - -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg); - transform: perspective(120px) rotateX(0deg) rotateY(0deg); - } - 50% { - -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); - transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); - } - 100% { - -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); - transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); - } - } - .loader-12 { - position: relative; - } - .loader-12:before, .loader-12:after { - content: ""; - display: block; - position: absolute; - background-color: currentcolor; - left: 50%; - right: 0; - top: 0; - bottom: 50%; - box-shadow: -0.5em 0 0 currentcolor; - -webkit-animation: loader-12 1s linear infinite; - animation: loader-12 1s linear infinite; - } - .loader-12:after { - top: 50%; - bottom: 0; - -webkit-animation-delay: 0.25s; - animation-delay: 0.25s; - } - - @-webkit-keyframes loader-12 { - 0%, - 100% { - box-shadow: -0.5em 0 0 transparent; - background-color: currentcolor; - } - 50% { - box-shadow: -0.5em 0 0 currentcolor; - background-color: transparent; - } - } - - @keyframes loader-12 { - 0%, - 100% { - box-shadow: -0.5em 0 0 transparent; - background-color: currentcolor; - } - 50% { - box-shadow: -0.5em 0 0 currentcolor; - background-color: transparent; - } - } - .loader-13:before, - .loader-13:after, - .loader-13 { - border-radius: 50%; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; - -webkit-animation: loader-13 1.8s infinite ease-in-out; - animation: loader-13 1.8s infinite ease-in-out; - } - - .loader-13 { - color: currentcolor; - position: relative; - -webkit-transform: translateZ(0); - transform: translateZ(0); - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; - top: -1em; - } - .loader-13:before { - right: 100%; - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; - } - .loader-13:after { - left: 100%; - } - .loader-13:before, .loader-13:after { - content: ""; - display: block; - position: absolute; - top: 0; - width: inherit; - height: inherit; - } - - @-webkit-keyframes loader-13 { - 0%, - 80%, - 100% { - box-shadow: 0 1em 0 -1em; - } - 40% { - box-shadow: 0 1em 0 -0.2em; - } - } - - @keyframes loader-13 { - 0%, - 80%, - 100% { - box-shadow: 0 1em 0 -1em; - } - 40% { - box-shadow: 0 1em 0 -0.2em; - } - } - .loader-14 { - border-radius: 50%; - box-shadow: 0 1em 0 -0.2em currentcolor; - position: relative; - -webkit-animation: loader-14 0.8s ease-in-out alternate infinite; - animation: loader-14 0.8s ease-in-out alternate infinite; - -webkit-animation-delay: 0.32s; - animation-delay: 0.32s; - top: -1em; - } - .loader-14:after, .loader-14:before { - content: ""; - position: absolute; - width: inherit; - height: inherit; - border-radius: inherit; - box-shadow: inherit; - -webkit-animation: inherit; - animation: inherit; - } - .loader-14:before { - left: -1em; - -webkit-animation-delay: 0.48s; - animation-delay: 0.48s; - } - .loader-14:after { - right: -1em; - -webkit-animation-delay: 0.16s; - animation-delay: 0.16s; - } - - @-webkit-keyframes loader-14 { - 0% { - box-shadow: 0 2em 0 -0.2em currentcolor; - } - 100% { - box-shadow: 0 1em 0 -0.2em currentcolor; - } - } - - @keyframes loader-14 { - 0% { - box-shadow: 0 2em 0 -0.2em currentcolor; - } - 100% { - box-shadow: 0 1em 0 -0.2em currentcolor; - } - } - .loader-15 { - background: currentcolor; - position: relative; - -webkit-animation: loader-15 1s ease-in-out infinite; - animation: loader-15 1s ease-in-out infinite; - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; - width: 0.25em; - height: 0.5em; - margin: 0 0.5em; - } - .loader-15:after, .loader-15:before { - content: ""; - position: absolute; - width: inherit; - height: inherit; - background: inherit; - -webkit-animation: inherit; - animation: inherit; - } - .loader-15:before { - right: 0.5em; - -webkit-animation-delay: 0.2s; - animation-delay: 0.2s; - } - .loader-15:after { - left: 0.5em; - -webkit-animation-delay: 0.6s; - animation-delay: 0.6s; - } - - @-webkit-keyframes loader-15 { - 0%, - 100% { - box-shadow: 0 0 0 currentcolor, 0 0 0 currentcolor; - } - 50% { - box-shadow: 0 -0.25em 0 currentcolor, 0 0.25em 0 currentcolor; - } - } - - @keyframes loader-15 { - 0%, - 100% { - box-shadow: 0 0 0 currentcolor, 0 0 0 currentcolor; - } - 50% { - box-shadow: 0 -0.25em 0 currentcolor, 0 0.25em 0 currentcolor; - } - } - .loader-16 { - -webkit-transform: rotateZ(45deg); - transform: rotateZ(45deg); - -webkit-perspective: 1000px; - perspective: 1000px; - border-radius: 50%; - } - .loader-16:before, .loader-16:after { - content: ""; - display: block; - position: absolute; - top: 0; - left: 0; - width: inherit; - height: inherit; - border-radius: 50%; - -webkit-animation: 1s spin linear infinite; - animation: 1s spin linear infinite; - } - .loader-16:before { - -webkit-transform: rotateX(70deg); - transform: rotateX(70deg); - } - .loader-16:after { - -webkit-transform: rotateY(70deg); - transform: rotateY(70deg); - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; - } - - @-webkit-keyframes rotate { - 0% { - -webkit-transform: translate(-50%, -50%) rotateZ(0deg); - transform: translate(-50%, -50%) rotateZ(0deg); - } - 100% { - -webkit-transform: translate(-50%, -50%) rotateZ(360deg); - transform: translate(-50%, -50%) rotateZ(360deg); - } - } - - @keyframes rotate { - 0% { - -webkit-transform: translate(-50%, -50%) rotateZ(0deg); - transform: translate(-50%, -50%) rotateZ(0deg); - } - 100% { - -webkit-transform: translate(-50%, -50%) rotateZ(360deg); - transform: translate(-50%, -50%) rotateZ(360deg); - } - } - @-webkit-keyframes rotateccw { - 0% { - -webkit-transform: translate(-50%, -50%) rotate(0deg); - transform: translate(-50%, -50%) rotate(0deg); - } - 100% { - -webkit-transform: translate(-50%, -50%) rotate(-360deg); - transform: translate(-50%, -50%) rotate(-360deg); - } - } - @keyframes rotateccw { - 0% { - -webkit-transform: translate(-50%, -50%) rotate(0deg); - transform: translate(-50%, -50%) rotate(0deg); - } - 100% { - -webkit-transform: translate(-50%, -50%) rotate(-360deg); - transform: translate(-50%, -50%) rotate(-360deg); - } - } - @-webkit-keyframes spin { - 0%, - 100% { - box-shadow: 0.2em 0px 0 0px currentcolor; - } - 12% { - box-shadow: 0.2em 0.2em 0 0 currentcolor; - } - 25% { - box-shadow: 0 0.2em 0 0px currentcolor; - } - 37% { - box-shadow: -0.2em 0.2em 0 0 currentcolor; - } - 50% { - box-shadow: -0.2em 0 0 0 currentcolor; - } - 62% { - box-shadow: -0.2em -0.2em 0 0 currentcolor; - } - 75% { - box-shadow: 0px -0.2em 0 0 currentcolor; - } - 87% { - box-shadow: 0.2em -0.2em 0 0 currentcolor; - } - } - @keyframes spin { - 0%, - 100% { - box-shadow: 0.2em 0px 0 0px currentcolor; - } - 12% { - box-shadow: 0.2em 0.2em 0 0 currentcolor; - } - 25% { - box-shadow: 0 0.2em 0 0px currentcolor; - } - 37% { - box-shadow: -0.2em 0.2em 0 0 currentcolor; - } - 50% { - box-shadow: -0.2em 0 0 0 currentcolor; - } - 62% { - box-shadow: -0.2em -0.2em 0 0 currentcolor; - } - 75% { - box-shadow: 0px -0.2em 0 0 currentcolor; - } - 87% { - box-shadow: 0.2em -0.2em 0 0 currentcolor; - } - } - .loader-17 { - position: relative; - background-color: currentcolor; - border-radius: 50%; - } - .loader-17:after, .loader-17:before { - content: ""; - position: absolute; - width: 0.25em; - height: 0.25em; - border-radius: 50%; - opacity: 0.8; - } - .loader-17:after { - left: -0.5em; - top: -0.25em; - background-color: currentcolor; - -webkit-transform-origin: 0.75em 1em; - transform-origin: 0.75em 1em; - -webkit-animation: loader-17 1s linear infinite; - animation: loader-17 1s linear infinite; - opacity: 0.6; - } - .loader-17:before { - left: -1.25em; - top: -0.75em; - background-color: currentcolor; - -webkit-transform-origin: 1.5em 1em; - transform-origin: 1.5em 1em; - -webkit-animation: loader-17 2s linear infinite; - animation: loader-17 2s linear infinite; - } - - @-webkit-keyframes loader-17 { - 0% { - -webkit-transform: rotateZ(0deg) translate3d(0, 0, 0); - transform: rotateZ(0deg) translate3d(0, 0, 0); - } - 100% { - -webkit-transform: rotateZ(360deg) translate3d(0, 0, 0); - transform: rotateZ(360deg) translate3d(0, 0, 0); - } - } - - @keyframes loader-17 { - 0% { - -webkit-transform: rotateZ(0deg) translate3d(0, 0, 0); - transform: rotateZ(0deg) translate3d(0, 0, 0); - } - 100% { - -webkit-transform: rotateZ(360deg) translate3d(0, 0, 0); - transform: rotateZ(360deg) translate3d(0, 0, 0); - } - } - .loader-18 { - position: relative; - } - .loader-18:before, .loader-18:after { - content: ""; - display: block; - position: absolute; - border-radius: 50%; - border: 0.1em solid transparent; - border-bottom-color: currentcolor; - top: 0; - left: 0; - -webkit-animation: 1s loader-18 linear infinite; - animation: 1s loader-18 linear infinite; - } - .loader-18:before { - width: 1em; - height: 1em; - } - .loader-18:after { - width: 0.8em; - height: 0.8em; - top: 0.1em; - left: 0.1em; - animation-direction: reverse; - } - - @-webkit-keyframes loader-18 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-18 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-19 { - border-top: 0.2em solid currentcolor; - border-right: 0.2em solid transparent; - -webkit-animation: loader-19 1s linear infinite; - animation: loader-19 1s linear infinite; - border-radius: 100%; - position: relative; - } - - @-webkit-keyframes loader-19 { - to { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-19 { - to { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-20 { - background-color: transparent; - box-shadow: inset 0px 0px 0px 0.1em currentcolor; - border-radius: 50%; - position: relative; - } - .loader-20:after, .loader-20:before { - position: absolute; - content: ""; - background-color: currentcolor; - top: 0.5em; - left: 0.5em; - height: 0.1em; - -webkit-transform-origin: left center; - transform-origin: left center; - } - .loader-20:after { - width: 0.4em; - -webkit-animation: loader-20 2s linear infinite; - animation: loader-20 2s linear infinite; - } - .loader-20:before { - width: 0.3em; - -webkit-animation: loader-20 8s linear infinite; - animation: loader-20 8s linear infinite; - } - - @-webkit-keyframes loader-20 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-20 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-21 { - position: relative; - } - .loader-21:before, .loader-21:after { - position: absolute; - content: ""; - } - .loader-21:before { - width: 80%; - height: 80%; - left: 10%; - bottom: 10%; - border-radius: 100% 100% 100% 0; - box-shadow: 0px 0px 0px 0.1em currentcolor; - -webkit-animation: loader-21 1s linear infinite; - animation: loader-21 1s linear infinite; - -webkit-transform: rotate(-46deg); - transform: rotate(-46deg); - } - .loader-21:after { - width: 1em; - height: 0.3em; - border-radius: 100%; - left: 0; - background-color: rgba(255, 255, 255, 0.2); - bottom: -0.2em; - z-index: -1; - } - - @-webkit-keyframes loader-21 { - 0% { - top: 0; - } - 50% { - top: -5px; - } - 100% { - top: 0; - } - } - - @keyframes loader-21 { - 0% { - top: 0; - } - 50% { - top: -5px; - } - 100% { - top: 0; - } - } - .loader-22 { - border: 0.1em currentcolor solid; - border-radius: 100%; - position: relative; - overflow: hidden; - z-index: 1; - } - .loader-22:after, .loader-22:before { - position: absolute; - content: ""; - background-color: currentcolor; - } - .loader-22:after { - width: 50%; - height: 0.1em; - left: 50%; - top: 50%; - -webkit-transform-origin: left center; - transform-origin: left center; - -webkit-animation: loader-22 2s linear infinite alternate; - animation: loader-22 2s linear infinite alternate; - } - .loader-22:before { - width: 100%; - height: 40%; - left: 0; - bottom: 0; - } - - @-webkit-keyframes loader-22 { - 0% { - -webkit-transform: rotate(-160deg); - transform: rotate(-160deg); - } - 100% { - -webkit-transform: rotate(-20deg); - transform: rotate(-20deg); - } - } - - @keyframes loader-22 { - 0% { - -webkit-transform: rotate(-160deg); - transform: rotate(-160deg); - } - 100% { - -webkit-transform: rotate(-20deg); - transform: rotate(-20deg); - } - } - .loader-23 { - height: 0.5em; - border: 0.1em currentcolor solid; - border-radius: 0.1em; - position: relative; - -webkit-animation: loader-23 5s linear infinite; - animation: loader-23 5s linear infinite; - } - .loader-23:after { - width: 0.07em; - height: 100%; - background-color: currentcolor; - border-radius: 0px 0.5em 0.5em 0px; - position: absolute; - content: ""; - top: 0; - left: calc(100% + 0.1em); - } - - @-webkit-keyframes loader-23 { - 0% { - box-shadow: inset 0px 0px 0px currentcolor; - } - 100% { - box-shadow: inset 1em 0px 0px currentcolor; - } - } - - @keyframes loader-23 { - 0% { - box-shadow: inset 0px 0px 0px currentcolor; - } - 100% { - box-shadow: inset 1em 0px 0px currentcolor; - } - } - .loader-24 { - width: 0.8em; - height: 1em; - border: 0.1em currentcolor solid; - border-radius: 0px 0px 0.2em 0.2em; - position: relative; - } - .loader-24:after, .loader-24:before { - position: absolute; - content: ""; - } - .loader-24:after { - width: 0.2em; - height: 50%; - border: 0.1em currentcolor solid; - border-left: none; - border-radius: 0px 0.5em 0.5em 0px; - left: calc(100% + 0.1em); - top: 0.1em; - } - .loader-24:before { - width: 0.1em; - height: 0.3em; - background-color: currentcolor; - top: -0.3em; - left: 0.05em; - box-shadow: 0.2em 0px 0px 0px currentcolor, 0.2em -0.2em 0px 0px currentcolor, 0.4em 0px 0px 0px currentcolor; - -webkit-animation: loader-24 1s linear infinite alternate; - animation: loader-24 1s linear infinite alternate; - } - - @-webkit-keyframes loader-24 { - 0% { - height: 0px; - } - 100% { - height: 6px; - } - } - - @keyframes loader-24 { - 0% { - height: 0px; - } - 100% { - height: 6px; - } - } - .loader-25 { - border: 0.1em currentcolor solid; - position: relative; - -webkit-animation: loader-25-1 5s linear infinite; - animation: loader-25-1 5s linear infinite; - } - .loader-25:after { - width: 0.2em; - height: 0.2em; - position: absolute; - content: ""; - background-color: currentcolor; - bottom: calc(100% + 0.2em); - left: -0.4em; - -webkit-animation: loader-25-2 1s ease-in-out infinite; - animation: loader-25-2 1s ease-in-out infinite; - } - - @-webkit-keyframes loader-25-1 { - 0% { - box-shadow: inset 0 0 0 0 currentcolor; - } - 100% { - box-shadow: inset 0 -1em 0 0 currentcolor; - } - } - - @keyframes loader-25-1 { - 0% { - box-shadow: inset 0 0 0 0 currentcolor; - } - 100% { - box-shadow: inset 0 -1em 0 0 currentcolor; - } - } - @-webkit-keyframes loader-25-2 { - 25% { - left: calc(100% + 0.2em); - bottom: calc(100% + 0.2em); - } - 50% { - left: calc(100% + 0.2em); - bottom: -0.4em; - } - 75% { - left: -0.4em; - bottom: -0.4em; - } - 100% { - left: -0.4em; - bottom: calc(100% + 0.2em); - } - } - @keyframes loader-25-2 { - 25% { - left: calc(100% + 0.2em); - bottom: calc(100% + 0.2em); - } - 50% { - left: calc(100% + 0.2em); - bottom: -0.4em; - } - 75% { - left: -0.4em; - bottom: -0.4em; - } - 100% { - left: -0.4em; - bottom: calc(100% + 0.2em); - } - } - .loader-26 { - width: 0.5em; - height: 0.5em; - background-color: currentcolor; - box-shadow: 1em 0px 0px currentcolor; - border-radius: 50%; - -webkit-animation: loader-26 1s ease-in-out infinite alternate; - animation: loader-26 1s ease-in-out infinite alternate; - } - - @-webkit-keyframes loader-26 { - 0% { - opacity: 0.1; - -webkit-transform: rotate(0deg) scale(0.5); - transform: rotate(0deg) scale(0.5); - } - 100% { - opacity: 1; - -webkit-transform: rotate(360deg) scale(1.2); - transform: rotate(360deg) scale(1.2); - } - } - - @keyframes loader-26 { - 0% { - opacity: 0.1; - -webkit-transform: rotate(0deg) scale(0.5); - transform: rotate(0deg) scale(0.5); - } - 100% { - opacity: 1; - -webkit-transform: rotate(360deg) scale(1.2); - transform: rotate(360deg) scale(1.2); - } - } - .loader-27 { - box-shadow: inset 0 0 0 0.1em currentcolor; - border-radius: 50%; - position: relative; - margin-left: 1.2em; - } - .loader-27:before { - content: ""; - display: block; - width: inherit; - height: inherit; - border-radius: 50%; - position: absolute; - right: 1.2em; - top: 0; - box-shadow: inset 0 0 0 0.1em currentcolor; - } - .loader-27:after { - border: 0.2em solid currentcolor; - box-shadow: -1.2em 0 0 0 currentcolor; - width: 0; - height: 0; - border-radius: 50%; - left: 50%; - top: 25%; - position: absolute; - content: ""; - -webkit-animation: loader-27 2s linear infinite alternate; - animation: loader-27 2s linear infinite alternate; - } - - @-webkit-keyframes loader-27 { - 0% { - left: 0; - } - 100% { - left: 0.5em; - } - } - - @keyframes loader-27 { - 0% { - left: 0; - } - 100% { - left: 0.5em; - } - } - .loader-28 { - position: relative; - -webkit-animation: 2s loader-28-1 infinite; - animation: 2s loader-28-1 infinite; - } - .loader-28:before { - content: ""; - display: block; - width: inherit; - height: inherit; - border-radius: 80% 20%; - border: 0.1em solid currentcolor; - -webkit-transform: rotate(45deg); - transform: rotate(45deg); - border-width: 0.1em 0.05em 0.05em 0.1em; - } - .loader-28:after { - content: ""; - display: block; - width: 0.2em; - height: 0.2em; - position: absolute; - top: 0.4em; - left: 50%; - border-radius: 50%; - box-shadow: -0.07em 0.07em 0 0.1em currentcolor; - -webkit-animation: 2s loader-28-2 linear infinite; - animation: 2s loader-28-2 linear infinite; - } - - @-webkit-keyframes loader-28-1 { - 0%, - 100% { - -webkit-transform: scaleY(1); - transform: scaleY(1); - } - 10% { - -webkit-transform: scaleY(0); - transform: scaleY(0); - } - 20% { - -webkit-transform: scaleY(1); - transform: scaleY(1); - } - } - - @keyframes loader-28-1 { - 0%, - 100% { - -webkit-transform: scaleY(1); - transform: scaleY(1); - } - 10% { - -webkit-transform: scaleY(0); - transform: scaleY(0); - } - 20% { - -webkit-transform: scaleY(1); - transform: scaleY(1); - } - } - @-webkit-keyframes loader-28-2 { - 0%, - 100% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - 30% { - -webkit-transform: translateX(-100%); - transform: translateX(-100%); - } - 50% { - -webkit-transform: transalteX(200%); - transform: transalteX(200%); - } - } - @keyframes loader-28-2 { - 0%, - 100% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - 30% { - -webkit-transform: translateX(-100%); - transform: translateX(-100%); - } - 50% { - -webkit-transform: transalteX(200%); - transform: transalteX(200%); - } - } - .loader-29 { - border-radius: 50%; - box-shadow: inset 0 0 0 0.1em currentcolor, -0.5em -0.5em 0 -0.4em currentcolor, 0 -0.7em 0 -0.4em currentcolor, 0.5em -0.5em 0 -0.4em currentcolor, -0.5em 0.5em 0 -0.4em currentcolor, 0 0.7em 0 -0.4em currentcolor, 0.5em 0.5em 0 -0.4em currentcolor, -0.7em 0 0 -0.4em currentcolor, 0.7em 0 0 -0.4em currentcolor; - -webkit-animation: 5s loader-29 linear infinite; - animation: 5s loader-29 linear infinite; - } - - @-webkit-keyframes loader-29 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-29 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-30 { - border: 0.2em solid transparent; - border-top-color: currentcolor; - border-bottom-color: currentcolor; - border-radius: 50%; - position: relative; - -webkit-animation: 1s loader-30 linear infinite; - animation: 1s loader-30 linear infinite; - } - .loader-30:before, .loader-30:after { - content: ""; - display: block; - width: 0; - height: 0; - position: absolute; - border: 0.2em solid transparent; - border-bottom-color: currentcolor; - } - .loader-30:before { - -webkit-transform: rotate(135deg); - transform: rotate(135deg); - right: -0.3em; - top: -0.05em; - } - .loader-30:after { - -webkit-transform: rotate(-45deg); - transform: rotate(-45deg); - left: -0.3em; - bottom: -0.05em; - } - - @-webkit-keyframes loader-30 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-30 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - .loader-31 { - box-shadow: 0 0 2em currentcolor; - background-color: currentcolor; - position: relative; - border-radius: 50%; - -webkit-transform: rotateX(-60deg) perspective(1000px); - transform: rotateX(-60deg) perspective(1000px); - } - .loader-31:before, .loader-31:after { - content: ""; - display: block; - position: absolute; - top: 0; - left: 0; - width: inherit; - height: inherit; - border-radius: inherit; - -webkit-animation: 1s loader-31 ease-out infinite; - animation: 1s loader-31 ease-out infinite; - } - .loader-31:after { - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; - } - - @-webkit-keyframes loader-31 { - 0% { - opacity: 1; - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - box-shadow: 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor; - } - 100% { - opacity: 0; - -webkit-transform: rotate(180deg); - transform: rotate(180deg); - box-shadow: -1em -1em 0 -0.35em currentcolor, 0 -1.5em 0 -0.35em currentcolor, 1em -1em 0 -0.35em currentcolor, -1.5em 0 0 -0.35em currentcolor, 1.5em -0 0 -0.35em currentcolor, -1em 1em 0 -0.35em currentcolor, 0 1.5em 0 -0.35em currentcolor, 1em 1em 0 -0.35em currentcolor; - } - } - - @keyframes loader-31 { - 0% { - opacity: 1; - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - box-shadow: 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor, 0 0 0 -0.5em currentcolor; - } - 100% { - opacity: 0; - -webkit-transform: rotate(180deg); - transform: rotate(180deg); - box-shadow: -1em -1em 0 -0.35em currentcolor, 0 -1.5em 0 -0.35em currentcolor, 1em -1em 0 -0.35em currentcolor, -1.5em 0 0 -0.35em currentcolor, 1.5em -0 0 -0.35em currentcolor, -1em 1em 0 -0.35em currentcolor, 0 1.5em 0 -0.35em currentcolor, 1em 1em 0 -0.35em currentcolor; - } - } - .loader-32 { - position: relative; - border-radius: 50%; - box-shadow: 0 0 1em 0 currentcolor, inset 0 0 1em 0 currentcolor; - -webkit-animation: 1s loader-32 linear infinite; - animation: 1s loader-32 linear infinite; - } - .loader-32:before, .loader-32:after { - content: ""; - display: block; - width: inherit; - height: inherit; - position: absolute; - border-radius: 50%; - } - .loader-32:before { - border-top: 0.2em solid currentcolor; - border-right: 0.2em solid transparent; - top: 0.28em; - right: calc(50% - 0.22em); - } - .loader-32:after { - border-bottom: 0.2em solid currentcolor; - border-left: 0.2em solid transparent; - bottom: 0.28em; - left: calc(50% - 0.22em); - } - - @-webkit-keyframes loader-32 { - 0% { - -webkit-transform: rotateX(-60deg) rotateZ(0deg); - transform: rotateX(-60deg) rotateZ(0deg); - } - 100% { - -webkit-transform: rotateX(-60deg) rotateZ(360deg); - transform: rotateX(-60deg) rotateZ(360deg); - } - } - - @keyframes loader-32 { - 0% { - -webkit-transform: rotateX(-60deg) rotateZ(0deg); - transform: rotateX(-60deg) rotateZ(0deg); - } - 100% { - -webkit-transform: rotateX(-60deg) rotateZ(360deg); - transform: rotateX(-60deg) rotateZ(360deg); - } - } - .loader-33 { - border-radius: 50%; - position: relative; - } - .loader-33:after, .loader-33:before { - position: absolute; - content: ""; - } - .loader-33:after { - height: 0.1em; - width: 1em; - background-color: currentcolor; - border-radius: 0.1em; - bottom: 0; - left: 0; - -webkit-transform-origin: bottom center; - transform-origin: bottom center; - -webkit-animation: loader-33-1 0.8s ease-in-out infinite alternate; - animation: loader-33-1 0.8s ease-in-out infinite alternate; - } - .loader-33:before { - height: 0.2em; - width: 0.2em; - background-color: currentcolor; - border-radius: 50%; - top: 0; - left: calc(50% - 0.1em); - -webkit-animation: loader-33-2 0.4s ease-in-out infinite alternate; - animation: loader-33-2 0.4s ease-in-out infinite alternate; - } - - @-webkit-keyframes loader-33-2 { - 0% { - height: 0.24em; - -webkit-transform: translateY(0px); - transform: translateY(0px); - } - 75% { - height: 0.2em; - width: 0.2em; - } - 100% { - height: 0.1em; - width: 0.24em; - -webkit-transform: translateY(0.8em); - transform: translateY(0.8em); - } - } - - @keyframes loader-33-2 { - 0% { - height: 0.24em; - -webkit-transform: translateY(0px); - transform: translateY(0px); - } - 75% { - height: 0.2em; - width: 0.2em; - } - 100% { - height: 0.1em; - width: 0.24em; - -webkit-transform: translateY(0.8em); - transform: translateY(0.8em); - } - } - @-webkit-keyframes loader-33-1 { - 0% { - -webkit-transform: rotate(-45deg); - transform: rotate(-45deg); - } - 100% { - -webkit-transform: rotate(45deg); - transform: rotate(45deg); - } - } - @keyframes loader-33-1 { - 0% { - -webkit-transform: rotate(-45deg); - transform: rotate(-45deg); - } - 100% { - -webkit-transform: rotate(45deg); - transform: rotate(45deg); - } - } - .loader-34 { - position: relative; - width: 1em; - height: 0.5em; - } - .loader-34:after, .loader-34:before { - position: absolute; - content: ""; - height: 0.4em; - width: 0.4em; - top: 0; - background-color: currentcolor; - border-radius: 50%; - } - .loader-34:after { - right: 0; - -webkit-animation: loader-34-2 0.5s ease-in-out infinite; - animation: loader-34-2 0.5s ease-in-out infinite; - -webkit-animation-direction: alternate; - animation-direction: alternate; - } - .loader-34:before { - left: 0; - -webkit-animation: loader-34-1 0.5s ease-in-out infinite; - animation: loader-34-1 0.5s ease-in-out infinite; - -webkit-animation-direction: alternate; - animation-direction: alternate; - } - - @-webkit-keyframes loader-34-1 { - 0% { - -webkit-transform: translatex(0px); - transform: translatex(0px); - } - 65% { - height: 0.4em; - width: 0.4em; - } - 100% { - height: 0.5em; - width: 0.3em; - -webkit-transform: translatex(0.2em); - transform: translatex(0.2em); - } - } - - @keyframes loader-34-1 { - 0% { - -webkit-transform: translatex(0px); - transform: translatex(0px); - } - 65% { - height: 0.4em; - width: 0.4em; - } - 100% { - height: 0.5em; - width: 0.3em; - -webkit-transform: translatex(0.2em); - transform: translatex(0.2em); - } - } - @-webkit-keyframes loader-34-2 { - 0% { - -webkit-transform: translatex(0px); - transform: translatex(0px); - } - 65% { - height: 0.4em; - width: 0.4em; - } - 100% { - height: 0.5em; - width: 0.3em; - -webkit-transform: translatex(-0.2em); - transform: translatex(-0.2em); - } - } - @keyframes loader-34-2 { - 0% { - -webkit-transform: translatex(0px); - transform: translatex(0px); - } - 65% { - height: 0.4em; - width: 0.4em; - } - 100% { - height: 0.5em; - width: 0.3em; - -webkit-transform: translatex(-0.2em); - transform: translatex(-0.2em); - } - } - .loader-35 { - margin: 0 0.5em; - position: relative; - } - .loader-35:before { - border-radius: 50%; - background-color: currentcolor; - -webkit-animation: loader-35 3s cubic-bezier(0.77, 0, 0.175, 1) infinite; - animation: loader-35 3s cubic-bezier(0.77, 0, 0.175, 1) infinite; - content: ""; - width: inherit; - height: inherit; - top: 0; - left: 0; - position: absolute; - } - - @-webkit-keyframes loader-35 { - 0% { - -webkit-transform: translateX(0) scale(1); - transform: translateX(0) scale(1); - } - 25% { - -webkit-transform: translateX(-100%) scale(0.3); - transform: translateX(-100%) scale(0.3); - } - 50% { - -webkit-transform: translateX(0) scale(1); - transform: translateX(0) scale(1); - } - 75% { - -webkit-transform: translateX(100%) scale(0.3); - transform: translateX(100%) scale(0.3); - } - 100% { - -webkit-transform: translateX(0) scale(1); - transform: translateX(0) scale(1); - } - } - - @keyframes loader-35 { - 0% { - -webkit-transform: translateX(0) scale(1); - transform: translateX(0) scale(1); - } - 25% { - -webkit-transform: translateX(-100%) scale(0.3); - transform: translateX(-100%) scale(0.3); - } - 50% { - -webkit-transform: translateX(0) scale(1); - transform: translateX(0) scale(1); - } - 75% { - -webkit-transform: translateX(100%) scale(0.3); - transform: translateX(100%) scale(0.3); - } - 100% { - -webkit-transform: translateX(0) scale(1); - transform: translateX(0) scale(1); - } - } - .loader-36 { - position: relative; - } - .loader-36:before, .loader-36:after { - content: ""; - position: absolute; - top: 0; - left: 0; - } - .loader-36:before { - width: 1em; - height: 1em; - border: 0.1em solid currentcolor; - border-radius: 50%; - -webkit-animation: loader-36-1 1.15s infinite -0.3s; - animation: loader-36-1 1.15s infinite -0.3s; - } - .loader-36:after { - right: 0; - bottom: 0; - margin: auto; - width: 0; - height: 0; - border: 0.1em solid currentcolor; - border-radius: 50%; - -webkit-transform: translate(-0.2em); - transform: translate(-0.2em); - -webkit-animation: loader-36-2 4.6s infinite steps(1); - animation: loader-36-2 4.6s infinite steps(1); - } - - @-webkit-keyframes loader-36-1 { - to { - -webkit-transform: rotateX(180deg); - transform: rotateX(180deg); - } - } - - @keyframes loader-36-1 { - to { - -webkit-transform: rotateX(180deg); - transform: rotateX(180deg); - } - } - @-webkit-keyframes loader-36-2 { - 0% { - opacity: 0; - } - 25% { - opacity: 1; - } - 50% { - box-shadow: 0.2em 0 0 currentcolor; - } - 75% { - box-shadow: 0.2em 0 0 currentcolor, 0.4em 0 0 currentcolor; - } - } - @keyframes loader-36-2 { - 0% { - opacity: 0; - } - 25% { - opacity: 1; - } - 50% { - box-shadow: 0.2em 0 0 currentcolor; - } - 75% { - box-shadow: 0.2em 0 0 currentcolor, 0.4em 0 0 currentcolor; - } - } - .loader-37 { - border-right: 0.1em solid currentcolor; - border-radius: 100%; - -webkit-animation: loader-37 800ms linear infinite; - animation: loader-37 800ms linear infinite; - } - .loader-37:before, .loader-37:after { - content: ""; - width: 0.8em; - height: 0.8em; - display: block; - position: absolute; - top: calc(50% - 0.4em); - left: calc(50% - 0.4em); - border-left: 0.08em solid currentcolor; - border-radius: 100%; - animation: loader-37 400ms linear infinite reverse; - } - .loader-37:after { - width: 0.6em; - height: 0.6em; - top: calc(50% - 0.3em); - left: calc(50% - 0.3em); - border: 0; - border-right: 0.05em solid currentcolor; - -webkit-animation: none; - animation: none; - } - - @-webkit-keyframes loader-37 { - from { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - to { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - } - - @keyframes loader-37 { - from { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - to { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - } - .loader-38 { - height: 0.1em; - width: 0.1em; - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - -webkit-animation: loader-38 6s infinite; - animation: loader-38 6s infinite; - } - - @-webkit-keyframes loader-38 { - 0% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - } - 8.33% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor; - } - 16.66% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor; - } - 24.99% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 33.32% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - } - 41.65% { - box-shadow: 0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor; - } - 49.98% { - box-shadow: 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor; - } - 58.31% { - box-shadow: -0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 66.64% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 74.97% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 83.3% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 91.63% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 100% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - } - } - - @keyframes loader-38 { - 0% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - } - 8.33% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor; - } - 16.66% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor; - } - 24.99% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 33.32% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - } - 41.65% { - box-shadow: 0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor; - } - 49.98% { - box-shadow: 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor; - } - 58.31% { - box-shadow: -0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 66.64% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 74.97% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 83.3% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, 0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 91.63% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor, -0.2em 0.2em 0 0.1em currentcolor; - } - 100% { - box-shadow: -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor, -0.2em -0.2em 0 0.1em currentcolor; - } - } - .loader-39 { - position: relative; - width: 0.15em; - height: 0.15em; - background-color: currentcolor; - border-radius: 100%; - -webkit-animation: loader-39-1 30s infinite linear; - animation: loader-39-1 30s infinite linear; - } - .loader-39:before, .loader-39:after { - content: ""; - border-radius: 100%; - position: absolute; - top: 50%; - left: 50%; - -webkit-transform: translate(-50%, -50%); - transform: translate(-50%, -50%); - } - .loader-39:before { - width: 0.3em; - height: 1em; - -webkit-animation: loader-39-2 0.8s linear infinite; - animation: loader-39-2 0.8s linear infinite; - } - .loader-39:after { - width: 1em; - height: 0.3em; - -webkit-animation: loader-39-2 1.2s linear infinite; - animation: loader-39-2 1.2s linear infinite; - } - - @-webkit-keyframes loader-39-1 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loader-39-1 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - @-webkit-keyframes loader-39-2 { - 0% { - box-shadow: 0.04em -0.04em 0 0.02em currentcolor; - } - 25% { - box-shadow: 0.04em 0.04em 0 0.02em currentcolor; - } - 50% { - box-shadow: -0.04em 0.04em 0 0.02em currentcolor; - } - 75% { - box-shadow: -0.04em -0.04em 0 0.02em currentcolor; - } - 100% { - box-shadow: 0.04em -0.04em 0 0.02em currentcolor; - } - } - @keyframes loader-39-2 { - 0% { - box-shadow: 0.04em -0.04em 0 0.02em currentcolor; - } - 25% { - box-shadow: 0.04em 0.04em 0 0.02em currentcolor; - } - 50% { - box-shadow: -0.04em 0.04em 0 0.02em currentcolor; - } - 75% { - box-shadow: -0.04em -0.04em 0 0.02em currentcolor; - } - 100% { - box-shadow: 0.04em -0.04em 0 0.02em currentcolor; - } - } - .loader-40 { - border: 0.05em currentcolor solid; - border-radius: 0.2em; - overflow: hidden; - position: relative; - } - .loader-40:after, .loader-40:before { - content: ""; - border-radius: 50%; - position: absolute; - width: inherit; - height: inherit; - -webkit-animation: loader-40 2s infinite linear; - animation: loader-40 2s infinite linear; - } - .loader-40:before { - border-top: 0.2em currentcolor solid; - top: -0.15em; - left: calc(-50% - 0.15em); - -webkit-transform-origin: right center; - transform-origin: right center; - } - .loader-40:after { - border-bottom: 0.2em currentcolor solid; - top: 0.15em; - right: calc(-50% - 0.15em); - -webkit-transform-origin: left center; - transform-origin: left center; - } - - @-webkit-keyframes loader-40 { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - to { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } - } - - @keyframes loader-40 { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - to { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } - } - .loader-41 { - border: 0.05em currentcolor solid; - border-radius: 0.2em; - position: relative; - background: linear-gradient(45deg, transparent 48%, currentcolor 50%, currentcolor 50%, transparent 52%, transparent), linear-gradient(-45deg, transparent 48%, currentcolor 50%, currentcolor 50%, transparent 52%, transparent); - background-size: 0.5em 0.5em; - background-position: 0% 0%; - -webkit-animation: loader-41 1s infinite linear; - animation: loader-41 1s infinite linear; - } - - @-webkit-keyframes loader-41 { - from { - background-position: 0 0; - } - to { - background-position: -1em 0; - } - } - - @keyframes loader-41 { - from { - background-position: 0 0; - } - to { - background-position: -1em 0; - } +fieldset { + border: 0 !important; + margin: 0 !important; + padding: 0 !important; +} + +[class*="loader-"] { + display: inline-block; + width: 1em; + height: 1em; + color: inherit; + vertical-align: middle; + pointer-events: none; +} + +.loader-37 { + border-right: 0.1em solid currentcolor; + border-radius: 100%; + -webkit-animation: loader-37 800ms linear infinite; + animation: loader-37 800ms linear infinite; +} +.loader-37:before, +.loader-37:after { + content: ""; + width: 0.8em; + height: 0.8em; + display: block; + position: absolute; + top: calc(50% - 0.4em); + left: calc(50% - 0.4em); + border-left: 0.08em solid currentcolor; + border-radius: 100%; + animation: loader-37 400ms linear infinite reverse; +} +.loader-37:after { + width: 0.6em; + height: 0.6em; + top: calc(50% - 0.3em); + left: calc(50% - 0.3em); + border: 0; + border-right: 0.05em solid currentcolor; + -webkit-animation: none; + animation: none; +} + +@-webkit-keyframes loader-37 { + from { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } - .loader-42 { - width: 2em; - height: 0.66em; - border: 0.05em currentcolor solid; - border-radius: 0.1em; - background: linear-gradient(-60deg, transparent 0%, transparent 50%, currentcolor 50%, currentcolor 75%, transparent 75%, transparent); - background-size: 1em 2em; - background-position: 0 0; - -webkit-animation: loader-42 0.8s infinite linear; - animation: loader-42 0.8s infinite linear; + to { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } - - @-webkit-keyframes loader-42 { - from { - background-position: 0 0; - } - to { - background-position: -2em 0; - } +} + +@keyframes loader-37 { + from { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } - - @keyframes loader-42 { - from { - background-position: 0 0; - } - to { - background-position: -2em 0; - } + to { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } - - +} diff --git a/apps/OpenSign/src/styles/toast.css b/apps/OpenSign/src/styles/toast.css index 4e3ff0bc9..409833af9 100644 --- a/apps/OpenSign/src/styles/toast.css +++ b/apps/OpenSign/src/styles/toast.css @@ -1,209 +1,64 @@ #snackbar { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; + visibility: hidden; + min-width: 250px; + margin-left: -125px; + background-color: #333; + color: #fff; + text-align: center; + border-radius: 2px; + padding: 16px; + position: fixed; + z-index: 99999; + left: 50%; + top: 30px; + font-size: 14px; +} + +#snackbar.show { + visibility: visible; + -webkit-animation: fadein 0.5s; +} + +@-webkit-keyframes fadein { + from { + top: 0; + opacity: 0; + } + to { top: 30px; - font-size: 14px; + opacity: 1; } - - #_editsnackbar { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; - top: 30px; - font-size: 14px; - } - - #_editsnackbar.show { - visibility: visible; - -webkit-animation: fadein 0.5s; - } - - #UpdateColumnValue.show { - visibility: visible; - -webkit-animation: fadein 0.5s; +} + +@keyframes fadein { + from { + top: 0; + opacity: 0; } - #DeleteUser.show { - visibility: visible; - -webkit-animation: fadein 0.5s; - } - #DeleteUser { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; + to { top: 30px; - font-size: 14px; - } - - #deleteObj.show { - visibility: visible; - -webkit-animation: fadein 0.5s; + opacity: 1; } - #deleteObj { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; +} + +@-webkit-keyframes fadeout { + from { top: 30px; - font-size: 14px; + opacity: 1; } - - #UpdateColumnValue { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; - top: 30px; - font-size: 14px; - } - - #snackbar.show { - visibility: visible; - -webkit-animation: fadein 0.5s; + to { + top: 0; + opacity: 0; } - - #snackbar1 { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; +} + +@keyframes fadeout { + from { top: 30px; - font-size: 14px; - } - - #snackbar1.show { - visibility: visible; - -webkit-animation: fadein 0.5s; - } - - #snackbar10 { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; - top: 30px; - font-size: 14px; - } - - #snackbar10.show { - visibility: visible; - -webkit-animation: fadein 0.5s; - } - - #snackbarCol { - visibility: hidden; - min-width: 250px; - margin-left: -125px; - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 99999; - left: 50%; - top: 30px; - font-size: 14px; - } - - #snackbarCol.show { - visibility: visible; - -webkit-animation: fadein 0.5s; - } - - @-webkit-keyframes fadein { - from { - top: 0; - opacity: 0; - } - to { - top: 30px; - opacity: 1; - } - } - - @keyframes fadein { - from { - top: 0; - opacity: 0; - } - to { - top: 30px; - opacity: 1; - } - } - - @-webkit-keyframes fadeout { - from { - top: 30px; - opacity: 1; - } - to { - top: 0; - opacity: 0; - } + opacity: 1; } - - @keyframes fadeout { - from { - top: 30px; - opacity: 1; - } - to { - top: 0; - opacity: 0; - } + to { + top: 0; + opacity: 0; } - \ No newline at end of file +} From 416d8c823cc529e5a46a7a0364d67a683d44b59f Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Sat, 3 Feb 2024 18:29:49 +0530 Subject: [PATCH 47/73] refactor: remove unncessary code --- apps/OpenSign/src/json/FormJson.js | 385 ++--------------------- apps/OpenSign/src/routes/Form.js | 9 +- apps/OpenSign/src/routes/PageNotFound.js | 6 +- apps/OpenSign/src/routes/Report.js | 13 +- 4 files changed, 36 insertions(+), 377 deletions(-) diff --git a/apps/OpenSign/src/json/FormJson.js b/apps/OpenSign/src/json/FormJson.js index a8f8bc792..9edef57bf 100644 --- a/apps/OpenSign/src/json/FormJson.js +++ b/apps/OpenSign/src/json/FormJson.js @@ -1,369 +1,26 @@ import { documentCls, templateCls } from "../constant/const"; -export const formJson = (id) => { - let formData; +export const formJson = { //json form for signYourself - if (id === "sHAnZphf69") { - formData = { - title: "Sign Yourself", - redirectRoute: "signaturePdf", - msgVar: "Document", - Cls: documentCls - }; - return formData; - } + sHAnZphf69: { + title: "Sign Yourself", + redirectRoute: "signaturePdf", + msgVar: "Document", + Cls: documentCls + }, + //json form for request signature - else if (id === "8mZzFxbG1z") { - formData = { - title: "Request Signature", - msgVar: "Document", - redirectRoute: "placeHolderSign", - Cls: documentCls, - signers: true - }; - return formData; - } //json form for template - else if (id === "template") { - formData = { - title: "New Template", - redirectRoute: "template", - msgVar: "Template", - Cls: templateCls - }; - return formData; - } - //json form for create new folder - else if (id === "YjIB7W7Xs6") { - formData = { - jsonSchema: { - title: "New Folder", - description: "", - type: "object", - required: ["Name"], - properties: { - Name: { - type: "string", - title: "Name", - maxLength: 50 - }, - Type: { - type: "string", - data: { - valueKey: "Type", - isPointer: false - }, - default: "Folder" - }, - Folder: { - title: "Parent Folder", - data: { - class: "contracts_Document", - displayKey: "Name", - valueKey: "objectId", - query: 'where={"Type":"Folder"}&keys=Name', - isPointer: true, - savePointerClass: "", - helpbody: "", - helplink: "" - } - } - } - }, - uiSchema: { - Type: { - "ui:field": "HiddenField" - }, - Folder: { - "ui:field": "Level1Dropdown" - } - }, - userSchema: {}, - rules: null, - noValidate: false, - liveValidate: false, - isRegisterForm: false, - help: { htmlbody: "" }, - description: "", - class: "contracts_Document", - buttons: { - add: { - resetText: "Reset", - submitText: "Submit" - }, - edit: { submitText: "Update", cancelText: "Cancel" } - }, - formACL: { - "#currentUser#": { read: true, write: true }, - "*": { read: true, write: true } - }, - redirect_id: "", - success_message: "Success!", - success_redirect: "", - validFunction: - "ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ==" - }; - return formData; - } - //json form for add signers - else if (id === "fICciRuUcB") { - formData = { - jsonSchema: { - title: "Add Signer", - description: "", - type: "object", - required: ["Name", "Email", "Phone", "Company"], - properties: { - Name: { - type: "string", - title: "Name", - maxLength: 50 - }, - Email: { - type: "string", - title: "Email", - maxLength: 50 - }, - Phone: { - type: "string", - title: "Phone", - maxLength: 50 - }, - Company: { - type: "string", - title: "Company", - maxLength: 50 - }, - JobTitle: { - type: "string", - title: "JobTitle", - maxLength: 50 - }, - IsContactEntry: { - type: "boolean", - data: { - valueKey: "IsContactEntry", - isPointer: false - }, - default: true - } - } - }, - uiSchema: { - Email: { - "ui:widget": "email" - }, - IsContactEntry: { - "ui:field": "HiddenField" - } - }, - userSchema: { - email: "$Email", - name: "$Name", - password: "$Phone", - phone: "$Phone", - role: "contracts_User", - username: "$Email" - }, - rules: null, - noValidate: false, - liveValidate: false, - isRegisterForm: true, - help: {}, - description: "", - class: "contracts_Users", - buttons: { - add: { - resetText: "Reset", - submitText: "Submit" - }, - edit: { submitText: "Update", cancelText: "Cancel" } - }, - formACL: { - "#currentUser#": { read: true, write: true }, - "*": { read: true, write: true } - }, - redirect_id: "", - success_message: "Success!", - success_redirect: "", - validFunction: - "ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ==" - }; - return formData; - } - //json form for add users - else if (id === "lM0xRnM3iE") { - formData = { - jsonSchema: { - title: "Add User", - description: "", - type: "object", - required: ["Name", "Email", "Phone", "JobTitle"], - properties: { - Name: { - type: "string", - title: "Name", - maxLength: 50 - }, - Email: { - type: "string", - title: "Email", - maxLength: 50 - }, - Phone: { - type: "string", - title: "Phone", - maxLength: 50 - }, - JobTitle: { - type: "string", - title: "Job Title", - maxLength: 50 - }, - Company: { - type: "string", - title: "Company", - maxLength: 50 - } - } - }, - uiSchema: { - Email: { - "ui:widget": "email" - }, - Phone: { - "ui:options": { - inputType: "tel" - } - } - }, - userSchema: { - email: "$Email", - name: "$Name", - password: "$Phone", - phone: "$Phone", - role: "contracts_User", - username: "$Email" - }, - rules: null, - noValidate: false, - liveValidate: false, - isRegisterForm: true, - help: {}, - description: "", - class: "contracts_Users", - buttons: { - add: { - resetText: "Reset", - submitText: "Submit" - }, - edit: { submitText: "Update", cancelText: "Cancel" } - }, - formACL: { - "#currentUser#": { read: true, write: true }, - "*": { read: true, write: true } - }, - redirect_id: "", - success_message: "Success!", - success_redirect: "", - validFunction: - "ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ==" - }; - return formData; - } else if (id === "qUGywSWd8e") { - formData = { - jsonSchema: { - title: "Add Contact", - description: "", - type: "object", - required: ["Name", "Email", "Phone"], - properties: { - Name: { - type: "string", - title: "Name", - maxLength: 50 - }, - Email: { - type: "string", - title: "Email", - maxLength: 50 - }, - Phone: { - type: "string", - title: "Phone", - maxLength: 50 - } - } - }, - uiSchema: { - Email: { - "ui:widget": "email" - }, - Phone: { - "ui:options": { - inputType: "tel" - } - } - }, - userSchema: { - name: "$Name", - username: "$Email", - email: "$Email", - password: "$Phone", - phone: "$Phone", - role: "contracts_Guest" - }, - restrict_form_entry: { - enable_captcha: false, - allow_one_entry_per_ip_address: false, - allow_one_entry_per_user: false, - enable_geo_fence: false - }, - restrict_form_access: { - entryCount: "" - }, - help: {}, - email_template: { - from: "", - to: "", - subject: "", - message: "" - }, - buttons: { - add: { - submitText: "Submit", - resetText: "Reset" - }, - edit: { - submitText: "Update", - cancelText: "Cancel" - } - }, - appId: { - __type: "Pointer", - className: "w_appinfo", - objectId: "aIPmIvMzGM" - }, - formACL: { - "*": { - read: true, - write: true - }, - "#currentUser#": { - read: true, - write: true - } - }, - class: "contracts_Contactbook", - description: "", - success_message: "Success!", - form_permission: "private", - success_redirect: "", - redirect_id: "", - isRegisterForm: true, - liveValidate: false, - noValidate: false, - validFunction: - "ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ==" - }; - return formData; + "8mZzFxbG1z": { + title: "Request Signature", + msgVar: "Document", + redirectRoute: "placeHolderSign", + Cls: documentCls, + signers: true + }, + //json form for template + template: { + title: "New Template", + redirectRoute: "template", + msgVar: "Template", + Cls: templateCls } }; diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index da272e27f..0bf604eaa 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -9,6 +9,7 @@ import Alert from "../primitives/Alert"; import SelectFolder from "../components/fields/SelectFolder"; import SignersInput from "../components/fields/SignersInput"; import Title from "../components/Title"; +import PageNotFound from "./PageNotFound"; function Form() { const { id } = useParams(); @@ -16,8 +17,12 @@ function Form() { if (id === "lM0xRnM3iE") { return <AddUser />; } else { - const config = formJson(id) || {}; - return <Forms {...config} />; + const config = formJson[id]; + if (config) { + return <Forms {...config} />; + } else { + return <PageNotFound prefix={"Form"} />; + } } } diff --git a/apps/OpenSign/src/routes/PageNotFound.js b/apps/OpenSign/src/routes/PageNotFound.js index be8d10e6d..825cb98fb 100644 --- a/apps/OpenSign/src/routes/PageNotFound.js +++ b/apps/OpenSign/src/routes/PageNotFound.js @@ -2,7 +2,7 @@ import React from "react"; import Title from "../components/Title"; -const PageNotFound = () => { +const PageNotFound = ({ prefix }) => { return ( <div className="flex items-center justify-center h-screen w-full bg-white rounded"> <Title title={"Page Not Found"} /> @@ -10,7 +10,9 @@ const PageNotFound = () => { <h1 className="text-[60px] lg:text-[120px] font-semibold text-black"> 404 </h1> - <p className="text-[30px] lg:text-[50px] text-black">Page Not Found</p> + <p className="text-[30px] lg:text-[50px] text-black"> + {prefix ? prefix : "Page"} Not Found + </p> </div> </div> ); diff --git a/apps/OpenSign/src/routes/Report.js b/apps/OpenSign/src/routes/Report.js index af3273095..b47be1f34 100644 --- a/apps/OpenSign/src/routes/Report.js +++ b/apps/OpenSign/src/routes/Report.js @@ -5,6 +5,7 @@ import axios from "axios"; import reportJson from "../json/ReportJson"; import { useParams } from "react-router-dom"; import Title from "../components/Title"; +import PageNotFound from "./PageNotFound"; const Report = () => { const { id } = useParams(); @@ -15,7 +16,7 @@ const Report = () => { const [heading, setHeading] = useState([]); const [isNextRecord, setIsNextRecord] = useState(false); const [isMoreDocs, setIsMoreDocs] = useState(true); - const [form, setForm]= useState("") + const [form, setForm] = useState(""); const abortController = new AbortController(); const docPerPage = 10; @@ -51,7 +52,7 @@ const Report = () => { setActions(json.actions); setHeading(json.heading); setReportName(json.reportName); - setForm(json.form) + setForm(json.form); Parse.serverURL = localStorage.getItem("BaseUrl12"); Parse.initialize(localStorage.getItem("AppID12")); const currentUser = Parse.User.current().id; @@ -159,13 +160,7 @@ const Report = () => { form={form} /> ) : ( - <div className="flex items-center justify-center h-screen w-full bg-white rounded"> - <div className="text-center"> - <p className="text-[30px] lg:text-[50px] text-black"> - Report Not Found - </p> - </div> - </div> + <PageNotFound prefix={"Report"} /> )} </> )} From c115c7c7579b6a67ea0672173728fc4d3b3173fe Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Sat, 3 Feb 2024 18:51:58 +0530 Subject: [PATCH 48/73] fix: createdocument & createtemplate api not working properly --- .../v1/routes/createDocumentwithCoordinate.js | 69 ++++++++++-------- .../v1/routes/createTemplatewithCoordinate.js | 71 +++++++++++-------- 2 files changed, 82 insertions(+), 58 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index 8c1c4e68d..217ca5e2d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -108,35 +108,48 @@ export default async function createDocumentwithCoordinate(request, response) { 'Signers', contact?.map(x => x.contactPtr) ); - let updatePlaceholders = contact.map(x => { + let updatePlaceholders = contact.map((signer, index) => { + const placeHolder = []; + + for (const widget of signer.widgets) { + const pageNumber = widget.page; + const page = placeHolder.find(page => page.pageNumber === pageNumber); + + const widgetData = { + xPosition: widget.x, + yPosition: widget.y, + isStamp: widget.type === 'stamp', + key: Math.floor(Math.random() * 10000), + isDrag: false, + firstXPos: widget.x, + firstYPos: widget.y, + yBottom: 0, + scale: 1, + isMobile: false, + zIndex: 1, + type: widget.type, + widgetValue: '', + Width: widget.w, + Height: widget.h, + }; + + if (page) { + page.pos.push(widgetData); + } else { + placeHolder.push({ + pageNumber, + pos: [widgetData], + }); + } + } + return { - signerObjId: x?.contactPtr?.objectId, - signerPtr: x?.contactPtr, - Role: x.role, - Id: randomId(), - blockColor: color[x?.index], - placeHolder: x.widgets.map((widget, i) => ({ - pageNumber: widget.page, - pos: [ - { - xPosition: widget.x, - yPosition: widget.y, - isStamp: widget.type === 'stamp' || widget.type === 'image' ? true : false, - key: randomId(), - isDrag: false, - firstXPos: widget.x, - firstYPos: widget.y, - yBottom: 0, - scale: 1, - isMobile: false, - zIndex: i + 1, - type: widget.type, - widgetValue: '', - Width: widget.w, - Height: widget.h, - }, - ], - })), + signerObjId: signer?.contactPtr?.objectId, + signerPtr: signer?.contactPtr, + Role: signer.role, + Id: 3000 + index * 1000, + blockColor: color[signer?.index], + placeHolder, }; }); object.set('Placeholders', updatePlaceholders); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index 8e6c619e9..4c753a6d0 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -113,39 +113,50 @@ export default async function createTemplatewithCoordinate(request, response) { updatedSigners?.map(x => x.contactPtr) ); } - let updatePlaceholders = contact.map(x => { + let updatePlaceholders = contact.map((signer, index) => { + const placeHolder = []; + + for (const widget of signer.widgets) { + const pageNumber = widget.page; + const page = placeHolder.find(page => page.pageNumber === pageNumber); + + const widgetData = { + xPosition: widget.x, + yPosition: widget.y, + isStamp: widget.type === 'stamp', + key: Math.floor(Math.random() * 10000), + isDrag: false, + firstXPos: widget.x, + firstYPos: widget.y, + yBottom: 0, + scale: 1, + isMobile: false, + zIndex: 1, + type: widget.type, + widgetValue: '', + Width: widget.w, + Height: widget.h, + }; + + if (page) { + page.pos.push(widgetData); + } else { + placeHolder.push({ + pageNumber, + pos: [widgetData], + }); + } + } + return { - signerObjId: x?.contactPtr?.objectId || '', - signerPtr: x?.contactPtr || {}, - Role: x.role, - Id: randomId(), - blockColor: color[x?.index], - placeHolder: x.widgets.map((widget, i) => ({ - pageNumber: widget.page, - pos: [ - { - xPosition: widget.x, - yPosition: widget.y, - isStamp: widget.type === 'stamp' || widget.type === 'image' ? true : false, - key: randomId(), - isDrag: false, - firstXPos: widget.x, - firstYPos: widget.y, - yBottom: 0, - scale: 1, - isMobile: false, - zIndex: i + 1, - type: widget.type, - widgetValue: '', - Width: widget.w, - Height: widget.h, - }, - ], - })), + signerObjId: signer?.contactPtr?.objectId, + signerPtr: signer?.contactPtr, + Role: signer.role, + Id: 3000 + index * 1000, + blockColor: color[signer?.index], + placeHolder, }; }); - // console.log('updatePLacholders', updatePlaceholders); - object.set('Placeholders', updatePlaceholders); } if (folderId) { From f9e59905b7255a1f6eea91d01cd24572cee6f03f Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Sat, 3 Feb 2024 18:55:23 +0530 Subject: [PATCH 49/73] refactor: generate randomId in createDocument and createTemplate API --- .../customRoute/v1/routes/createDocumentwithCoordinate.js | 4 ++-- .../customRoute/v1/routes/createTemplatewithCoordinate.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index 217ca5e2d..aa4f475f4 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -119,7 +119,7 @@ export default async function createDocumentwithCoordinate(request, response) { xPosition: widget.x, yPosition: widget.y, isStamp: widget.type === 'stamp', - key: Math.floor(Math.random() * 10000), + key: randomId(), isDrag: false, firstXPos: widget.x, firstYPos: widget.y, @@ -147,7 +147,7 @@ export default async function createDocumentwithCoordinate(request, response) { signerObjId: signer?.contactPtr?.objectId, signerPtr: signer?.contactPtr, Role: signer.role, - Id: 3000 + index * 1000, + Id: randomId(), blockColor: color[signer?.index], placeHolder, }; diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index 4c753a6d0..4624e2ba3 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -124,7 +124,7 @@ export default async function createTemplatewithCoordinate(request, response) { xPosition: widget.x, yPosition: widget.y, isStamp: widget.type === 'stamp', - key: Math.floor(Math.random() * 10000), + key: randomId(), isDrag: false, firstXPos: widget.x, firstYPos: widget.y, @@ -152,7 +152,7 @@ export default async function createTemplatewithCoordinate(request, response) { signerObjId: signer?.contactPtr?.objectId, signerPtr: signer?.contactPtr, Role: signer.role, - Id: 3000 + index * 1000, + Id: randomId(), blockColor: color[signer?.index], placeHolder, }; From f0655893ebfa6d42f3607eb7e7f2ef303a2305b6 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 5 Feb 2024 11:23:47 +0530 Subject: [PATCH 50/73] change response of createdocument API --- .../v1/routes/createDocumentwithCoordinate.js | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index aa4f475f4..e651a3a92 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -233,19 +233,14 @@ export default async function createDocumentwithCoordinate(request, response) { } if (sendMail.data.result.status === 'success') { - const user = contact.find(x => x.email === parseExtUser.Email); - if (user && user.email) { - return response.json({ - objectId: res.id, - url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${user.email}/${user.contactPtr.objectId}/${serverParams}`, - message: 'Document sent successfully!', - }); - } else { - return response.json({ - objectId: res.id, - message: 'Document sent successfully!', - }); - } + return response.json({ + objectId: res.id, + signurl: contact.map(x => ({ + email: x.email, + url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`, + })), + message: 'Document sent successfully!', + }); } } else { return response.status(400).json({ error: 'Please provide signers!' }); From 9692f57663e9ecad07a14b9ac9a05f5b8fc7adc8 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 5 Feb 2024 13:29:36 +0530 Subject: [PATCH 51/73] feat: provide widgets in create document from binary and create template from binary --- apps/OpenSignServer/cloud/customRoute/v1/apiV1.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index cf671c8d9..7befaec65 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -50,10 +50,10 @@ app.delete('/contact/:contact_id', deleteContact); app.get('/contactlist', getContactList); // create Document -app.post('/createdocumentwithbinary', upload.array('file', 1), createDocument); +app.post('/createdocumentwithbinary', upload.array('file', 1), createDocumentwithCoordinate); // create Document with co-ordinate -app.post('/createdocument', upload.array('file', 1), createDocumentwithCoordinate); +app.post('/createdocument', createDocumentwithCoordinate); // create Document with base64 without placeholder app.post('/draftdocument', createDocument); @@ -74,13 +74,13 @@ app.delete('/document/:document_id', deleteDocument); app.get('/documentlist/:doctype', getDocumentList); // create Template with co-ordinate -app.post('/createtemplate', upload.array('file', 1), createTemplatewithCoordinate); +app.post('/createtemplate', createTemplatewithCoordinate); // create Template app.post('/drafttemplate', createTemplate); // create Template with binary -app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplate); +app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplatewithCoordinate); // get template on the basis of id app.get('/template/:template_id', getTemplate); From da846dcbbb8d67050992045924b03c2733d3ad58 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 5 Feb 2024 18:26:22 +0530 Subject: [PATCH 52/73] fix: issue of request payload entity too large --- .../cloud/parsefunction/pdf/PDF.min.js | 42 +++++++++---------- apps/OpenSignServer/index.js | 3 +- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 7b2f197d4..c646e9c1a 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -1,21 +1,18 @@ import SignPDF from './SignPDF.min.cjs'; import fs from 'node:fs'; import axios from 'axios'; -import FormData from 'form-data'; import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js'; const serverUrl = process.env.SERVER_URL, APPID = process.env.APP_ID, masterKEY = process.env.MASTER_KEY; -async function uploadFile(a) { +async function uploadFile(e, a) { try { - var e = new FormData(), - t = - (e.append('file', fs.createReadStream(a)), - { 'content-type': 'multipart/form-data', 'X-Parse-Application-Id': process.env.APP_ID }), - s = process.env.SERVER_URL.slice(0, -4) + '/file_upload'; - return (await axios.post(s, e, { headers: t })).data; + var t = fs.readFileSync(a), + s = new Parse.File(e, [...t]), + r = (await s.save({ useMasterKey: !0 }), s.url()); + return { imageUrl: r }; } catch (e) { - console.log('err ', e), fs.unlinkSync(a); + console.log('Err ', e), fs.unlinkSync(a); } } async function updateDoc(t, s, r, i, o, n) { @@ -224,8 +221,9 @@ async function PDF(i, o) { ); var P, v, - x = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`, - b = + x = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`, + b = './exports/' + x, + U = (t ? ((P = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), (e = @@ -243,13 +241,13 @@ async function PDF(i, o) { signatureLength: 1e4, })), (v = await new SignPDF(e, u).signPDF()), - fs.writeFileSync(x, v)) - : fs.writeFileSync(x, e), - await uploadFile(x)); - if (b && b.imageUrl) { + fs.writeFileSync(b, v)) + : fs.writeFileSync(b, e), + await uploadFile(x, b)); + if (U && U.imageUrl) { const o = await updateDoc( i.params.docId, - b.imageUrl, + U.imageUrl, s.data.results[0].objectId, i.headers['x-real-ip'], n.data, @@ -257,7 +255,7 @@ async function PDF(i, o) { ); return ( sendMail({ - url: b.imageUrl, + url: U.imageUrl, sender: { Mail: n.data.ExtUserPtr.Email, Name: n.data.ExtUserPtr.Name }, pdfName: n.data.Name, receiver: g, @@ -265,16 +263,16 @@ async function PDF(i, o) { o && o.isCompleted && (sendCompletedMail({ - url: b.imageUrl, + url: U.imageUrl, sender: { Mail: n.data.ExtUserPtr.Email, Name: 'Open sign' }, pdfName: n.data.Name, receiver: n.data.ExtUserPtr.Email, }), - sendDoctoWebhook(n, b.imageUrl)), - fs.unlinkSync(x), - console.log('New Signed PDF created called: ' + x), + sendDoctoWebhook(n, U.imageUrl)), + fs.unlinkSync(b), + console.log('New Signed PDF created called: ' + b), 'success' === o.message - ? { status: 'success', data: b.imageUrl } + ? { status: 'success', data: U.imageUrl } : { status: 'error', message: 'please provide required parameters!' } ); } diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 92deb1572..28d63e64a 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -131,7 +131,8 @@ export const config = { export const app = express(); app.use(cors()); - +app.use(express.json({ limit: '50mb' })); +app.use(express.urlencoded({ limit: '50mb', extended: true })); app.use(function (req, res, next) { // console.log("req ", req.headers); // console.log("x-forwarded-for", req.headers["x-forwarded-for"]); From db9ec6bfd53c7c2f397d0367a536034c7cef52d7 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 7 Feb 2024 12:08:27 +0530 Subject: [PATCH 53/73] fix: handle error for small screen in debug pdf page --- .../SignDocuments/src/Component/DebugUi.js | 416 +++++++++--------- .../SignDocuments/src/hook/useWindowSize.js | 25 ++ 2 files changed, 227 insertions(+), 214 deletions(-) create mode 100644 microfrontends/SignDocuments/src/hook/useWindowSize.js diff --git a/microfrontends/SignDocuments/src/Component/DebugUi.js b/microfrontends/SignDocuments/src/Component/DebugUi.js index 39237fd59..3423abd04 100644 --- a/microfrontends/SignDocuments/src/Component/DebugUi.js +++ b/microfrontends/SignDocuments/src/Component/DebugUi.js @@ -1,13 +1,14 @@ -import React, { useEffect, useState, useRef } from "react"; +import React, { useEffect, useState } from "react"; import RenderAllPdfPage from "./component/renderAllPdfPage"; import "../css/./signature.css"; -import { pdfNewWidthFun } from "../utils/Utils"; import "../css/AddUser.css"; import Title from "./component/Title"; import ModalUi from "../premitives/ModalUi"; import RenderDebugPdf from "./component/RenderDebugPdf"; import { pdfjs } from "react-pdf"; import Alert from "../premitives/Alert"; +import HandleError from "./component/HandleError"; +import { useWindowSize } from "../hook/useWindowSize"; function processDimensions(x, y, width, height) { if (width < 0) { @@ -28,15 +29,11 @@ function processDimensions(x, y, width, height) { }; } const DebugUi = () => { - const divRef = useRef(null); - const isMobile = window.innerWidth < 767; + const { width } = useWindowSize(); const [pdf, setPdf] = useState(""); const [isModal, setIsModal] = useState(true); const [allPages, setAllPages] = useState(null); const [pageNumber, setPageNumber] = useState(1); - const [pdfNewWidth, setPdfNewWidth] = useState(); - const [containerWH, setContainerWH] = useState(); - const [pdfOriginalWidth, setPdfOriginalWidth] = useState(); const [pdfLoadFail, setPdfLoadFail] = useState({ status: false, type: "load" @@ -51,21 +48,10 @@ const DebugUi = () => { base64: "" }); const [hoverCoordinates, setHoverCoordinates] = useState({ x: 0, y: 0 }); - const [drawing, setDrawing] = useState(false); const [pdfDimension, setPdfDimension] = useState({ width: 0, height: 0 }); const [annotations, setAnnotations] = useState([]); const [newAnnotation, setNewAnnotation] = useState([]); const [copied, setCopied] = useState(false); - useEffect(() => { - if (divRef.current) { - const pdfWidth = pdfNewWidthFun(divRef); - setPdfNewWidth(pdfWidth); - setContainerWH({ - width: divRef.current.offsetWidth, - height: divRef.current.offsetHeight - }); - } - }, [divRef.current]); useEffect(() => { if (pdf && pdf.name) { @@ -233,207 +219,209 @@ const DebugUi = () => { <div> {copied && <Alert type="success">Copied</Alert>} <Title title={"Debug Pdf"} /> - {!isModal && ( - <div className="signatureContainer" ref={divRef}> - {/* this component used to render all pdf pages in left side */} - <RenderAllPdfPage - signPdfUrl={pdf} - allPages={allPages} - setAllPages={setAllPages} - setPageNumber={setPageNumber} - pageNumber={pageNumber} - /> - {/* pdf render view */} - <div - style={{ - marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px", - marginRight: !isMobile && pdfOriginalWidth > 500 && "20px" - }} - > - <div data-tut="reactourThird"> - {containerWH && ( - <RenderDebugPdf - pdfUrl={pdf} - pageDetails={pageDetails} - pageNumber={pageNumber} - pdfOriginalWidth={pdfOriginalWidth} - pdfNewWidth={pdfNewWidth} - setPdfLoadFail={setPdfLoadFail} - pdfLoadFail={pdfLoadFail} - handlePageLoadSuccess={handlePageLoadSuccess} - handleMouseMove={handleMouseMove} - handleMouseUp={handleMouseUp} - handleMouseDown={handleMouseDown} - hoverCoordinates={hoverCoordinates} - annotations={annotationsToDraw} - pdfDimension={pdfDimension} - handleMouseMoveDiv={handleMouseMoveDiv} - /> - )} - </div> - </div> - <div style={{ backgroundColor: "white", width: 220 }}> - <div - style={{ - fontSize: 18, - fontWeight: 500, - padding: "10px 12px", - borderBottom: "1px solid grey" - }} - > - PDF details - </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - Name: {pdfDetails?.name} - </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - Pdf type: {pdfDetails?.pdftype} - </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - Total Pages: {pdfDetails?.totalPages} - </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - Current Page: {pdfDetails?.currentPage} + {width < 800 ? ( + <HandleError handleError={"Debug PDF only availble for PC"} /> + ) : ( + <> + {!isModal && ( + <div className="signatureContainer"> + {/* this component used to render all pdf pages in left side */} + <RenderAllPdfPage + signPdfUrl={pdf} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + pageNumber={pageNumber} + /> + {/* pdf render view */} + <div> + <div data-tut="reactourThird"> + <RenderDebugPdf + pdfUrl={pdf} + pageDetails={pageDetails} + pageNumber={pageNumber} + setPdfLoadFail={setPdfLoadFail} + pdfLoadFail={pdfLoadFail} + handlePageLoadSuccess={handlePageLoadSuccess} + handleMouseMove={handleMouseMove} + handleMouseUp={handleMouseUp} + handleMouseDown={handleMouseDown} + hoverCoordinates={hoverCoordinates} + annotations={annotationsToDraw} + pdfDimension={pdfDimension} + handleMouseMoveDiv={handleMouseMoveDiv} + /> + </div> + </div> + <div style={{ backgroundColor: "white", width: 220 }}> + <div + style={{ + fontSize: 18, + fontWeight: 500, + padding: "10px 12px", + borderBottom: "1px solid grey" + }} + > + PDF details + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Name: {pdfDetails?.name} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Pdf type: {pdfDetails?.pdftype} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Total Pages: {pdfDetails?.totalPages} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Current Page: {pdfDetails?.currentPage} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + Base64 : {pdfDetails?.base64.slice(0, 10)}... + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => copytoclipboard(pdfDetails?.base64)} + > + <i className="fa-solid fa-copy"></i> + </span> + </div> + <div + style={{ + fontSize: 18, + fontWeight: 500, + padding: "10px 12px", + borderBottom: "1px solid grey" + }} + > + Last click + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + x co-ordinate: {pdfDetails?.x} + </div> + <div style={{ fontSize: 14, padding: "5px 12px" }}> + y co-ordinate: {pdfDetails?.y} + </div> + + <div + style={{ + fontSize: 18, + fontWeight: 500, + padding: "10px 12px", + borderBottom: "1px solid grey", + borderTop: "1px solid grey" + }} + > + Annotation + </div> + <ul + style={{ + listStyle: "none", + padding: 10, + height: 500, + overflowY: "auto", + scrollbarWidth: 5 + }} + > + {annotations.map((coord, index) => ( + <li key={index}> + <span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${ + index + 1 + }:`}</span> + <code + style={{ + fontSize: 12, + color: "black", + cursor: "pointer" + }} + > + {` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`} + </code> + <div> + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => + copytoclipboard( + `"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}` + ) + } + > + <i className="fa-solid fa-copy"></i> + </span> + <span + style={{ + borderRadius: 4, + padding: "3px 5px", + border: "1px solid gray", + fontSize: 12, + margin: 2, + cursor: "pointer" + }} + onClick={() => handleDelete(coord.key)} + > + <i className="fa-solid fa-trash-can"></i> + </span> + </div> + </li> + ))} + </ul> + </div> </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - Base64 : {pdfDetails?.base64.slice(0, 10)}... - <span + )} + <ModalUi title={"Select PDF"} isOpen={isModal}> + <form onSubmit={handleSubmit} style={{ margin: "10px" }}> + <input + type="file" + onChange={(e) => handleFileChange(e.target.files)} style={{ - borderRadius: 4, - padding: "3px 5px", - border: "1px solid gray", - fontSize: 12, - margin: 2, - cursor: "pointer" + width: "100%", + border: "1px solid grey", + borderRadius: "4px", + padding: "5px", + fontSize: 12 }} - onClick={() => copytoclipboard(pdfDetails?.base64)} + accept=".pdf" + required + /> + <div + style={{ borderTop: "1px solid grey", margin: "10px 0" }} + ></div> + <button + style={{ + background: "#32a3ac", + borderRadius: "2px", + boxShadow: + "0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)", + border: "none", + textTransform: "uppercase", + fontSize: "13px", + fontWeight: "600", + padding: "0.375rem 0.75rem", + textAlign: "center", + color: "#ffffff", + outline: "none" + }} + type="submit" > - <i className="fa-solid fa-copy"></i> - </span> - </div> - <div - style={{ - fontSize: 18, - fontWeight: 500, - padding: "10px 12px", - borderBottom: "1px solid grey" - }} - > - Last click - </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - x co-ordinate: {pdfDetails?.x} - </div> - <div style={{ fontSize: 14, padding: "5px 12px" }}> - y co-ordinate: {pdfDetails?.y} - </div> - - <div - style={{ - fontSize: 18, - fontWeight: 500, - padding: "10px 12px", - borderBottom: "1px solid grey", - borderTop: "1px solid grey" - }} - > - Annotation - </div> - <ul - style={{ - listStyle: "none", - padding: 10, - height: 500, - overflowY: "auto", - scrollbarWidth: 5 - }} - > - {annotations.map((coord, index) => ( - <li key={index}> - <span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${ - index + 1 - }:`}</span> - <code - style={{ fontSize: 12, color: "black", cursor: "pointer" }} - > - {` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`} - </code> - <div> - <span - style={{ - borderRadius: 4, - padding: "3px 5px", - border: "1px solid gray", - fontSize: 12, - margin: 2, - cursor: "pointer" - }} - onClick={() => - copytoclipboard( - `"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}` - ) - } - > - <i className="fa-solid fa-copy"></i> - </span> - <span - style={{ - borderRadius: 4, - padding: "3px 5px", - border: "1px solid gray", - fontSize: 12, - margin: 2, - cursor: "pointer" - }} - onClick={() => handleDelete(coord.key)} - > - <i className="fa-solid fa-trash-can"></i> - </span> - </div> - </li> - ))} - </ul> - </div> - </div> + Submit + </button> + </form> + </ModalUi> + </> )} - - <ModalUi title={"Select PDF"} isOpen={isModal}> - <form onSubmit={handleSubmit} style={{ margin: "10px" }}> - <input - type="file" - onChange={(e) => handleFileChange(e.target.files)} - style={{ - width: "100%", - border: "1px solid grey", - borderRadius: "4px", - padding: "5px", - fontSize: 12 - }} - accept=".pdf" - required - /> - <div style={{ borderTop: "1px solid grey", margin: "10px 0" }}></div> - <button - style={{ - background: "#32a3ac", - borderRadius: "2px", - boxShadow: - "0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)", - border: "none", - textTransform: "uppercase", - fontSize: "13px", - fontWeight: "600", - padding: "0.375rem 0.75rem", - textAlign: "center", - color: "#ffffff", - outline: "none" - }} - type="submit" - > - Submit - </button> - </form> - </ModalUi> </div> ); }; diff --git a/microfrontends/SignDocuments/src/hook/useWindowSize.js b/microfrontends/SignDocuments/src/hook/useWindowSize.js new file mode 100644 index 000000000..0c84d6f13 --- /dev/null +++ b/microfrontends/SignDocuments/src/hook/useWindowSize.js @@ -0,0 +1,25 @@ +import { useEffect, useState } from "react"; + +export function useWindowSize() { + const [size, setSize] = useState({ + width: 0, + height: 0 + }); + + const onResize = () => { + setSize({ + width: window.innerWidth, + height: window.innerHeight + }); + }; + + useEffect(() => { + onResize(); + window.addEventListener("resize", onResize); + return () => { + window.removeEventListener("resize", onResize); + }; + }, []); + + return size; +} From 1a774bfcfabd80ff916d0d3f49d3b3d1a9568382 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 7 Feb 2024 12:52:51 +0530 Subject: [PATCH 54/73] feat: add Signed event for webhook --- .../cloud/parsefunction/pdf/PDF.min.js | 114 ++++++++++-------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index c646e9c1a..a70ea21c0 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -92,55 +92,62 @@ async function sendCompletedMail(e) { }, }); } -async function sendDoctoWebhook(t, e) { - t.data.ExtUserPtr?.Webhook && - ((e = { - File: e || '', - Name: t?.data?.Name, - Note: t?.data?.Note || '', - Description: t?.data?.Description || '', - Signers: t?.data?.Signers?.map(e => ({ Name: e.Name, Email: e.Email, Phone: e.Phone })) || [ +async function sendDoctoWebhook(t, e, a, s) { + let r = []; + (r = s + ? { Name: s?.Name, Email: s?.Email, Phone: s?.Phone } + : t?.data?.Signers?.map(e => ({ Name: e.Name, Email: e.Email, Phone: e.Phone })) || [ { Name: t?.data?.ExtUserPtr?.Name, Email: t?.data?.ExtUserPtr?.Email, Phone: t?.data?.ExtUserPtr?.Phone, }, - ], - Event: 'Completed', - CompletedAt: new Date(), - CreatedAt: t?.data?.createdAt, - }), - await axios - .post(t?.data?.ExtUserPtr?.Webhook, e, { headers: { 'Content-Type': 'application/json' } }) - .then(e => { - try { - var a = new Parse.Object('contracts_Webhook'); - a.set('Log', e?.status), - a.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: t.data.ExtUserPtr.UserId.objectId, - }), - a.save(null, { useMasterKey: !0 }); - } catch (e) { - console.log('err save in contracts_Webhook', e); - } - }) - .catch(e => { - console.log('Err send data to webhook', e); - try { - var a = new Parse.Object('contracts_Webhook'); - a.set('Log', e?.status), - a.set('UserId', { - __type: 'Pointer', - className: '_User', - objectId: t.data.ExtUserPtr.UserId.objectId, - }), - a.save(null, { useMasterKey: !0 }); - } catch (e) { - console.log('err save in contracts_Webhook', e); - } - })); + ]), + t.data.ExtUserPtr?.Webhook && + ((s = + 'Signed' === a + ? { Signer: r, SignedAt: new Date() } + : { Signers: r, CompletedAt: new Date() }), + (a = { + Event: a, + File: e || '', + Name: t?.data?.Name, + Note: t?.data?.Note || '', + Description: t?.data?.Description || '', + ...s, + CreatedAt: t?.data?.createdAt, + }), + await axios + .post(t?.data?.ExtUserPtr?.Webhook, a, { headers: { 'Content-Type': 'application/json' } }) + .then(e => { + try { + var a = new Parse.Object('contracts_Webhook'); + a.set('Log', e?.status), + a.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: t.data.ExtUserPtr.UserId.objectId, + }), + a.save(null, { useMasterKey: !0 }); + } catch (e) { + console.log('err save in contracts_Webhook', e); + } + }) + .catch(e => { + console.log('Err send data to webhook', e); + try { + var a = new Parse.Object('contracts_Webhook'); + a.set('Log', e?.status), + a.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: t.data.ExtUserPtr.UserId.objectId, + }), + a.save(null, { useMasterKey: !0 }); + } catch (e) { + console.log('err save in contracts_Webhook', e); + } + })); } async function PDF(i, o) { try { @@ -221,8 +228,8 @@ async function PDF(i, o) { ); var P, v, - x = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`, - b = './exports/' + x, + b = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`, + x = './exports/' + b, U = (t ? ((P = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), @@ -241,9 +248,9 @@ async function PDF(i, o) { signatureLength: 1e4, })), (v = await new SignPDF(e, u).signPDF()), - fs.writeFileSync(b, v)) - : fs.writeFileSync(b, e), - await uploadFile(x, b)); + fs.writeFileSync(x, v)) + : fs.writeFileSync(x, e), + await uploadFile(b, x)); if (U && U.imageUrl) { const o = await updateDoc( i.params.docId, @@ -260,17 +267,18 @@ async function PDF(i, o) { pdfName: n.data.Name, receiver: g, }), + sendDoctoWebhook(n, U.imageUrl, 'Signed', s?.data.results?.[0]), o && o.isCompleted && (sendCompletedMail({ url: U.imageUrl, - sender: { Mail: n.data.ExtUserPtr.Email, Name: 'Open sign' }, + sender: { Mail: n.data.ExtUserPtr.Email, Name: 'OpenSign™' }, pdfName: n.data.Name, receiver: n.data.ExtUserPtr.Email, }), - sendDoctoWebhook(n, U.imageUrl)), - fs.unlinkSync(b), - console.log('New Signed PDF created called: ' + b), + sendDoctoWebhook(n, U.imageUrl, 'Completed')), + fs.unlinkSync(x), + console.log('New Signed PDF created called: ' + x), 'success' === o.message ? { status: 'success', data: U.imageUrl } : { status: 'error', message: 'please provide required parameters!' } From eb01a0b17dad32f560710ab30b1b96700d4a9778 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 7 Feb 2024 22:01:32 +0530 Subject: [PATCH 55/73] feat:add declined, created event which is send document on webhook --- .../v1/routes/CreateDocumentWithTemplate.js | 4 + .../customRoute/v1/routes/createDocument.js | 2 + .../v1/routes/createDocumentwithCoordinate.js | 59 +++++++++++- apps/OpenSignServer/cloud/main.js | 2 + .../cloud/parsefunction/callWebhook.js | 66 +++++++++++++ .../cloud/parsefunction/pdf/PDF.min.js | 96 ++++++++++--------- .../src/Component/PdfRequestFiles.js | 30 +++++- 7 files changed, 211 insertions(+), 48 deletions(-) create mode 100644 apps/OpenSignServer/cloud/parsefunction/callWebhook.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index dacc083e7..8d61d3327 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -7,6 +7,8 @@ export default async function createDocumentWithTemplate(request, response) { const templateId = request.params.template_id; const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); + const send_email = request.body.send_email || true; + try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -48,6 +50,8 @@ export default async function createDocumentWithTemplate(request, response) { if (template?.Description) { object.set('Description', template.Description); } + object.set('IsSendMail', send_email); + let templateSigner = template?.Signers ? template?.Signers : []; let contact = []; if (signers && signers.length > 0) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 0235302d7..5e92267cf 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -9,6 +9,7 @@ export default async function createDocument(request, response) { const signers = request.body.signers; const folderId = request.body.folderId; const base64File = request.body.file; + const send_email = request.body.send_email || true; const fileData = request.files?.[0] ? request.files[0].buffer : null; // console.log('fileData ', fileData); const protocol = customAPIurl(); @@ -65,6 +66,7 @@ export default async function createDocument(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); + object.set('IsSendMail', send_email); if (signers && signers.length > 0) { let parseSigners; if (base64File) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index e651a3a92..ec67b9c20 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -1,11 +1,56 @@ import axios from 'axios'; import { color, customAPIurl } from '../../../../Utils.js'; +// `sendDoctoWebhook` is used to send res data of document on webhook +async function sendDoctoWebhook(doc, WebhookUrl, userId) { + if (WebhookUrl) { + const params = { + event: 'created', + ...doc, + }; + await axios + .post(WebhookUrl, params, { + headers: { 'Content-Type': 'application/json' }, + }) + .then(res => { + try { + // console.log('res ', res); + const webhook = new Parse.Object('contracts_Webhook'); + webhook.set('Log', res?.status); + webhook.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + webhook.save(null, { useMasterKey: true }); + } catch (err) { + console.log('err save in contracts_Webhook', err); + } + }) + .catch(err => { + console.log('Err send data to webhook', err); + try { + const webhook = new Parse.Object('contracts_Webhook'); + webhook.set('Log', err?.status); + webhook.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + webhook.save(null, { useMasterKey: true }); + } catch (err) { + console.log('err save in contracts_Webhook', err); + } + }); + // console.log('res ', res.data); + } +} const randomId = () => Math.floor(1000 + Math.random() * 9000); export default async function createDocumentwithCoordinate(request, response) { const name = request.body.title; const note = request.body.note; const description = request.body.description; + const send_email = request.body.send_email || true; const signers = request.body.signers; const folderId = request.body.folderId; const base64File = request.body.file; @@ -63,6 +108,7 @@ export default async function createDocumentwithCoordinate(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); + object.set('IsSendMail', send_email); let contact = []; if (signers && signers.length > 0) { let parseSigners; @@ -168,7 +214,18 @@ export default async function createDocumentwithCoordinate(request, response) { newACL.setWriteAccess(userPtr.id, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); - + const doc = { + objectId: res.id, + file: fileUrl, + name: name, + note: note || '', + description: description || '', + signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x.phone })), + createdAt: res.createdAt, + }; + if (parseExtUser && parseExtUser.Webhook) { + sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.id); + } const newDate = new Date(); newDate.setDate(newDate.getDate() + 15); const localExpireDate = newDate.toLocaleDateString('en-US', { diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index b02ac1894..d0838e72f 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -22,6 +22,7 @@ import getapitoken from './parsefunction/getapitoken.js'; import TemplateAfterSave from './parsefunction/TemplateAfterSave.js'; import GetTemplate from './parsefunction/GetTemplate.js'; import savewebhook from './parsefunction/saveWebhook.js'; +import callWebhook from './parsefunction/callWebhook.js'; Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('UserGroups', getUserGroups); @@ -43,6 +44,7 @@ Parse.Cloud.define('generateapitoken', generateApiToken); Parse.Cloud.define('getapitoken', getapitoken); Parse.Cloud.define('getTemplate', GetTemplate); Parse.Cloud.define('savewebhook', savewebhook); +Parse.Cloud.define('callwebhook', callWebhook); Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); diff --git a/apps/OpenSignServer/cloud/parsefunction/callWebhook.js b/apps/OpenSignServer/cloud/parsefunction/callWebhook.js new file mode 100644 index 000000000..7e2fa4056 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/callWebhook.js @@ -0,0 +1,66 @@ +import axios from 'axios'; +export default async function callWebhook(request) { + const event = request.params.event; + const body = request.params.body; + const serverUrl = process.env.SERVER_URL; + const appId = process.env.APP_ID; + 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 extendcls = new Parse.Query('contracts_Users'); + extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); + const res = await extendcls.first({ useMasterKey: true }); + if (res) { + const extUser = JSON.parse(JSON.stringify(res)); + if (extUser?.Webhook) { + const params = { + event: event, + ...body, + }; + await axios + .post(extUser?.Webhook, params, { + headers: { 'Content-Type': 'application/json' }, + }) + .then(res => { + try { + // console.log('res ', res); + const webhook = new Parse.Object('contracts_Webhook'); + webhook.set('Log', res?.status); + webhook.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + webhook.save(null, { useMasterKey: true }); + } catch (err) { + console.log('err save in contracts_Webhook', err); + } + }) + .catch(err => { + console.log('Err send data to webhook', err); + try { + const webhook = new Parse.Object('contracts_Webhook'); + webhook.set('Log', err?.status); + webhook.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + webhook.save(null, { useMasterKey: true }); + } catch (err) { + console.log('err save in contracts_Webhook', err); + } + }); + } + return { message: 'webhook called!' }; + } + } else { + return { message: 'User not found!' }; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index a70ea21c0..8ff68542b 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -15,20 +15,20 @@ async function uploadFile(e, a) { console.log('Err ', e), fs.unlinkSync(a); } } -async function updateDoc(t, s, r, i, o, n) { +async function updateDoc(t, s, r, i, n, o) { try { var d = { - UserPtr: { __type: 'Pointer', className: n, objectId: r }, + UserPtr: { __type: 'Pointer', className: o, objectId: r }, SignedUrl: s, Activity: 'Signed', ipAddress: i, }; let e; - var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter( + var l = (e = n.AuditTrail && 0 < n.AuditTrail.length ? [...n.AuditTrail, d] : [d]).filter( e => 'Signed' === e.Activity ); let a = !1; - !((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0)); + !((n.Signers && 0 < n.Signers.length && l.length !== n.Signers.length) || !(a = !0)); var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a }; await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, { headers: { @@ -95,27 +95,28 @@ async function sendCompletedMail(e) { async function sendDoctoWebhook(t, e, a, s) { let r = []; (r = s - ? { Name: s?.Name, Email: s?.Email, Phone: s?.Phone } - : t?.data?.Signers?.map(e => ({ Name: e.Name, Email: e.Email, Phone: e.Phone })) || [ + ? { name: s?.Name, email: s?.Email, phone: s?.Phone } + : t?.data?.Signers?.map(e => ({ name: e.Name, email: e.Email, phone: e.Phone })) || [ { - Name: t?.data?.ExtUserPtr?.Name, - Email: t?.data?.ExtUserPtr?.Email, - Phone: t?.data?.ExtUserPtr?.Phone, + name: t?.data?.ExtUserPtr?.Name, + email: t?.data?.ExtUserPtr?.Email, + phone: t?.data?.ExtUserPtr?.Phone, }, ]), t.data.ExtUserPtr?.Webhook && ((s = - 'Signed' === a - ? { Signer: r, SignedAt: new Date() } - : { Signers: r, CompletedAt: new Date() }), + 'signed' === a + ? { signer: r, signedAt: new Date() } + : { signers: r, completedAt: new Date() }), (a = { - Event: a, - File: e || '', - Name: t?.data?.Name, - Note: t?.data?.Note || '', - Description: t?.data?.Description || '', + event: a, + objectId: t?.data?.objectId, + file: e || '', + name: t?.data?.Name, + note: t?.data?.Note || '', + description: t?.data?.Description || '', ...s, - CreatedAt: t?.data?.createdAt, + createdAt: t?.data?.createdAt, }), await axios .post(t?.data?.ExtUserPtr?.Webhook, a, { headers: { 'Content-Type': 'application/json' } }) @@ -149,12 +150,12 @@ async function sendDoctoWebhook(t, e, a, s) { } })); } -async function PDF(i, o) { +async function PDF(i, n) { try { i.params.sign; var e = i.params.docId, a = i.params.userId, - n = await axios.get( + o = await axios.get( serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers', { headers: { @@ -218,26 +219,26 @@ async function PDF(i, o) { }; let a; var y = (a = - n.data.AuditTrail && 0 < n.data.AuditTrail.length - ? [...n.data.AuditTrail, f] + o.data.AuditTrail && 0 < o.data.AuditTrail.length + ? [...o.data.AuditTrail, f] : [f]).filter(e => 'Signed' === e.Activity); let t = !1; !( - (n.data.Signers && 0 < n.data.Signers.length && y.length !== n.data.Signers.length) || + (o.data.Signers && 0 < o.data.Signers.length && y.length !== o.data.Signers.length) || !(t = !0) ); - var P, - v, + var v, + P, b = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`, x = './exports/' + b, U = (t - ? ((P = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), + ? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), (e = - P && 0 < P.length + v && 0 < v.length ? plainAddPlaceholder({ pdfBuffer: e, - reason: 'Digitally signed by Open sign for ' + P?.join(', '), + reason: 'Digitally signed by Open sign for ' + v?.join(', '), location: 'location', signatureLength: 1e4, }) @@ -247,39 +248,42 @@ async function PDF(i, o) { location: 'location', signatureLength: 1e4, })), - (v = await new SignPDF(e, u).signPDF()), - fs.writeFileSync(x, v)) + (P = await new SignPDF(e, u).signPDF()), + fs.writeFileSync(x, P)) : fs.writeFileSync(x, e), await uploadFile(b, x)); if (U && U.imageUrl) { - const o = await updateDoc( + const n = await updateDoc( i.params.docId, U.imageUrl, s.data.results[0].objectId, i.headers['x-real-ip'], - n.data, + o.data, r ); - return ( - sendMail({ + var I, + w = { url: U.imageUrl, - sender: { Mail: n.data.ExtUserPtr.Email, Name: n.data.ExtUserPtr.Name }, - pdfName: n.data.Name, + sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name }, + pdfName: o.data.Name, receiver: g, - }), - sendDoctoWebhook(n, U.imageUrl, 'Signed', s?.data.results?.[0]), - o && - o.isCompleted && - (sendCompletedMail({ + }; + return ( + o.data.IsSendMail && sendMail(w), + sendDoctoWebhook(o, U.imageUrl, 'signed', s?.data.results?.[0]), + n && + n.isCompleted && + ((I = { url: U.imageUrl, - sender: { Mail: n.data.ExtUserPtr.Email, Name: 'OpenSign™' }, - pdfName: n.data.Name, - receiver: n.data.ExtUserPtr.Email, + sender: { Mail: o.data.ExtUserPtr.Email, Name: 'OpenSign™' }, + pdfName: o.data.Name, + receiver: o.data.ExtUserPtr.Email, }), - sendDoctoWebhook(n, U.imageUrl, 'Completed')), + o.data.IsSendMail && sendCompletedMail(I), + sendDoctoWebhook(o, U.imageUrl, 'completed')), fs.unlinkSync(x), console.log('New Signed PDF created called: ' + x), - 'success' === o.message + 'success' === n.message ? { status: 'success', data: U.imageUrl } : { status: 'error', message: 'please provide required parameters!' } ); diff --git a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js index 901c37a3f..924c7c5c1 100644 --- a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js +++ b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js @@ -609,9 +609,37 @@ function PdfRequestFiles() { } } ) - .then((result) => { + .then(async (result) => { const res = result.data; if (res) { + const params = { + event: "declined", + body: { + objectId: pdfDetails?.[0].objectId, + name: pdfDetails?.[0].Name, + note: pdfDetails?.[0].Note || "", + description: pdfDetails?.[0].Description || "", + signers: pdfDetails?.[0].Signers?.map((x) => ({ + name: x?.Name, + email: x?.Email, + phone: x?.Phone + })), + createdAt: pdfDetails?.[0].createdAt, + declinedAt: new Date() + } + }; + const res = await axios.post( + `${localStorage.getItem("baseUrl")}functions/callwebhook`, + params, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + sessiontoken: localStorage.getItem("accesstoken") + } + } + ); + console.log("res ", res.data); const currentDecline = { currnt: "YouDeclined", isDeclined: true From caa1dfaf34541325236d234f26d1f78bab91550e Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 7 Feb 2024 22:04:40 +0530 Subject: [PATCH 56/73] changed callwwebhook --- .../src/Component/PdfRequestFiles.js | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js index 924c7c5c1..53c45f0df 100644 --- a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js +++ b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js @@ -612,6 +612,10 @@ function PdfRequestFiles() { .then(async (result) => { const res = result.data; if (res) { + const currentDecline = { + currnt: "YouDeclined", + isDeclined: true + }; const params = { event: "declined", body: { @@ -628,24 +632,23 @@ function PdfRequestFiles() { declinedAt: new Date() } }; - const res = await axios.post( - `${localStorage.getItem("baseUrl")}functions/callwebhook`, - params, - { - headers: { - "Content-Type": "application/json", - "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - sessiontoken: localStorage.getItem("accesstoken") - } - } - ); - console.log("res ", res.data); - const currentDecline = { - currnt: "YouDeclined", - isDeclined: true - }; setIsDecline(currentDecline); setIsUiLoading(false); + try { + await axios.post( + `${localStorage.getItem("baseUrl")}functions/callwebhook`, + params, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + sessiontoken: localStorage.getItem("accesstoken") + } + } + ); + } catch (err) { + console.log("Err ", err); + } } }) .catch((err) => { From a198bce3e279f8ef4399b494dec79e3180b51e02 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 8 Feb 2024 15:24:34 +0530 Subject: [PATCH 57/73] feat: add viewed document event for webhook --- .../src/Component/PdfRequestFiles.js | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js index 53c45f0df..b935f9bea 100644 --- a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js +++ b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js @@ -182,6 +182,51 @@ function PdfRequestFiles() { checkAlreadySign.length > 0 ) { setAlreadySign(true); + } else { + const obj = documentData?.[0]; + if ( + obj && + obj.Signers && + obj.Signers.length > 0 && + obj.Placeholders && + obj.Placeholders.length > 0 + ) { + const params = { + event: "viewed", + body: { + objectId: documentData?.[0].objectId, + file: documentData?.[0]?.SignedUrl || documentData?.[0]?.URL, + name: documentData?.[0].Name, + note: documentData?.[0].Note || "", + description: documentData?.[0].Description || "", + signers: documentData?.[0].Signers?.map((x) => ({ + name: x?.Name, + email: x?.Email, + phone: x?.Phone + })), + viewedBy: jsonSender.email, + viewedAt: new Date(), + createdAt: documentData?.[0].createdAt + } + }; + + try { + await axios.post( + `${localStorage.getItem("baseUrl")}functions/callwebhook`, + params, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": + localStorage.getItem("parseAppId"), + sessiontoken: localStorage.getItem("accesstoken") + } + } + ); + } catch (err) { + console.log("Err ", err); + } + } } let signers = []; @@ -616,10 +661,13 @@ function PdfRequestFiles() { currnt: "YouDeclined", isDeclined: true }; + setIsDecline(currentDecline); + setIsUiLoading(false); const params = { event: "declined", body: { objectId: pdfDetails?.[0].objectId, + file: pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL, name: pdfDetails?.[0].Name, note: pdfDetails?.[0].Note || "", description: pdfDetails?.[0].Description || "", @@ -628,12 +676,12 @@ function PdfRequestFiles() { email: x?.Email, phone: x?.Phone })), - createdAt: pdfDetails?.[0].createdAt, - declinedAt: new Date() + declinedBy: jsonSender.email, + declinedAt: new Date(), + createdAt: pdfDetails?.[0].createdAt } }; - setIsDecline(currentDecline); - setIsUiLoading(false); + try { await axios.post( `${localStorage.getItem("baseUrl")}functions/callwebhook`, From 9d431af0b9c18bcebdaad9976cb7295981ecc650 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 8 Feb 2024 20:02:19 +0530 Subject: [PATCH 58/73] feat: add send_email, email_subject, email_body for custom mail signing request in createdocument --- .../v1/routes/CreateDocumentWithTemplate.js | 189 +++++++++++++----- .../v1/routes/createDocumentwithCoordinate.js | 127 ++++++++---- 2 files changed, 224 insertions(+), 92 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 8d61d3327..3764bb74b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -1,14 +1,59 @@ import axios from 'axios'; -import { customAPIurl } from '../../../../Utils.js'; +import { customAPIurl, replaceMailVaribles } from '../../../../Utils.js'; +// `sendDoctoWebhook` is used to send res data of document on webhook +async function sendDoctoWebhook(doc, WebhookUrl, userId) { + if (WebhookUrl) { + const params = { + event: 'created', + ...doc, + }; + await axios + .post(WebhookUrl, params, { + headers: { 'Content-Type': 'application/json' }, + }) + .then(res => { + try { + // console.log('res ', res); + const webhook = new Parse.Object('contracts_Webhook'); + webhook.set('Log', res?.status); + webhook.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + webhook.save(null, { useMasterKey: true }); + } catch (err) { + console.log('err save in contracts_Webhook', err); + } + }) + .catch(err => { + console.log('Err send data to webhook', err); + try { + const webhook = new Parse.Object('contracts_Webhook'); + webhook.set('Log', err?.status); + webhook.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userId, + }); + webhook.save(null, { useMasterKey: true }); + } catch (err) { + console.log('err save in contracts_Webhook', err); + } + }); + // console.log('res ', res.data); + } +} export default async function createDocumentWithTemplate(request, response) { const signers = request.body.signers; const folderId = request.body.folderId; const templateId = request.params.template_id; const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); - const send_email = request.body.send_email || true; - + const send_email = request.body.send_email; + const email_subject = request.body.email_subject; + const email_body = request.body.email_body; try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -142,34 +187,32 @@ export default async function createDocumentWithTemplate(request, response) { const serverUrl = process.env.SERVER_URL; const newServer = serverUrl.replaceAll('/', '%2F'); const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`; + if (send_email === false) { + console.log("don't send mail"); + } else { + for (let i = 0; i < contact.length; i++) { + try { + const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; + let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; - for (let i = 0; i < contact.length; i++) { - try { - const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; - let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - - const objectId = contact[i].contactPtr.objectId; + const objectId = contact[i].contactPtr.objectId; - const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; - let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; - const openSignUrl = 'https://www.opensignlabs.com/contact-us'; - const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : ''; - const themeBGcolor = '#47a3ad'; - let params = { - recipient: contact[i].email, - subject: `${template.ExtUserPtr.Name} has requested you to sign ${template.ExtUserPtr.Name}`, - 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=" + + const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; + let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; + const openSignUrl = 'https://www.opensignlabs.com/contact-us'; + const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : ''; + const themeBGcolor = '#47a3ad'; + const email_html = + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" + imgPng + - " height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" + + "' 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;'> " + + ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + template.ExtUserPtr.Name + ' has requested you to review and sign <strong> ' + template.Name + @@ -181,33 +224,83 @@ export default async function createDocumentWithTemplate(request, response) { 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 " + + "> <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= ' + + ' 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>', - }; - sendMail = await axios.post(url, params, { headers: headers }); - } catch (error) { - console.log('error', error); + ' target=_blank>here</a>.</p> </div></div></body> </html>'; + + let replaceVar; + const variables = { + document_title: template.Name, + sender_name: template.ExtUserPtr.Name, + sender_mail: template.ExtUserPtr.Email, + sender_phone: template.ExtUserPtr.Phone, + receiver_name: contact[i].name, + receiver_email: contact[i].email, + receiver_phone: contact[i].phone, + expiry_date: localExpireDate, + company_name: orgName, + signing_url: signPdf, + }; + if (email_subject && email_body) { + replaceVar = replaceMailVaribles(email_subject, email_body, variables); + } else if (email_subject) { + replaceVar = replaceMailVaribles(email_subject, '', variables); + replaceVar = { subject: replaceVar.subject, body: email_html }; + } else if (email_body) { + replaceVar = replaceMailVaribles( + `${template.ExtUserPtr.Name} has requested you to sign ${template.Name}`, + email_body, + variables + ); + } else { + replaceVar = { + subject: `${template.ExtUserPtr.Name} has requested you to sign ${template.Name}`, + body: email_html, + }; + } + + const subject = replaceVar.subject; + const html = replaceVar.body; + let params = { + recipient: contact[i].email, + subject: subject, + from: sender, + html: html, + }; + sendMail = await axios.post(url, params, { headers: headers }); + } catch (error) { + console.log('error', error); + } } } - - if (sendMail.data.result.status === 'success') { - const user = contact.find(x => x.email === template.ExtUserPtr.Email); - if (user && user.email) { - return response.json({ - objectId: res.id, - url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${user.email}/${user.contactPtr.objectId}/${serverParams}`, - message: 'Document sent successfully!', - }); - } else { - return response.json({ - objectId: res.id, - message: 'Document sent successfully!', - }); + // if (sendMail.data.result.status === 'success') { + try { + const doc = { + objectId: res.id, + file: template?.URL, + name: template?.Name, + note: template?.Note || '', + description: template?.Description || '', + signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x.phone })), + createdAt: res.createdAt, + }; + if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) { + sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.id); } + } catch (err) { + console.log('Err', err); } + return response.json({ + objectId: res.id, + signurl: contact.map(x => ({ + email: x.email, + url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`, + })), + message: 'Document sent successfully!', + }); + // } } else { return response.status(400).json({ error: 'Please provide signers properly!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index ec67b9c20..a96983619 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -1,5 +1,5 @@ import axios from 'axios'; -import { color, customAPIurl } from '../../../../Utils.js'; +import { color, customAPIurl, replaceMailVaribles } from '../../../../Utils.js'; // `sendDoctoWebhook` is used to send res data of document on webhook async function sendDoctoWebhook(doc, WebhookUrl, userId) { @@ -50,15 +50,17 @@ export default async function createDocumentwithCoordinate(request, response) { const name = request.body.title; const note = request.body.note; const description = request.body.description; - const send_email = request.body.send_email || true; + const send_email = request.body.send_email; const signers = request.body.signers; const folderId = request.body.folderId; const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; + const email_subject = request.body.email_subject; + const email_body = request.body.email_body; // console.log('fileData ', fileData); const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); - + console.log('send_email ', send_email); try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -238,34 +240,32 @@ export default async function createDocumentwithCoordinate(request, response) { const serverUrl = process.env.SERVER_URL; const newServer = serverUrl.replaceAll('/', '%2F'); const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`; + if (send_email === false) { + console.log("don't send mail"); + } else { + for (let i = 0; i < contact.length; i++) { + try { + const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; + let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; - for (let i = 0; i < contact.length; i++) { - try { - const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; - let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': process.env.APP_ID, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - - const objectId = contact[i].contactPtr.objectId; + const objectId = contact[i].contactPtr.objectId; - const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; - let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; - const openSignUrl = 'https://www.opensignlabs.com/contact-us'; - const orgName = parseExtUser.Company ? parseExtUser.Company : ''; - const themeBGcolor = '#47a3ad'; - let params = { - recipient: contact[i].email, - subject: `${parseExtUser.Name} has requested you to sign ${parseExtUser.Name}`, - 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=" + + const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; + let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; + const openSignUrl = 'https://www.opensignlabs.com/contact-us'; + const orgName = parseExtUser.Company ? parseExtUser.Company : ''; + const themeBGcolor = '#47a3ad'; + const email_html = + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + imgPng + - " height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" + + " 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;'> " + + ";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + parseExtUser.Name + ' has requested you to review and sign <strong> ' + name + @@ -279,26 +279,65 @@ export default async function createDocumentwithCoordinate(request, response) { 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= ' + + ' 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>', - }; - sendMail = await axios.post(url, params, { headers: headers }); - } catch (error) { - console.log('error', error); - } - } + ' target=_blank>here</a>.</p> </div></div></body> </html>'; + let replaceVar; + const variables = { + document_title: name, + sender_name: parseExtUser.Name, + sender_mail: parseExtUser.Email, + sender_phone: parseExtUser.Phone, + receiver_name: contact[i].name, + receiver_email: contact[i].email, + receiver_phone: contact[i].phone, + expiry_date: localExpireDate, + company_name: orgName, + signing_url: signPdf, + }; + if (email_subject && email_body) { + replaceVar = replaceMailVaribles(email_subject, email_body, variables); + } else if (email_subject) { + replaceVar = replaceMailVaribles(email_subject, '', variables); + replaceVar = { subject: replaceVar.subject, body: email_html }; + } else if (email_body) { + replaceVar = replaceMailVaribles( + `${parseExtUser.Name} has requested you to sign ${name}`, + email_body, + variables + ); + } else { + replaceVar = { + subject: `${parseExtUser.Name} has requested you to sign ${parseExtUser.Name}`, + body: email_html, + }; + } + const subject = replaceVar.subject; + const html = replaceVar.body; - if (sendMail.data.result.status === 'success') { - return response.json({ - objectId: res.id, - signurl: contact.map(x => ({ - email: x.email, - url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`, - })), - message: 'Document sent successfully!', - }); + let params = { + recipient: contact[i].email, + subject: subject, + from: sender, + html: html, + }; + + sendMail = await axios.post(url, params, { headers: headers }); + } catch (error) { + console.log('error', error); + } + } } + // if (sendMail.data.result.status === 'success') { + return response.json({ + objectId: res.id, + signurl: contact.map(x => ({ + email: x.email, + url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`, + })), + message: 'Document sent successfully!', + }); + // } } else { return response.status(400).json({ error: 'Please provide signers!' }); } From b58c3fd4677d7a3d1ed78868ee9e103fece57fc1 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 8 Feb 2024 20:03:15 +0530 Subject: [PATCH 59/73] add replacemailvaribles function to change varibale from custom mail --- apps/OpenSignServer/Utils.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apps/OpenSignServer/Utils.js b/apps/OpenSignServer/Utils.js index 98c1a4366..8fc705ceb 100644 --- a/apps/OpenSignServer/Utils.js +++ b/apps/OpenSignServer/Utils.js @@ -17,3 +17,24 @@ export const color = [ '#66ccff', '#ffffcc', ]; + +export function replaceMailVaribles(subject, body, variables) { + let replacedSubject = subject; + let replacedBody = body; + + for (const variable in variables) { + const regex = new RegExp(`{{${variable}}}`, 'g'); + if (subject) { + replacedSubject = replacedSubject.replace(regex, variables[variable]); + } + if (body) { + replacedBody = replacedBody.replace(regex, variables[variable]); + } + } + + const result = { + subject: replacedSubject, + body: replacedBody, + }; + return result; +} From 388490996564b7ecc016e61d6e2cf1516e5d397b Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 9 Feb 2024 15:10:21 +0530 Subject: [PATCH 60/73] fix: get templatelist api is not working --- .../customRoute/v1/routes/createDocumentwithCoordinate.js | 1 - .../cloud/customRoute/v1/routes/getTemplateList.js | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index a96983619..cd285a905 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -60,7 +60,6 @@ export default async function createDocumentwithCoordinate(request, response) { // console.log('fileData ', fileData); const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); - console.log('send_email ', send_email); try { const reqToken = request.headers['x-api-token']; if (!reqToken) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 0e641e20a..71c19df1d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -21,7 +21,11 @@ export default async function getTemplatetList(request, response) { const clsName = 'contracts_Template'; const params = { Type: { $ne: 'Folder' }, - CreatedBy: userPtr, + CreatedBy: { + __type: 'Pointer', + className: '_User', + objectId: userPtr.id, + }, IsArchive: { $ne: true }, }; const keys = [ From ebfd9d3af707235209a963a0426707c075b0585f Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 9 Feb 2024 17:13:39 +0530 Subject: [PATCH 61/73] fix: get contactlist API not working & response fo APIs to lowercase --- .../cloud/customRoute/v1/routes/createContact.js | 12 ++++++------ .../cloud/customRoute/v1/routes/getContact.js | 6 +++--- .../cloud/customRoute/v1/routes/getContactList.js | 11 +++++------ .../cloud/customRoute/v1/routes/getDocument.js | 14 ++++++++------ .../cloud/customRoute/v1/routes/getDocumentList.js | 13 +++++++------ .../cloud/customRoute/v1/routes/getTemplate.js | 14 ++++++++------ .../cloud/customRoute/v1/routes/getTemplateList.js | 14 ++++++++------ .../cloud/customRoute/v1/routes/getUser.js | 10 +++++----- .../cloud/customRoute/v1/routes/getWebhook.js | 2 +- 9 files changed, 51 insertions(+), 45 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index ba6ffa503..29fc57bbd 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -82,9 +82,9 @@ export default async function createContact(request, response) { const parseRes = JSON.parse(JSON.stringify(contactRes)); return response.json({ objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, + name: parseRes.Name, + email: parseRes.Email, + phone: parseRes.Phone, createdAt: parseRes.createdAt, updatedAt: parseRes.updatedAt, }); @@ -124,9 +124,9 @@ export default async function createContact(request, response) { const parseRes = JSON.parse(JSON.stringify(contactRes)); return response.json({ objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, + name: parseRes.Name, + email: parseRes.Email, + phone: parseRes.Phone, createdAt: parseRes.createdAt, updatedAt: parseRes.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index 0a68b31bc..e400cd372 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -21,9 +21,9 @@ export default async function getContact(request, response) { const parseRes = JSON.parse(JSON.stringify(res)); return response.json({ objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, + name: parseRes.Name, + email: parseRes.Email, + phone: parseRes.Phone, createdAt: parseRes.createdAt, updatedAt: parseRes.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index a6b74a819..68e0505d7 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -10,9 +10,8 @@ export default async function getContactList(request, response) { if (token !== undefined) { // Valid Token then proceed request const userPtr = token.get('userId'); - - const limit = request?.query?.limit ? request.query.limit : 100; - const skip = request?.query?.skip ? request.query.skip : 0; + const limit = request?.query?.limit ? parseInt(request.query.limit) : 100; + const skip = request?.query?.skip ? parseInt(request.query.skip) : 0; const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('CreatedBy', userPtr); Contactbook.notEqualTo('IsDeleted', true); @@ -23,9 +22,9 @@ export default async function getContactList(request, response) { const parseRes = JSON.parse(JSON.stringify(res)); const contactlist = parseRes.map(x => ({ objectId: x.objectId, - Name: x.Name, - Email: x.Email, - Phone: x.Phone, + name: x.Name, + email: x.Email, + phone: x.Phone, createdAt: x.createdAt, updatedAt: x.updatedAt, })); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index 76046aa5e..4643460ae 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -22,12 +22,14 @@ export default async function getDocument(request, response) { const document = JSON.parse(JSON.stringify(res)); return response.json({ objectId: document.objectId, - Title: document.Name, - Note: document.Note || '', - Folder: document?.Folder?.Name || 'OpenSign™ Drive', - File: document?.SignedUrl || document.URL, - Owner: document?.ExtUserPtr?.Name, - Signers: document?.Signers?.map(y => y?.Name) || '', + title: document.Name, + note: document.Note || '', + folder: { objectId: document?.Folder?.objectId, name: document?.Folder?.Name } || '', + file: document?.SignedUrl || document.URL, + owner: document?.ExtUserPtr?.Name, + signers: + document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || + [], createdAt: document.createdAt, updatedAt: document.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index f586cc2c6..a4cf04d12 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -59,12 +59,13 @@ export default async function getDocumentList(request, response) { if (res.data && res.data.results.length > 0) { const updateRes = res.data.results.map(x => ({ objectId: x.objectId, - Title: x.Name, - Note: x.Note || '', - Folder: x?.Folder?.Name || 'OpenSign™ Drive', - File: x?.SignedUrl || x.URL, - Owner: x?.ExtUserPtr?.Name, - Signers: x?.Signers?.map(y => y?.Name) || '', + title: x.Name, + note: x.Note || '', + folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: + x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], createdAt: x.createdAt, updatedAt: x.updatedAt, })); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index f69bd896a..ab56f2b36 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -22,12 +22,14 @@ export default async function getTemplate(request, response) { const template = JSON.parse(JSON.stringify(res)); return response.json({ objectId: template.objectId, - Title: template.Name, - Note: template.Note || '', - Folder: template?.Folder?.Name || 'OpenSign™ Drive', - File: template?.SignedUrl || x.URL, - Owner: template?.ExtUserPtr?.Name, - Signers: template?.Signers?.map(y => y?.Name) || '', + title: template.Name, + note: template.Note || '', + folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '', + file: template?.SignedUrl || x.URL, + owner: template?.ExtUserPtr?.Name, + signers: + template?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || + [], createdAt: template.createdAt, updatedAt: template.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 71c19df1d..435e99f73 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -37,6 +37,8 @@ export default async function getTemplatetList(request, response) { 'SignedUrl', 'ExtUserPtr.Name', 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', ]; const orderBy = '-updatedAt'; const strParams = JSON.stringify(params); @@ -51,12 +53,12 @@ export default async function getTemplatetList(request, response) { if (res.data && res.data.results.length > 0) { const updateRes = res.data.results.map(x => ({ objectId: x.objectId, - Title: x.Name, - Note: x.Note || '', - Folder: x?.Folder?.Name || 'OpenSign™ Drive', - File: x?.SignedUrl || x.URL, - Owner: x?.ExtUserPtr?.Name, - Signers: x?.Signers?.map(y => y?.Name) || '', + title: x.Name, + note: x.Note || '', + folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], createdAt: x.createdAt, updatedAt: x.updatedAt, })); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index 54f92ef52..81da0d479 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -20,11 +20,11 @@ export default async function getUser(request, response) { const parseRes = JSON.parse(JSON.stringify(user)); return response.json({ objectId: parseRes.objectId, - Name: parseRes.Name, - Email: parseRes.Email, - Phone: parseRes.Phone, - JobTitle: parseRes.JobTitle, - Company: parseRes.Company, + name: parseRes.Name, + email: parseRes.Email, + phone: parseRes.Phone, + jobTitle: parseRes.JobTitle, + company: parseRes.Company, createdAt: parseRes.createdAt, updatedAt: parseRes.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js index c022d0d38..244965e2b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -17,7 +17,7 @@ export default async function getWebhook(request, response) { if (parseUser && parseUser.Webhook) { return response.json({ - Webhook: parseUser.Webhook, + webhook: parseUser.Webhook, }); } else { return response.json({}); From 5142a8c62dabe4cde685b2ad258844eb1e19a14d Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 12 Feb 2024 17:17:48 +0530 Subject: [PATCH 62/73] fix: create contact not working properly & update 400 error --- .../v1/routes/CreateDocumentWithTemplate.js | 2 +- .../customRoute/v1/routes/createContact.js | 2 +- .../customRoute/v1/routes/createDocument.js | 2 +- .../v1/routes/createTemplatewithCoordinate.js | 2 +- .../customRoute/v1/routes/getContactList.js | 1 + .../customRoute/v1/routes/saveWebhook.js | 23 ++++++++++++------- .../customRoute/v1/routes/updateDocument.js | 2 +- .../customRoute/v1/routes/updateTemplate.js | 2 +- 8 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 3764bb74b..08a066e86 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -318,6 +318,6 @@ export default async function createDocumentWithTemplate(request, response) { if (err.code === 101) { return response.status(404).json({ error: 'Invalid template id!' }); } - return response.status(400).json({ error: 'Something went wrong!' }); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index 29fc57bbd..879217e92 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -19,7 +19,7 @@ export default async function createContact(request, response) { const contactbook = new Parse.Query('contracts_Contactbook'); contactbook.equalTo('Email', email); contactbook.equalTo('CreatedBy', userPtr); - + contactbook.notEqualTo('IsDeleted', true); const userExists = await contactbook.first({ useMasterKey: true }); if (userExists) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 5e92267cf..1b88369a2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -128,6 +128,6 @@ export default async function createDocument(request, response) { } } catch (err) { console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong!' }); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index 4624e2ba3..528827561 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -186,6 +186,6 @@ export default async function createTemplatewithCoordinate(request, response) { } } catch (err) { console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong!' }); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 68e0505d7..3ecfc7885 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -17,6 +17,7 @@ export default async function getContactList(request, response) { Contactbook.notEqualTo('IsDeleted', true); Contactbook.limit(limit); Contactbook.skip(skip); + Contactbook.descending('createdAt'); const res = await Contactbook.find({ useMasterKey: true }); if (res && res.length > 0) { const parseRes = JSON.parse(JSON.stringify(res)); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js index 675fe6e90..bbb2be945 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -18,14 +18,21 @@ export default async function saveWebhook(request, response) { const isUrlExist = parseUser?.Webhook && parseUser?.Webhook === Url; if (!isUrlExist) { - const updateQuery = new Parse.Object('contracts_Users'); - updateQuery.id = user.id; - updateQuery.set('Webhook', Url); - const res = await updateQuery.save(null, { useMasterKey: true }); - if (res) { - return response.json({ - result: 'Webhook updated successfully!', - }); + try { + const updateQuery = new Parse.Object('contracts_Users'); + updateQuery.id = user.id; + updateQuery.set('Webhook', Url); + const res = await updateQuery.save(null, { useMasterKey: true }); + if (res) { + return response.json({ + result: 'Webhook updated successfully!', + }); + } + } catch (err) { + console.log('Err ', err); + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } } else { return response.status(401).json({ error: 'Webhook url already exists!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index 30c9b9d41..51fda1139 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -33,7 +33,7 @@ export default async function updateDocument(request, response) { updateQuery.set('Note', request?.body?.note); } if (request?.body?.description) { - updateQuery.set('Name', request?.body?.description); + updateQuery.set('Description', request?.body?.description); } if (request?.body?.folderId) { updateQuery.set('Folder', { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 38dac8e6d..7bbe031b2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -33,7 +33,7 @@ export default async function updateTemplate(request, response) { updateQuery.set('Note', request?.body?.note); } if (request?.body?.description) { - updateQuery.set('Name', request?.body?.description); + updateQuery.set('Description', request?.body?.description); } if (request?.body?.folderId) { updateQuery.set('Folder', { From b0e26b8ae2ac5faf52c6ec043da77b1fcef18412 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Tue, 13 Feb 2024 20:39:53 +0530 Subject: [PATCH 63/73] refactor: add analytics code for internal tracking --- .../v1/routes/CreateDocumentWithTemplate.js | 43 ++++++++++++++-- .../customRoute/v1/routes/createContact.js | 49 ++++++++++++++++--- .../customRoute/v1/routes/createDocument.js | 26 ++++++++-- .../v1/routes/createDocumentwithCoordinate.js | 30 ++++++++++-- .../customRoute/v1/routes/createTemplate.js | 19 +++++-- .../v1/routes/createTemplatewithCoordinate.js | 27 ++++++++-- .../customRoute/v1/routes/deleteContact.js | 23 ++++++++- .../customRoute/v1/routes/deleteDocument.js | 23 ++++++++- .../customRoute/v1/routes/deleteTemplate.js | 22 ++++++++- .../customRoute/v1/routes/deleteWebhook.js | 23 ++++++++- .../cloud/customRoute/v1/routes/getContact.js | 23 ++++++++- .../customRoute/v1/routes/getContactList.js | 22 ++++++++- .../customRoute/v1/routes/getDocument.js | 22 ++++++++- .../customRoute/v1/routes/getDocumentList.js | 24 ++++++++- .../customRoute/v1/routes/getTemplate.js | 24 ++++++++- .../customRoute/v1/routes/getTemplateList.js | 30 +++++++++--- .../cloud/customRoute/v1/routes/getUser.js | 23 ++++++++- .../cloud/customRoute/v1/routes/getWebhook.js | 23 ++++++++- .../customRoute/v1/routes/saveWebhook.js | 37 +++++++++++++- .../customRoute/v1/routes/updateDocument.js | 29 ++++++++++- .../customRoute/v1/routes/updateTemplate.js | 29 ++++++++++- apps/OpenSignServer/index.js | 12 ++++- apps/OpenSignServer/package-lock.json | 47 ++++++++++++++++++ apps/OpenSignServer/package.json | 1 + 24 files changed, 580 insertions(+), 51 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 08a066e86..4b108ac87 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -61,11 +61,16 @@ export default async function createDocumentWithTemplate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); - + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const templateQuery = new Parse.Query('contracts_Template'); templateQuery.include('ExtUserPtr'); const templateRes = await templateQuery.get(templateId, { useMasterKey: true }); @@ -170,8 +175,8 @@ export default async function createDocumentWithTemplate(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.id, true); - newACL.setWriteAccess(userPtr.id, true); + newACL.setReadAccess(userPtr.objectId, true); + newACL.setWriteAccess(userPtr.objectId, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); @@ -287,11 +292,18 @@ export default async function createDocumentWithTemplate(request, response) { createdAt: res.createdAt, }; if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) { - sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.id); + sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId); } } catch (err) { console.log('Err', err); } + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_document_with_templateid', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: res.id, signurl: contact.map(x => ({ @@ -302,12 +314,33 @@ export default async function createDocumentWithTemplate(request, response) { }); // } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_document_with_templateid', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please provide signers properly!' }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_document_with_templateid', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please setup template properly!' }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_document_with_templateid', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Invalid template id!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index 879217e92..b0160a4aa 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -11,10 +11,17 @@ export default async function createContact(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + try { const contactbook = new Parse.Query('contracts_Contactbook'); contactbook.equalTo('Email', email); @@ -23,6 +30,13 @@ export default async function createContact(request, response) { const userExists = await contactbook.first({ useMasterKey: true }); if (userExists) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_contact', + properties: { response_code: 401 }, + }); + } return response .status(401) .json({ error: 'Contact already exists!', objectId: userExists.id }); @@ -72,8 +86,8 @@ export default async function createContact(request, response) { contactQuery.set('UserId', user); const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(userPtr.objectId, true); + acl.setWriteAccess(userPtr.objectId, true); acl.setReadAccess(user.id, true); acl.setWriteAccess(user.id, true); contactQuery.setACL(acl); @@ -103,18 +117,18 @@ export default async function createContact(request, response) { const body = { appName: 'contracts', roleName: 'contracts_Guest', - userId: userRes.id, + userId: userRes.objectId, }; await axios.post(roleurl, body, { headers: headers }); - contactQuery.set('CreatedBy', userPtr); + contactQuery.set('CreatedBy', userPtr.objectId); contactQuery.set('UserId', { __type: 'Pointer', className: '_User', objectId: userRes.id, }); const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.id, true); - acl.setWriteAccess(userPtr.id, true); + acl.setReadAccess(userPtr.objectId, true); + acl.setWriteAccess(userPtr.objectId, true); acl.setReadAccess(userRes.id, true); acl.setWriteAccess(userRes.id, true); @@ -143,8 +157,22 @@ export default async function createContact(request, response) { } catch (err) { console.log('err ', err); if (err.code === 137) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_contact', + properties: { response_code: 401 }, + }); + } return response.status(401).json({ error: 'Contact already exists!' }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_contact', + properties: { response_code: 400 }, + }); + } return response .status(400) .json({ error: 'Something went wrong, please try again later!' }); @@ -152,6 +180,13 @@ export default async function createContact(request, response) { } } } catch (err) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_contact', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 1b88369a2..33f89b21a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -21,11 +21,17 @@ export default async function createDocument(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; // Valid Token then proceed request if (signers && signers.length > 0) { - const userPtr = token.get('userId'); let fileUrl; if (request.files?.[0]) { const file = new Parse.File(request.files?.[0]?.originalname, { @@ -112,15 +118,29 @@ export default async function createDocument(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.id, true); - newACL.setWriteAccess(userPtr.id, true); + newACL.setReadAccess(userPtr.objectId, true); + newACL.setWriteAccess(userPtr.objectId, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'draft_document', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: res.id, url: protocol + '/load/signmicroapp/placeholdersign/' + res.id, }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'draft_document', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please provide signers!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index cd285a905..3f5b30171 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -67,11 +67,17 @@ export default async function createDocumentwithCoordinate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; if (signers && signers.length > 0) { - const userPtr = token.get('userId'); let fileUrl; if (request.files?.[0]) { const file = new Parse.File(request.files?.[0]?.originalname, { @@ -211,8 +217,8 @@ export default async function createDocumentwithCoordinate(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.id, true); - newACL.setWriteAccess(userPtr.id, true); + newACL.setReadAccess(userPtr.objectId, true); + newACL.setWriteAccess(userPtr.objectId, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); const doc = { @@ -225,7 +231,7 @@ export default async function createDocumentwithCoordinate(request, response) { createdAt: res.createdAt, }; if (parseExtUser && parseExtUser.Webhook) { - sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.id); + sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId); } const newDate = new Date(); newDate.setDate(newDate.getDate() + 15); @@ -328,6 +334,13 @@ export default async function createDocumentwithCoordinate(request, response) { } } // if (sendMail.data.result.status === 'success') { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_document', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: res.id, signurl: contact.map(x => ({ @@ -338,6 +351,13 @@ export default async function createDocumentwithCoordinate(request, response) { }); // } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_document', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please provide signers!' }); } } else { @@ -345,6 +365,6 @@ export default async function createDocumentwithCoordinate(request, response) { } } catch (err) { console.log('err ', err); - return response.status(400).json({ error: 'Something went wrong!' }); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 5d8e4fb14..742f487ba 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -18,10 +18,16 @@ export default async function createTemplate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; let fileUrl; if (base64File) { const file = new Parse.File(`${name}.pdf`, { @@ -100,10 +106,17 @@ export default async function createTemplate(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.id, true); - newACL.setWriteAccess(userPtr.id, true); + newACL.setReadAccess(userPtr.objectId, true); + newACL.setWriteAccess(userPtr.objectId, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'draft_template', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: res.id, url: protocol + '/load/signmicroapp/template/' + res.id, diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index 528827561..fd0a045db 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -20,11 +20,17 @@ export default async function createTemplatewithCoordinate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; if (signers && signers.length > 0) { - const userPtr = token.get('userId'); let fileUrl; if (request.files?.[0]) { const file = new Parse.File(request.files?.[0]?.originalname, { @@ -169,16 +175,29 @@ export default async function createTemplatewithCoordinate(request, response) { const newACL = new Parse.ACL(); newACL.setPublicReadAccess(false); newACL.setPublicWriteAccess(false); - newACL.setReadAccess(userPtr.id, true); - newACL.setWriteAccess(userPtr.id, true); + newACL.setReadAccess(userPtr.objectId, true); + newACL.setWriteAccess(userPtr.objectId, true); object.setACL(newACL); const res = await object.save(null, { useMasterKey: true }); - + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_template', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: res.id, message: 'Template created successfully!', }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'create_template', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please provide signers!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index b9e57012a..ade460c9c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -6,10 +6,17 @@ export default async function deleteContact(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('objectId', request.params.contact_id); Contactbook.equalTo('CreatedBy', userPtr); @@ -25,6 +32,13 @@ export default async function deleteContact(request, response) { deleteQuery.set('IsDeleted', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_contact', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: request.params.contact_id, deletedAt: deleteRes.get('updatedAt'), @@ -32,6 +46,13 @@ export default async function deleteContact(request, response) { } } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_contact', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Contact not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js index 543dd73ba..1094fe887 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js @@ -6,10 +6,17 @@ export default async function deleteDocument(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const Document = new Parse.Query('contracts_Document'); Document.equalTo('objectId', request.params.document_id); Document.equalTo('CreatedBy', userPtr); @@ -25,6 +32,13 @@ export default async function deleteDocument(request, response) { deleteQuery.set('IsArchive', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_document', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: request.params.document_id, deletedAt: deleteRes.get('updatedAt'), @@ -32,6 +46,13 @@ export default async function deleteDocument(request, response) { } } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_document', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Document not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index 9967f9001..d22417e9c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -6,10 +6,16 @@ export default async function deletedTemplate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const template = new Parse.Query('contracts_Template'); template.equalTo('objectId', request.params.template_id); template.equalTo('CreatedBy', userPtr); @@ -25,6 +31,13 @@ export default async function deletedTemplate(request, response) { deleteQuery.set('IsArchive', true); const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); if (deleteRes) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_template', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: request.params.template_id, deletedAt: deleteRes.get('updatedAt'), @@ -32,6 +45,13 @@ export default async function deletedTemplate(request, response) { } } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_template', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Template not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js index b51be025a..23cdf6cde 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js @@ -5,10 +5,17 @@ export default async function deleteWebhook(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const query = new Parse.Query('contracts_Users'); query.equalTo('UserId', userPtr); const user = await query.first({ useMasterKey: true }); @@ -18,11 +25,25 @@ export default async function deleteWebhook(request, response) { updateQuery.unset('Webhook'); const res = await updateQuery.save(null, { useMasterKey: true }); if (res) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_webhook', + properties: { response_code: 200 }, + }); + } return response.json({ result: 'Webhook deleted successfully!', }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'delete_webhook', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'User not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index e400cd372..15270b088 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -6,10 +6,17 @@ export default async function getContact(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const Contactbook = new Parse.Query('contracts_Contactbook'); Contactbook.equalTo('objectId', request.params.contact_id); Contactbook.equalTo('CreatedBy', userPtr); @@ -19,6 +26,13 @@ export default async function getContact(request, response) { const res = await Contactbook.first({ useMasterKey: true }); if (res) { const parseRes = JSON.parse(JSON.stringify(res)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_contact', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: parseRes.objectId, name: parseRes.Name, @@ -28,6 +42,13 @@ export default async function getContact(request, response) { updatedAt: parseRes.updatedAt, }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_contact', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Contact not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index 3ecfc7885..b0d473d4b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -6,10 +6,16 @@ export default async function getContactList(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const limit = request?.query?.limit ? parseInt(request.query.limit) : 100; const skip = request?.query?.skip ? parseInt(request.query.skip) : 0; const Contactbook = new Parse.Query('contracts_Contactbook'); @@ -29,8 +35,22 @@ export default async function getContactList(request, response) { createdAt: x.createdAt, updatedAt: x.updatedAt, })); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_contact_list', + properties: { response_code: 200 }, + }); + } return response.json({ result: contactlist }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_contact_list', + properties: { response_code: 200 }, + }); + } return response.json({ result: [] }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index 4643460ae..4ba439673 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -6,10 +6,16 @@ export default async function getDocument(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const Document = new Parse.Query('contracts_Document'); Document.equalTo('objectId', request.params.document_id); Document.equalTo('CreatedBy', userPtr); @@ -20,6 +26,13 @@ export default async function getDocument(request, response) { const res = await Document.first({ useMasterKey: true }); if (res) { const document = JSON.parse(JSON.stringify(res)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_document', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: document.objectId, title: document.Name, @@ -34,6 +47,13 @@ export default async function getDocument(request, response) { updatedAt: document.updatedAt, }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_document', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Document not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index a4cf04d12..4540a5ec2 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -12,10 +12,16 @@ export default async function getDocumentList(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const docType = request.params.doctype; const limit = request?.query?.limit ? request.query.limit : 100; const skip = request?.query?.skip ? request.query.skip : 0; @@ -42,7 +48,7 @@ export default async function getDocumentList(request, response) { default: reportId = ''; } - const json = reportId && reportJson(reportId, userPtr.id); + const json = reportId && reportJson(reportId, userPtr.objectId); const clsName = 'contracts_Document'; if (reportId && json) { const { params, keys } = json; @@ -57,6 +63,13 @@ export default async function getDocumentList(request, response) { const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; const res = await axios.get(url, { headers: headers }); if (res.data && res.data.results.length > 0) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_document_list_by_status', + properties: { response_code: 200 }, + }); + } const updateRes = res.data.results.map(x => ({ objectId: x.objectId, title: x.Name, @@ -74,6 +87,13 @@ export default async function getDocumentList(request, response) { return response.json({ result: [] }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_document_list_by_status', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Report not available!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index ab56f2b36..818fb7223 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -6,10 +6,17 @@ export default async function getTemplate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const Template = new Parse.Query('contracts_Template'); Template.equalTo('objectId', request.params.template_id); Template.equalTo('CreatedBy', userPtr); @@ -20,6 +27,14 @@ export default async function getTemplate(request, response) { const res = await Template.first({ useMasterKey: true }); if (res) { const template = JSON.parse(JSON.stringify(res)); + + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_template', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: template.objectId, title: template.Name, @@ -34,6 +49,13 @@ export default async function getTemplate(request, response) { updatedAt: template.updatedAt, }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_template', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Template not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 435e99f73..6d4d5e978 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -1,7 +1,6 @@ import axios from 'axios'; import dotenv from 'dotenv'; dotenv.config(); - export default async function getTemplatetList(request, response) { const reqToken = request.headers['x-api-token']; const appId = process.env.APP_ID; @@ -11,21 +10,24 @@ export default async function getTemplatetList(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const limit = request?.query?.limit ? request.query.limit : 100; const skip = request?.query?.skip ? request.query.skip : 0; const clsName = 'contracts_Template'; const params = { Type: { $ne: 'Folder' }, - CreatedBy: { - __type: 'Pointer', - className: '_User', - objectId: userPtr.id, - }, + CreatedBy: userPtr, IsArchive: { $ne: true }, }; const keys = [ @@ -51,6 +53,13 @@ export default async function getTemplatetList(request, response) { const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; const res = await axios.get(url, { headers: headers }); if (res.data && res.data.results.length > 0) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_template_list', + properties: { response_code: 200 }, + }); + } const updateRes = res.data.results.map(x => ({ objectId: x.objectId, title: x.Name, @@ -65,6 +74,13 @@ export default async function getTemplatetList(request, response) { return response.json({ result: updateRes }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_template_list', + properties: { response_code: 200 }, + }); + } return response.json({ result: [] }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index 81da0d479..b1e9b25df 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -8,16 +8,30 @@ export default async function getUser(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const query = new Parse.Query('contracts_Users'); query.equalTo('UserId', userPtr); query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); const user = await query.first({ useMasterKey: true }); if (user) { const parseRes = JSON.parse(JSON.stringify(user)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_your_account_details', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: parseRes.objectId, name: parseRes.Name, @@ -29,6 +43,13 @@ export default async function getUser(request, response) { updatedAt: parseRes.updatedAt, }); } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_your_account_details', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'User not found!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js index 244965e2b..2b3c73ee6 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -5,16 +5,28 @@ export default async function getWebhook(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const query = new Parse.Query('contracts_Users'); query.equalTo('UserId', userPtr); const user = await query.first({ useMasterKey: true }); if (user) { const parseUser = JSON.parse(JSON.stringify(user)); - + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_webhook', + properties: { response_code: 200 }, + }); + } if (parseUser && parseUser.Webhook) { return response.json({ webhook: parseUser.Webhook, @@ -23,6 +35,13 @@ export default async function getWebhook(request, response) { return response.json({}); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'get_webhook', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'User not found!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js index bbb2be945..caff3d8ce 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -6,10 +6,16 @@ export default async function saveWebhook(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const userPtr = token.get('userId'); + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; const query = new Parse.Query('contracts_Users'); query.equalTo('UserId', userPtr); const user = await query.first({ useMasterKey: true }); @@ -24,23 +30,52 @@ export default async function saveWebhook(request, response) { updateQuery.set('Webhook', Url); const res = await updateQuery.save(null, { useMasterKey: true }); if (res) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'save_webhook', + properties: { response_code: 200 }, + }); + } return response.json({ result: 'Webhook updated successfully!', }); } } catch (err) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'save_webhook', + properties: { response_code: 400 }, + }); + } console.log('Err ', err); return response .status(400) .json({ error: 'Something went wrong, please try again later!' }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'save_webhook', + properties: { response_code: 401 }, + }); + } return response.status(401).json({ error: 'Webhook url already exists!' }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'save_webhook', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'User not found!' }); } } else { return response.status(405).json({ error: 'Invalid API Token!' }); } } +// client.shutdown() diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index 51fda1139..bdd98690c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -6,14 +6,20 @@ export default async function updateDocument(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request const allowedKeys = ['name', 'note', 'description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; if (isValid) { - const userPtr = token.get('userId'); const document = new Parse.Query('contracts_Document'); document.equalTo('objectId', request.params.document_id); document.equalTo('CreatedBy', userPtr); @@ -44,6 +50,13 @@ export default async function updateDocument(request, response) { } const updatedRes = await updateQuery.save(null, { useMasterKey: true }); if (updatedRes) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'update_document', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: updatedRes.id, updatedAt: updatedRes.get('updatedAt'), @@ -51,9 +64,23 @@ export default async function updateDocument(request, response) { } } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'update_document', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Document not found!' }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'update_document', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please provide valid field names!' }); } } else { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index 7bbe031b2..ab3405c29 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -6,14 +6,20 @@ export default async function updateTemplate(request, response) { } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request const allowedKeys = ['name', 'note', 'description']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; if (isValid) { - const userPtr = token.get('userId'); const template = new Parse.Query('contracts_Template'); template.equalTo('objectId', request.params.template_id); template.equalTo('CreatedBy', userPtr); @@ -44,6 +50,13 @@ export default async function updateTemplate(request, response) { } const updatedRes = await updateQuery.save(null, { useMasterKey: true }); if (updatedRes) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'update_template', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: updatedRes.id, updatedAt: updatedRes.get('updatedAt'), @@ -51,9 +64,23 @@ export default async function updateTemplate(request, response) { } } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'update_template', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Template not found!' }); } } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'update_template', + properties: { response_code: 400 }, + }); + } return response.status(400).json({ error: 'Please provide valid field names!' }); } } else { diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 28d63e64a..07da66812 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -20,7 +20,7 @@ import { app as customRoute } from './cloud/customRoute/customApp.js'; import { exec } from 'child_process'; import { createTransport } from 'nodemailer'; import { app as v1 } from './cloud/customRoute/v1/apiV1.js'; - +import { PostHog } from 'posthog-node'; const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT); // console.log("configuration ", configuration); if (process.env.USE_LOCAL !== 'TRUE') { @@ -154,6 +154,16 @@ function getUserIP(request) { return request.socket.remoteAddress; } } +app.use(function (req, res, next) { + const ph_project_api_key = process.env.PH_PROJECT_API_KEY; + try { + req.posthog = new PostHog(ph_project_api_key); + } catch (err) { + // console.log('Err', err); + req.posthog = ''; + } + next(); +}); // Serve static assets from the /public folder app.use('/public', express.static(path.join(__dirname, '/public'))); diff --git a/apps/OpenSignServer/package-lock.json b/apps/OpenSignServer/package-lock.json index fac7ba41c..119072cf3 100644 --- a/apps/OpenSignServer/package-lock.json +++ b/apps/OpenSignServer/package-lock.json @@ -35,6 +35,7 @@ "parse-server-s3-adapter": "^1.2.0", "pdf-lib": "^1.16.0", "pdfkit": "^0.13.0", + "posthog-node": "^3.6.2", "razorpay": "^2.8.6", "request": "^2.88.2" }, @@ -8373,6 +8374,47 @@ "node": ">=0.10.0" } }, + "node_modules/posthog-node": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-3.6.2.tgz", + "integrity": "sha512-tVIaShR3SxBx17AlAUS86jQTweKuJIFRedBB504fCz7YPnXJTYSrVcUHn5IINE2wu4jUQimQK6ihQr90Djrdrg==", + "dependencies": { + "axios": "^1.6.2", + "rusha": "^0.8.14" + }, + "engines": { + "node": ">=15.0.0" + } + }, + "node_modules/posthog-node/node_modules/axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/posthog-node/node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/precond": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", @@ -8870,6 +8912,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rusha": { + "version": "0.8.14", + "resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz", + "integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==" + }, "node_modules/safari-14-idb-fix": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz", diff --git a/apps/OpenSignServer/package.json b/apps/OpenSignServer/package.json index 350f10979..de0fa18b4 100644 --- a/apps/OpenSignServer/package.json +++ b/apps/OpenSignServer/package.json @@ -44,6 +44,7 @@ "parse-server-s3-adapter": "^1.2.0", "pdf-lib": "^1.16.0", "pdfkit": "^0.13.0", + "posthog-node": "^3.6.2", "razorpay": "^2.8.6", "request": "^2.88.2" }, From f565edc6550069e9312238395cf77d50c5d75ad4 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 14 Feb 2024 12:31:37 +0530 Subject: [PATCH 64/73] refactor: change tour message as well as popup from template flow --- .../SignDocuments/src/Component/TemplatePlaceholder.js | 8 ++++---- .../src/Component/component/fieldsComponent.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js b/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js index 07762c8d7..a8c34524d 100644 --- a/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js +++ b/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js @@ -726,7 +726,7 @@ const TemplatePlaceholder = () => { selector: '[data-tut="reactourFirst"]', content: () => ( <TourContentWithBtn - message={`Select a recipient from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.`} + message={`Select a role from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.`} isChecked={handleDontShow} /> ), @@ -749,7 +749,7 @@ const TemplatePlaceholder = () => { selector: '[data-tut="reactourThird"]', content: () => ( <TourContentWithBtn - message={`Drag the placeholder for a recipient anywhere on the document.Remember, it will appear in the same colour as the name of the recipient for easy reference.`} + message={`Drag the placeholder for a role anywhere on the document.Remember, it will appear in the same colour as the name of the recipient for easy reference.`} isChecked={handleDontShow} /> ), @@ -1020,11 +1020,11 @@ const TemplatePlaceholder = () => { <ModalUi headerColor={"#dc3545"} isOpen={!IsReceipent} - title={"Receipent required"} + title={"Roles"} handleClose={() => setIsReceipent(true)} > <div style={{ height: "100%", padding: 20 }}> - <p>Please add receipent.</p> + <p>Please add a role</p> </div> </ModalUi> {/* this modal is used show send mail message and after send mail success message */} diff --git a/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js b/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js index c3b4947ef..4cec31cb6 100644 --- a/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js +++ b/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js @@ -370,7 +370,7 @@ function FieldsComponent({ )} {isSignersModal && ( <ModalUi - title={"Recipients"} + title={"Roles"} isOpen={isSignersModal} handleClose={handleModal} > @@ -398,7 +398,7 @@ function FieldsComponent({ textAlign: "center" }} > - Please add Recipient + Please add a role </div> )} </ModalUi> From 9114908521a0fc7431d4fc682b0b93105e0737ec Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 14 Feb 2024 16:03:12 +0530 Subject: [PATCH 65/73] standarize all modal in frontend --- .../src/components/AppendFormInForm.js | 7 +- apps/OpenSign/src/components/LoginGoogle.js | 200 ++++++++---------- .../src/components/fields/SignersInput.js | 20 +- apps/OpenSign/src/constant/const.js | 2 + apps/OpenSign/src/json/plansArr.json | 2 +- apps/OpenSign/src/routes/Form.js | 1 + apps/OpenSign/src/routes/Login.js | 164 +++++++------- apps/OpenSign/src/routes/PlanSubscriptions.js | 20 +- 8 files changed, 196 insertions(+), 220 deletions(-) diff --git a/apps/OpenSign/src/components/AppendFormInForm.js b/apps/OpenSign/src/components/AppendFormInForm.js index 47679d033..4f757e5bf 100644 --- a/apps/OpenSign/src/components/AppendFormInForm.js +++ b/apps/OpenSign/src/components/AppendFormInForm.js @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import Parse from "parse"; import axios from "axios"; +import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const"; const AppendFormInForm = (props) => { const [name, setName] = useState(""); @@ -293,14 +294,16 @@ const AppendFormInForm = (props) => { <div className="mt-4 flex justify-start"> <button type="submit" - className="bg-[#1ab6ce] text-sm text-white px-4 py-2 rounded shadow focus:outline-none" + style={{ backgroundColor: modalSubmitBtnColor }} + className="mr-2 px-[20px] py-1.5 text-white rounded shadow-md text-center focus:outline-none " > Submit </button> <button type="button" onClick={() => handleReset()} - className="bg-[#188ae2] text-sm text-white px-4 py-2 rounded ml-2 shadow focus:outline-none" + style={{ backgroundColor: modalCancelBtnColor }} + className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none" > Reset </button> diff --git a/apps/OpenSign/src/components/LoginGoogle.js b/apps/OpenSign/src/components/LoginGoogle.js index a95f903bf..002686390 100644 --- a/apps/OpenSign/src/components/LoginGoogle.js +++ b/apps/OpenSign/src/components/LoginGoogle.js @@ -2,6 +2,8 @@ import React, { useState, useRef } from "react"; import Parse from "parse"; import jwtDecode from "jwt-decode"; import { useScript } from "../hook/useScript"; +import ModalUi from "../primitives/ModalUi"; +import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const"; /* * `GoogleSignInBtn`as it's name indicates it render google sign in button @@ -231,118 +233,94 @@ const GoogleSignInBtn = ({ </div> )} <div ref={googleBtn} className="text-sm"></div> - - {isModal && ( - <div - className="modal fade show" - id="exampleModal" - tabIndex="-1" - role="dialog" - style={{ display: "block", zIndex: 1 }} - > - <div className="modal-dialog" role="document"> - <div className="modal-content"> - <div className="modal-header"> - <h5 className="modal-title">Sign up form</h5> - <span> - <span></span> - </span> - </div> - <div className="modal-body"> - <form> - <div className="form-group"> - <label - htmlFor="Phone" - style={{ display: "flex" }} - className="col-form-label" - > - Phone{" "} - <span style={{ fontSize: 13, color: "red" }}>*</span> - </label> - <input - type="tel" - className="form-control" - id="Phone" - value={userDetails.Phone} - onChange={(e) => - setUserDetails({ - ...userDetails, - Phone: e.target.value - }) - } - required - /> - </div> - <div className="form-group"> - <label - htmlFor="Company" - style={{ display: "flex" }} - className="col-form-label" - > - Company{" "} - <span style={{ fontSize: 13, color: "red" }}>*</span> - </label> - <input - type="text" - className="form-control" - id="Company" - value={userDetails.Company} - onChange={(e) => - setUserDetails({ - ...userDetails, - Company: e.target.value - }) - } - required - /> - </div> - <div className="form-group"> - <label - htmlFor="JobTitle" - style={{ display: "flex" }} - className="col-form-label" - > - Job Title{" "} - <span style={{ fontSize: 13, color: "red" }}>*</span> - </label> - <input - type="text" - className="form-control" - id="JobTitle" - value={userDetails.Destination} - onChange={(e) => - setUserDetails({ - ...userDetails, - Destination: e.target.value - }) - } - required - /> - </div> - <div> - <button - type="button" - className="bg-[#17a2b8] p-2 text-white rounded" - onClick={() => handleSubmitbtn()} - style={{ marginRight: 10 }} - > - Sign up - </button> - <button - type="button" - className="bg-[#6c757d] p-2 text-white rounded" - onClick={handleCloseModal} - style={{ width: 90 }} - > - Cancel - </button> - </div> - </form> - </div> - </div> + <ModalUi showClose={false} isOpen={isModal} title="Sign up form"> + <form className="px-4 py-3"> + <div className="mb-3"> + <label + htmlFor="Phone" + style={{ display: "flex" }} + className="block text-xs text-gray-700 font-semibold" + > + Phone <span style={{ fontSize: 13, color: "red" }}>*</span> + </label> + <input + type="tel" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + id="Phone" + value={userDetails.Phone} + onChange={(e) => + setUserDetails({ + ...userDetails, + Phone: e.target.value + }) + } + required + /> </div> - </div> - )} + <div className="mb-3"> + <label + htmlFor="Company" + style={{ display: "flex" }} + className="block text-xs text-gray-700 font-semibold" + > + Company <span style={{ fontSize: 13, color: "red" }}>*</span> + </label> + <input + type="text" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + id="Company" + value={userDetails.Company} + onChange={(e) => + setUserDetails({ + ...userDetails, + Company: e.target.value + }) + } + required + /> + </div> + <div className="mb-3"> + <label + htmlFor="JobTitle" + style={{ display: "flex" }} + className="block text-xs text-gray-700 font-semibold" + > + Job Title <span style={{ fontSize: 13, color: "red" }}>*</span> + </label> + <input + type="text" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + id="JobTitle" + value={userDetails.Destination} + onChange={(e) => + setUserDetails({ + ...userDetails, + Destination: e.target.value + }) + } + required + /> + </div> + <div> + <button + type="button" + className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none " + onClick={() => handleSubmitbtn()} + style={{ marginRight: 10, backgroundColor: modalSubmitBtnColor }} + > + Sign up + </button> + <button + type="button" + className="p-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none" + onClick={handleCloseModal} + style={{ width: 90, backgroundColor: modalCancelBtnColor }} + > + Cancel + </button> + </div> + </form> + </ModalUi> </div> ); }; diff --git a/apps/OpenSign/src/components/fields/SignersInput.js b/apps/OpenSign/src/components/fields/SignersInput.js index af6016931..6cfb93dc0 100644 --- a/apps/OpenSign/src/components/fields/SignersInput.js +++ b/apps/OpenSign/src/components/fields/SignersInput.js @@ -147,6 +147,7 @@ const SignersInput = (props) => { right: "auto", bottom: "auto", transform: "translate(-50%, -50%)", + border: "1px transparent", padding: 0 }, overlay: { @@ -158,18 +159,15 @@ const SignersInput = (props) => { > <div className="min-w-full md:min-w-[500px]"> <div - type="button" - className="flex justify-between items-center p-3 border-b-[1px] border-gray-300" + className="flex justify-between rounded-t items-center py-[10px] px-[20px] text-white" + style={{ background: "#32a3ac" }} > - <div className=" text-black text-xl font-semibold pl-3"> - Add Signer - </div> - <button onClick={handleModalCloseClick}> - <i - style={{ fontSize: 25 }} - className="fa fa-times-circle" - aria-hidden="true" - ></i> + <div className="text-[1.2rem] font-normal">Add Signer</div> + <button + onClick={handleModalCloseClick} + className="text-[1.5rem] cursor-pointer focus:outline-none" + > + × </button> </div> diff --git a/apps/OpenSign/src/constant/const.js b/apps/OpenSign/src/constant/const.js index b2401db56..4f7ded0f8 100644 --- a/apps/OpenSign/src/constant/const.js +++ b/apps/OpenSign/src/constant/const.js @@ -5,3 +5,5 @@ export const rejectBtn = "bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]"; export const submitBtn = "bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center"; +export const modalSubmitBtnColor = "#17a2b8"; +export const modalCancelBtnColor = "white"; diff --git a/apps/OpenSign/src/json/plansArr.json b/apps/OpenSign/src/json/plansArr.json index 8d337fdb0..90ab47bdc 100644 --- a/apps/OpenSign/src/json/plansArr.json +++ b/apps/OpenSign/src/json/plansArr.json @@ -27,7 +27,7 @@ "planName": "THANKS PLAN", "currency": "$", "price": "29.99", - "subtitle": "Use code 'FREEBETA' to get this for free(First 1000 users)", + "subtitle": "Use code <span style='background-color: yellow;'>'FREEBETA'</span> to get this for free(First 1000 users)", "btnText": "Subscribe", "url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks", "target": "_self", diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index 0bf604eaa..1069753e6 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -148,6 +148,7 @@ const Forms = (props) => { const dropboxCancel = async () => {}; const handleSubmit = async (e) => { e.preventDefault(); + e.stopPropagation(); setIsSubmit(true); try { const currentUser = Parse.User.current(); diff --git a/apps/OpenSign/src/routes/Login.js b/apps/OpenSign/src/routes/Login.js index 53d349211..04c49ac2f 100644 --- a/apps/OpenSign/src/routes/Login.js +++ b/apps/OpenSign/src/routes/Login.js @@ -11,6 +11,8 @@ import GoogleSignInBtn from "../components/LoginGoogle"; import { NavLink, useNavigate, useLocation } from "react-router-dom"; import login_img from "../assets/images/login_img.svg"; import { useWindowSize } from "../hook/useWindowSize"; +import ModalUi from "../primitives/ModalUi"; +import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const"; function Login(props) { const navigate = useNavigate(); @@ -1131,100 +1133,76 @@ function Login(props) { {state.toastDescription} </div> </div> - {isModal && ( - <div - className="modal fade show" - id="exampleModal" - tabIndex="-1" - role="dialog" - style={{ - display: "block", - zIndex: 1, - backgroundColor: "rgba(0,0,0,0.5)" - }} - > - <div className="modal-dialog" role="document"> - <div className="modal-content"> - <div className="modal-header"> - <h5 className="modal-title font-semibold"> - Additional Info - </h5> - <span> - <span></span> - </span> - </div> - <div className="modal-body"> - <form className="text-sm"> - <div className="form-group"> - <label - htmlFor="Company" - style={{ display: "flex" }} - className="col-form-label" - > - Company{" "} - <span style={{ fontSize: 13, color: "red" }}>*</span> - </label> - <input - type="text" - className="form-control" - id="Company" - value={userDetails.Company} - onChange={(e) => - setUserDetails({ - ...userDetails, - Company: e.target.value - }) - } - required - /> - </div> - <div className="form-group"> - <label - htmlFor="JobTitle" - style={{ display: "flex" }} - className="col-form-label" - > - Job Title - <span style={{ fontSize: 13, color: "red" }}>*</span> - </label> - <input - type="text" - className="form-control" - id="JobTitle" - value={userDetails.Destination} - onChange={(e) => - setUserDetails({ - ...userDetails, - Destination: e.target.value - }) - } - required - /> - </div> - <div className="mt-4"> - <button - type="button" - className="bg-[#17a2b8] text-sm p-2 text-white rounded uppercase" - onClick={(e) => handleSubmitbtn(e)} - style={{ marginRight: 10 }} - > - Login - </button> - <button - type="button" - className="bg-[#6c757d] text-sm p-2 text-white rounded uppercase" - onClick={handleCloseModal} - style={{ width: 90 }} - > - Cancel - </button> - </div> - </form> - </div> - </div> + <ModalUi isOpen={isModal} title="Additional Info" showClose={false}> + <form className="px-4 py-3"> + <div className="mb-3"> + <label + htmlFor="Company" + style={{ display: "flex" }} + className="block text-xs text-gray-700 font-semibold" + > + Company <span style={{ fontSize: 13, color: "red" }}>*</span> + </label> + <input + type="text" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + id="Company" + value={userDetails.Company} + onChange={(e) => + setUserDetails({ + ...userDetails, + Company: e.target.value + }) + } + required + /> </div> - </div> - )} + <div className="mb-3"> + <label + htmlFor="JobTitle" + style={{ display: "flex" }} + className="block text-xs text-gray-700 font-semibold" + > + Job Title + <span style={{ fontSize: 13, color: "red" }}>*</span> + </label> + <input + type="text" + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + id="JobTitle" + value={userDetails.Destination} + onChange={(e) => + setUserDetails({ + ...userDetails, + Destination: e.target.value + }) + } + required + /> + </div> + <div className="mt-4"> + <button + type="button" + className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none " + onClick={(e) => handleSubmitbtn(e)} + style={{ + marginRight: 10, + backgroundColor: modalSubmitBtnColor + }} + > + Login + </button> + <button + type="button" + className="py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none" + onClick={handleCloseModal} + style={{ width: 75, backgroundColor: modalCancelBtnColor }} + > + Cancel + </button> + </div> + </form> + </ModalUi> </> ) : ( <div diff --git a/apps/OpenSign/src/routes/PlanSubscriptions.js b/apps/OpenSign/src/routes/PlanSubscriptions.js index ceb764a3f..db39ee465 100644 --- a/apps/OpenSign/src/routes/PlanSubscriptions.js +++ b/apps/OpenSign/src/routes/PlanSubscriptions.js @@ -104,11 +104,27 @@ const PlanSubscriptions = () => { <div className={`${ item.subtitle.length <= 32 - ? "w-[150px] text-center" + ? "w-[150px] text-center" : "" } text-sm text-center my-2`} > - <p>{item.subtitle}</p> + <p + style={{ + backgroundColor: item.subtitlecolor + ? item.subtitlecolor + : "white" + }} + > + {item.subtitle.includes("<") ? ( + <div + dangerouslySetInnerHTML={{ + __html: item.subtitle + }} + /> + ) : ( + <span>{item.subtitle}</span> + )} + </p> </div> </div> From 13845adbd5152ca9c707ac0965d16cf19c614e3e Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 14 Feb 2024 19:05:00 +0530 Subject: [PATCH 66/73] feat: link changelog url to footer version --- apps/OpenSign/src/components/Footer.js | 12 ++++++++++-- apps/OpenSign/src/primitives/GetReportDisplay.js | 7 +++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/OpenSign/src/components/Footer.js b/apps/OpenSign/src/components/Footer.js index 92605da90..8ea0ac541 100644 --- a/apps/OpenSign/src/components/Footer.js +++ b/apps/OpenSign/src/components/Footer.js @@ -1,6 +1,8 @@ import React, { useEffect, useState } from "react"; import Package from "../../package.json"; import axios from "axios"; +import { NavLink } from "react-router-dom"; +import { openInNewTab } from "../constant/Utils"; const Footer = () => { const [showButton, setShowButton] = useState(false); const [version, setVersion] = useState(""); @@ -37,12 +39,18 @@ const Footer = () => { }, []); const appName = "OpenSign™"; - + const openUrl = () => { + openInNewTab( + "https://github.com/OpenSignLabs/OpenSign/releases/tag/" + version + ); + }; return ( <> <div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3"> All Rights Reserved © {new Date().getFullYear()}   - {appName} ( version: {version ? version : `${Package.version} `}) + <span onClick={openUrl} className="hover:underline cursor-pointer"> + {appName} ( version: {version ? version : `${Package.version} `}) + </span> </div> <button className={`${ diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js index 8e50fb667..8450c2657 100644 --- a/apps/OpenSign/src/primitives/GetReportDisplay.js +++ b/apps/OpenSign/src/primitives/GetReportDisplay.js @@ -5,6 +5,7 @@ import axios from "axios"; import "../styles/report.css"; import ModalUi from "./ModalUi"; import AppendFormInForm from "../components/AppendFormInForm"; +import { modalSubmitBtnColor, modalCancelBtnColor } from "../constant/const"; const ReportTable = ({ ReportName, List, @@ -342,13 +343,15 @@ const ReportTable = ({ <div className="flex items-center mt-3 gap-2 text-white"> <button onClick={() => handleDelete(item)} - className="bg-[#1ab6ce] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-3 focus:outline-none" + className="px-4 py-1.5 text-white rounded shadow-md text-center focus:outline-none " + style={{ backgroundColor: modalSubmitBtnColor }} > Yes </button> <button onClick={handleCloseDeleteModal} - className="bg-[#188ae2] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-3 text-center ml-[2px] focus:outline-none" + className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none" + style={{ backgroundColor: modalCancelBtnColor }} > No </button> From 9d15b035c5885bb5e1e97ca4810151d521be0a52 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Wed, 14 Feb 2024 22:10:57 +0530 Subject: [PATCH 67/73] fix: webhook api not working --- apps/OpenSign/src/components/Footer.js | 1 - .../v1/routes/CreateDocumentWithTemplate.js | 10 +- .../customRoute/v1/routes/createContact.js | 327 ++++++++++-------- .../customRoute/v1/routes/createDocument.js | 4 +- .../v1/routes/createDocumentwithCoordinate.js | 14 +- .../customRoute/v1/routes/createTemplate.js | 6 +- .../v1/routes/createTemplatewithCoordinate.js | 4 +- .../customRoute/v1/routes/deleteContact.js | 4 +- .../customRoute/v1/routes/deleteDocument.js | 4 +- .../customRoute/v1/routes/deleteTemplate.js | 19 +- .../customRoute/v1/routes/deleteWebhook.js | 77 +++-- .../cloud/customRoute/v1/routes/getContact.js | 4 +- .../customRoute/v1/routes/getContactList.js | 4 +- .../customRoute/v1/routes/getDocument.js | 4 +- .../customRoute/v1/routes/getDocumentList.js | 163 ++++----- .../customRoute/v1/routes/getTemplate.js | 6 +- .../customRoute/v1/routes/getTemplateList.js | 148 ++++---- .../cloud/customRoute/v1/routes/getUser.js | 91 ++--- .../cloud/customRoute/v1/routes/getWebhook.js | 83 ++--- .../customRoute/v1/routes/saveWebhook.js | 106 +++--- .../customRoute/v1/routes/updateDocument.js | 8 +- .../customRoute/v1/routes/updateTemplate.js | 8 +- .../cloud/parsefunction/reportsJson.js | 91 ++++- 23 files changed, 659 insertions(+), 527 deletions(-) diff --git a/apps/OpenSign/src/components/Footer.js b/apps/OpenSign/src/components/Footer.js index 8ea0ac541..31753698c 100644 --- a/apps/OpenSign/src/components/Footer.js +++ b/apps/OpenSign/src/components/Footer.js @@ -1,7 +1,6 @@ import React, { useEffect, useState } from "react"; import Package from "../../package.json"; import axios from "axios"; -import { NavLink } from "react-router-dom"; import { openInNewTab } from "../constant/Utils"; const Footer = () => { const [showButton, setShowButton] = useState(false); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 4b108ac87..228db6705 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -225,7 +225,7 @@ export default async function createDocumentWithTemplate(request, response) { 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'>Expire on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + + "</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 href=" + signPdf + @@ -300,7 +300,7 @@ export default async function createDocumentWithTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_document_with_templateid', + event: 'api_create_document_with_templateid', properties: { response_code: 200 }, }); } @@ -317,7 +317,7 @@ export default async function createDocumentWithTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_document_with_templateid', + event: 'api_create_document_with_templateid', properties: { response_code: 400 }, }); } @@ -327,7 +327,7 @@ export default async function createDocumentWithTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_document_with_templateid', + event: 'api_create_document_with_templateid', properties: { response_code: 400 }, }); } @@ -337,7 +337,7 @@ export default async function createDocumentWithTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_document_with_templateid', + event: 'api_create_document_with_templateid', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js index b0160a4aa..32d4683f5 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -9,133 +9,99 @@ export default async function createContact(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; - try { - const contactbook = new Parse.Query('contracts_Contactbook'); - contactbook.equalTo('Email', email); - contactbook.equalTo('CreatedBy', userPtr); - contactbook.notEqualTo('IsDeleted', true); - const userExists = await contactbook.first({ useMasterKey: true }); + try { + const contactbook = new Parse.Query('contracts_Contactbook'); + contactbook.equalTo('Email', email); + contactbook.equalTo('CreatedBy', userPtr); + contactbook.notEqualTo('IsDeleted', true); + const userExists = await contactbook.first({ useMasterKey: true }); - if (userExists) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'create_contact', - properties: { response_code: 401 }, - }); - } - return response - .status(401) - .json({ error: 'Contact already exists!', objectId: userExists.id }); - } else { - try { - const Tenant = new Parse.Query('partners_Tenant'); - Tenant.equalTo('UserId', userPtr); - const tenantRes = await Tenant.first({ useMasterKey: true }); - - const contactQuery = new Parse.Object('contracts_Contactbook'); - contactQuery.set('Name', name); - contactQuery.set('Phone', phone); - contactQuery.set('Email', email); - contactQuery.set('UserRole', 'contracts_Guest'); - if (tenantRes && tenantRes.id) { - contactQuery.set('TenantId', { - __type: 'Pointer', - className: 'partners_Tenant', - objectId: tenantRes.id, + if (userExists) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_create_contact', + properties: { response_code: 401 }, }); } + return response + .status(401) + .json({ error: 'Contact already exists!', objectId: userExists.id }); + } else { try { - const _users = Parse.Object.extend('User'); - const _user = new _users(); - _user.set('name', name); - _user.set('username', email); - _user.set('email', email); - _user.set('phone', phone); - _user.set('password', phone); - - const user = await _user.save(); - if (user) { - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: user.id, - }; - await axios.post(roleurl, body, { headers: headers }); - const currentUser = userPtr; - contactQuery.set('CreatedBy', currentUser); - contactQuery.set('UserId', user); - - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.objectId, true); - acl.setWriteAccess(userPtr.objectId, true); - acl.setReadAccess(user.id, true); - acl.setWriteAccess(user.id, true); - contactQuery.setACL(acl); + const Tenant = new Parse.Query('partners_Tenant'); + Tenant.equalTo('UserId', userPtr); + const tenantRes = await Tenant.first({ useMasterKey: true }); - const contactRes = await contactQuery.save(); - const parseRes = JSON.parse(JSON.stringify(contactRes)); - return response.json({ - objectId: parseRes.objectId, - name: parseRes.Name, - email: parseRes.Email, - phone: parseRes.Phone, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } - } catch (err) { - console.log('err in', err); - if (err.code === 202) { - const params = { email: email }; - const userRes = await Parse.Cloud.run('getUserId', params); - const roleurl = `${serverUrl}/functions/AddUserToRole`; - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - // sessionToken: localStorage.getItem('accesstoken'), - }; - const body = { - appName: 'contracts', - roleName: 'contracts_Guest', - userId: userRes.objectId, - }; - await axios.post(roleurl, body, { headers: headers }); - contactQuery.set('CreatedBy', userPtr.objectId); - contactQuery.set('UserId', { + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + contactQuery.set('Phone', phone); + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + if (tenantRes && tenantRes.id) { + contactQuery.set('TenantId', { __type: 'Pointer', - className: '_User', - objectId: userRes.id, + className: 'partners_Tenant', + objectId: tenantRes.id, }); - const acl = new Parse.ACL(); - acl.setReadAccess(userPtr.objectId, true); - acl.setWriteAccess(userPtr.objectId, true); - acl.setReadAccess(userRes.id, true); - acl.setWriteAccess(userRes.id, true); + } + 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('phone', phone); + _user.set('password', phone); + + const user = await _user.save(); + if (user) { + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: user.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = userPtr; + contactQuery.set('CreatedBy', currentUser); + contactQuery.set('UserId', user); - contactQuery.setACL(acl); - const contactRes = await contactQuery.save(); - if (contactRes) { + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.objectId, true); + acl.setWriteAccess(userPtr.objectId, true); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + contactQuery.setACL(acl); + + const contactRes = await contactQuery.save(); const parseRes = JSON.parse(JSON.stringify(contactRes)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_create_contact', + properties: { response_code: 200 }, + }); + } return response.json({ objectId: parseRes.objectId, name: parseRes.Name, @@ -145,51 +111,106 @@ export default async function createContact(request, response) { updatedAt: parseRes.updatedAt, }); } + } catch (err) { + console.log('err in', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: userRes.objectId, + }; + await axios.post(roleurl, body, { headers: headers }); + contactQuery.set('CreatedBy', userPtr.objectId); + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(userPtr.objectId, true); + acl.setWriteAccess(userPtr.objectId, true); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + + contactQuery.setACL(acl); + const contactRes = await contactQuery.save(); + if (contactRes) { + const parseRes = JSON.parse(JSON.stringify(contactRes)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_create_contact', + properties: { response_code: 200 }, + }); + } + return response.json({ + objectId: parseRes.objectId, + name: parseRes.Name, + email: parseRes.Email, + phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } + } else { + if (err.code === 137) { + return response.status(401).json({ error: 'Contact already exists!' }); + } + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); + } + } + } catch (err) { + console.log('err ', err); + if (err.code === 137) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_create_contact', + properties: { response_code: 401 }, + }); + } + return response.status(401).json({ error: 'Contact already exists!' }); } else { - if (err.code === 137) { - return response.status(401).json({ error: 'Contact already exists!' }); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_create_contact', + properties: { response_code: 400 }, + }); } return response .status(400) .json({ error: 'Something went wrong, please try again later!' }); } } - } catch (err) { - console.log('err ', err); - if (err.code === 137) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'create_contact', - properties: { response_code: 401 }, - }); - } - return response.status(401).json({ error: 'Contact already exists!' }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'create_contact', - properties: { response_code: 400 }, - }); - } - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); - } } + } catch (err) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_create_contact', + properties: { response_code: 400 }, + }); + } + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } - } catch (err) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'create_contact', - properties: { response_code: 400 }, - }); - } - return response.status(400).json({ error: 'Something went wrong, please try again later!' }); + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('Err ', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index 33f89b21a..a57c20e58 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -125,7 +125,7 @@ export default async function createDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'draft_document', + event: 'api_draft_document', properties: { response_code: 200 }, }); } @@ -137,7 +137,7 @@ export default async function createDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'draft_document', + event: 'api_draft_document', properties: { response_code: 400 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index 3f5b30171..527519038 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -60,11 +60,11 @@ export default async function createDocumentwithCoordinate(request, response) { // console.log('fileData ', fileData); const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); tokenQuery.include('userId'); @@ -278,7 +278,7 @@ export default async function createDocumentwithCoordinate(request, response) { 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'>Expire on</td><td> </td> <td style='color:#626363;font-weight:bold'>" + + "</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 href=" + signPdf + @@ -337,7 +337,7 @@ export default async function createDocumentwithCoordinate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_document', + event: 'api_create_document', properties: { response_code: 200 }, }); } @@ -354,7 +354,7 @@ export default async function createDocumentwithCoordinate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_document', + event: 'api_create_document', properties: { response_code: 400 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 742f487ba..1e835958a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -9,7 +9,7 @@ export default async function createTemplate(request, response) { const folderId = request.body?.folderId; const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; - const protocol = customAPIurl(); + const baseUrl = new URL(process.env.SERVER_URL); try { const reqToken = request.headers['x-api-token']; @@ -113,13 +113,13 @@ export default async function createTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'draft_template', + event: 'api_draft_template', properties: { response_code: 200 }, }); } return response.json({ objectId: res.id, - url: protocol + '/load/signmicroapp/template/' + res.id, + url: baseUrl.p + '/load/signmicroapp/template/' + res.id, }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index fd0a045db..40f0a170c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -182,7 +182,7 @@ export default async function createTemplatewithCoordinate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_template', + event: 'api_create_template', properties: { response_code: 200 }, }); } @@ -194,7 +194,7 @@ export default async function createTemplatewithCoordinate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'create_template', + event: 'api_create_template', properties: { response_code: 400 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js index ade460c9c..4926eceba 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -35,7 +35,7 @@ export default async function deleteContact(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_contact', + event: 'api_delete_contact', properties: { response_code: 200 }, }); } @@ -49,7 +49,7 @@ export default async function deleteContact(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_contact', + event: 'api_delete_contact', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js index 1094fe887..b166ec2ef 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js @@ -35,7 +35,7 @@ export default async function deleteDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_document', + event: 'api_delete_document', properties: { response_code: 200 }, }); } @@ -49,7 +49,7 @@ export default async function deleteDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_document', + event: 'api_delete_document', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js index d22417e9c..4011795e4 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -1,9 +1,9 @@ export default async function deletedTemplate(request, response) { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } try { - const reqToken = request.headers['x-api-token']; - if (!reqToken) { - return response.status(400).json({ error: 'Please Provide API Token' }); - } const tokenQuery = new Parse.Query('appToken'); tokenQuery.equalTo('token', reqToken); tokenQuery.include('userId'); @@ -23,6 +23,13 @@ export default async function deletedTemplate(request, response) { if (res) { const isArchive = res.get('IsArchive'); if (isArchive && isArchive) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_delete_template', + properties: { response_code: 404 }, + }); + } return response.status(404).json({ error: 'Template not found!' }); } else { const template = Parse.Object.extend('contracts_Template'); @@ -34,7 +41,7 @@ export default async function deletedTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_template', + event: 'api_delete_template', properties: { response_code: 200 }, }); } @@ -48,7 +55,7 @@ export default async function deletedTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_template', + event: 'api_delete_template', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js index 23cdf6cde..ac82b521f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteWebhook.js @@ -3,50 +3,55 @@ export default async function deleteWebhook(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - const user = await query.first({ useMasterKey: true }); - if (user) { - const updateQuery = new Parse.Object('contracts_Users'); - updateQuery.id = user.id; - updateQuery.unset('Webhook'); - const res = await updateQuery.save(null, { useMasterKey: true }); - if (res) { + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + const user = await query.first({ useMasterKey: true }); + if (user) { + const updateQuery = new Parse.Object('contracts_Users'); + updateQuery.id = user.id; + updateQuery.unset('Webhook'); + const res = await updateQuery.save(null, { useMasterKey: true }); + if (res) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_delete_webhook', + properties: { response_code: 200 }, + }); + } + return response.json({ + result: 'Webhook deleted successfully!', + }); + } + } else { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'delete_webhook', - properties: { response_code: 200 }, + event: 'api_delete_webhook', + properties: { response_code: 404 }, }); } - return response.json({ - result: 'Webhook deleted successfully!', - }); + return response.status(404).json({ error: 'User not found!' }); } } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'delete_webhook', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('err ', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js index 15270b088..e3d288586 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -29,7 +29,7 @@ export default async function getContact(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_contact', + event: 'api_get_contact', properties: { response_code: 200 }, }); } @@ -45,7 +45,7 @@ export default async function getContact(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_contact', + event: 'api_get_contact', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js index b0d473d4b..f20682c63 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -38,7 +38,7 @@ export default async function getContactList(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_contact_list', + event: 'api_get_contact_list', properties: { response_code: 200 }, }); } @@ -47,7 +47,7 @@ export default async function getContactList(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_contact_list', + event: 'api_get_contact_list', properties: { response_code: 200 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index 4ba439673..c02a3a93f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -29,7 +29,7 @@ export default async function getDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_document', + event: 'api_get_document', properties: { response_code: 200 }, }); } @@ -50,7 +50,7 @@ export default async function getDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_document', + event: 'api_get_document', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 4540a5ec2..bab8fcc66 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -10,92 +10,97 @@ export default async function getDocumentList(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const docType = request.params.doctype; - const limit = request?.query?.limit ? request.query.limit : 100; - const skip = request?.query?.skip ? request.query.skip : 0; - let reportId; - switch (docType) { - case 'draftdocuments': - reportId = 'ByHuevtCFY'; - break; - case 'signaturerequest': - reportId = '4Hhwbp482K'; - break; - case 'inprogressdocuments': - reportId = '1MwEuxLEkF'; - break; - case 'completedocuments': - reportId = 'kQUoW4hUXz'; - break; - case 'expiredocuments': - reportId = 'zNqBHXHsYH'; - break; - case 'declinedocuments': - reportId = 'UPr2Fm5WY3'; - break; - default: - reportId = ''; - } - const json = reportId && reportJson(reportId, userPtr.objectId); - const clsName = 'contracts_Document'; - if (reportId && json) { - const { params, keys } = json; - const orderBy = '-updatedAt'; - const strParams = JSON.stringify(params); - const strKeys = keys.join(); - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - 'X-Parse-Master-Key': process.env.MASTER_KEY, + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, }; - const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; - const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results.length > 0) { + const docType = request.params.doctype; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; + let reportId; + switch (docType) { + case 'draftdocuments': + reportId = 'ByHuevtCFY'; + break; + case 'signaturerequest': + reportId = '4Hhwbp482K'; + break; + case 'inprogressdocuments': + reportId = '1MwEuxLEkF'; + break; + case 'completedocuments': + reportId = 'kQUoW4hUXz'; + break; + case 'expiredocuments': + reportId = 'zNqBHXHsYH'; + break; + case 'declinedocuments': + reportId = 'UPr2Fm5WY3'; + break; + default: + reportId = ''; + } + const json = reportId && reportJson(reportId, userPtr.objectId); + const clsName = 'contracts_Document'; + if (reportId && json) { + const { params, keys } = json; + const orderBy = '-updatedAt'; + const strParams = JSON.stringify(params); + const strKeys = keys.join(); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results.length > 0) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_document_list_by_status', + properties: { response_code: 200 }, + }); + } + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + title: x.Name, + note: x.Note || '', + folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: + x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); + return response.json({ result: updateRes }); + } else { + return response.json({ result: [] }); + } + } else { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_document_list_by_status', - properties: { response_code: 200 }, + event: 'api_get_document_list_by_status', + properties: { response_code: 404 }, }); } - const updateRes = res.data.results.map(x => ({ - objectId: x.objectId, - title: x.Name, - note: x.Note || '', - folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', - file: x?.SignedUrl || x.URL, - owner: x?.ExtUserPtr?.Name, - signers: - x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], - createdAt: x.createdAt, - updatedAt: x.updatedAt, - })); - return response.json({ result: updateRes }); - } else { - return response.json({ result: [] }); - } - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_document_list_by_status', - properties: { response_code: 404 }, - }); + return response.status(404).json({ error: 'Report not available!' }); } - return response.status(404).json({ error: 'Report not available!' }); } + return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('Err', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } - return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index 818fb7223..4b9079a9c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -31,7 +31,7 @@ export default async function getTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_template', + event: 'api_get_template', properties: { response_code: 200 }, }); } @@ -40,7 +40,7 @@ export default async function getTemplate(request, response) { title: template.Name, note: template.Note || '', folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '', - file: template?.SignedUrl || x.URL, + file: template?.SignedUrl || template?.URL, owner: template?.ExtUserPtr?.Name, signers: template?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || @@ -52,7 +52,7 @@ export default async function getTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'get_template', + event: 'api_get_template', properties: { response_code: 404 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index 6d4d5e978..b47a9101a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -8,81 +8,87 @@ export default async function getTemplatetList(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; - const limit = request?.query?.limit ? request.query.limit : 100; - const skip = request?.query?.skip ? request.query.skip : 0; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; - const clsName = 'contracts_Template'; - const params = { - Type: { $ne: 'Folder' }, - CreatedBy: userPtr, - IsArchive: { $ne: true }, - }; - const keys = [ - 'Name', - 'Note', - 'Description', - 'Folder.Name', - 'URL', - 'SignedUrl', - 'ExtUserPtr.Name', - 'Signers.Name', - 'Signers.Email', - 'Signers.Phone', - ]; - const orderBy = '-updatedAt'; - const strParams = JSON.stringify(params); - const strKeys = keys.join(); - const headers = { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': appId, - 'X-Parse-Master-Key': process.env.MASTER_KEY, - }; - const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; - const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results.length > 0) { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_template_list', - properties: { response_code: 200 }, - }); - } - const updateRes = res.data.results.map(x => ({ - objectId: x.objectId, - title: x.Name, - note: x.Note || '', - folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', - file: x?.SignedUrl || x.URL, - owner: x?.ExtUserPtr?.Name, - signers: x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], - createdAt: x.createdAt, - updatedAt: x.updatedAt, - })); + const clsName = 'contracts_Template'; + const params = { + Type: { $ne: 'Folder' }, + CreatedBy: userPtr, + IsArchive: { $ne: true }, + }; + const keys = [ + 'Name', + 'Note', + 'Description', + 'Folder.Name', + 'URL', + 'SignedUrl', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ]; + const orderBy = '-updatedAt'; + const strParams = JSON.stringify(params); + const strKeys = keys.join(); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results.length > 0) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_template_list', + properties: { response_code: 200 }, + }); + } + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + title: x.Name, + note: x.Note || '', + folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: + x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); - return response.json({ result: updateRes }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_template_list', - properties: { response_code: 200 }, - }); + return response.json({ result: updateRes }); + } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_template_list', + properties: { response_code: 200 }, + }); + } + return response.json({ result: [] }); } - return response.json({ result: [] }); } + return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('err', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } - return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js index b1e9b25df..45776036e 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -6,52 +6,57 @@ export default async function getUser(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); - const user = await query.first({ useMasterKey: true }); - if (user) { - const parseRes = JSON.parse(JSON.stringify(user)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_your_account_details', - properties: { response_code: 200 }, + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); + const user = await query.first({ useMasterKey: true }); + if (user) { + const parseRes = JSON.parse(JSON.stringify(user)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_your_account_details', + properties: { response_code: 200 }, + }); + } + return response.json({ + objectId: parseRes.objectId, + name: parseRes.Name, + email: parseRes.Email, + phone: parseRes.Phone, + jobTitle: parseRes.JobTitle, + company: parseRes.Company, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, }); + } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_your_account_details', + properties: { response_code: 404 }, + }); + } + return response.status(404).json({ error: 'User not found!' }); } - return response.json({ - objectId: parseRes.objectId, - name: parseRes.Name, - email: parseRes.Email, - phone: parseRes.Phone, - jobTitle: parseRes.JobTitle, - company: parseRes.Company, - createdAt: parseRes.createdAt, - updatedAt: parseRes.updatedAt, - }); - } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_your_account_details', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); } + return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('Err', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } - return response.status(405).json({ error: 'Invalid API Token!' }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js index 2b3c73ee6..1dc692942 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getWebhook.js @@ -3,48 +3,53 @@ export default async function getWebhook(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - const user = await query.first({ useMasterKey: true }); - if (user) { - const parseUser = JSON.parse(JSON.stringify(user)); - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_webhook', - properties: { response_code: 200 }, - }); - } - if (parseUser && parseUser.Webhook) { - return response.json({ - webhook: parseUser.Webhook, - }); + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + const user = await query.first({ useMasterKey: true }); + if (user) { + const extUser = JSON.parse(JSON.stringify(user)); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_webhook', + properties: { response_code: 200 }, + }); + } + if (extUser && extUser.Webhook) { + return response.json({ + webhook: extUser.Webhook, + }); + } else { + return response.json({}); + } } else { - return response.json({}); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_webhook', + properties: { response_code: 404 }, + }); + } + return response.status(404).json({ error: 'User not found!' }); } } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'get_webhook', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('Err ', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js index caff3d8ce..9c6b4b9ba 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/saveWebhook.js @@ -4,78 +4,82 @@ export default async function saveWebhook(request, response) { if (!reqToken) { return response.status(400).json({ error: 'Please Provide API Token' }); } - const tokenQuery = new Parse.Query('appToken'); - tokenQuery.equalTo('token', reqToken); - tokenQuery.include('userId'); - const token = await tokenQuery.first({ useMasterKey: true }); - if (token !== undefined) { - // Valid Token then proceed request - const parseUser = JSON.parse(JSON.stringify(token)); - const userPtr = { - __type: 'Pointer', - className: '_User', - objectId: parseUser.userId.objectId, - }; - const query = new Parse.Query('contracts_Users'); - query.equalTo('UserId', userPtr); - const user = await query.first({ useMasterKey: true }); - if (user) { - const parseUser = JSON.parse(JSON.stringify(user)); - const isUrlExist = parseUser?.Webhook && parseUser?.Webhook === Url; + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', userPtr); + const user = await query.first({ useMasterKey: true }); + if (user) { + const extUser = JSON.parse(JSON.stringify(user)); + const isUrlExist = extUser?.Webhook && extUser?.Webhook === Url; - if (!isUrlExist) { - try { - const updateQuery = new Parse.Object('contracts_Users'); - updateQuery.id = user.id; - updateQuery.set('Webhook', Url); - const res = await updateQuery.save(null, { useMasterKey: true }); - if (res) { + if (!isUrlExist) { + try { + const updateQuery = new Parse.Object('contracts_Users'); + updateQuery.id = user.id; + updateQuery.set('Webhook', Url); + const res = await updateQuery.save(null, { useMasterKey: true }); + if (res) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_save_webhook', + properties: { response_code: 200 }, + }); + } + return response.json({ + result: 'Webhook updated successfully!', + }); + } + } catch (err) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'save_webhook', - properties: { response_code: 200 }, + event: 'api_save_webhook', + properties: { response_code: 400 }, }); } - return response.json({ - result: 'Webhook updated successfully!', - }); + console.log('Err ', err); + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } - } catch (err) { + } else { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'save_webhook', - properties: { response_code: 400 }, + event: 'api_save_webhook', + properties: { response_code: 401 }, }); } - console.log('Err ', err); - return response - .status(400) - .json({ error: 'Something went wrong, please try again later!' }); + return response.status(401).json({ error: 'Webhook url already exists!' }); } } else { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'save_webhook', - properties: { response_code: 401 }, + event: 'api_save_webhook', + properties: { response_code: 404 }, }); } - return response.status(401).json({ error: 'Webhook url already exists!' }); + return response.status(404).json({ error: 'User not found!' }); } } else { - if (request.posthog) { - request.posthog?.capture({ - distinctId: parseUser.userId.email, - event: 'save_webhook', - properties: { response_code: 404 }, - }); - } - return response.status(404).json({ error: 'User not found!' }); + return response.status(405).json({ error: 'Invalid API Token!' }); } - } else { - return response.status(405).json({ error: 'Invalid API Token!' }); + } catch (err) { + console.log('Err ', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); } } -// client.shutdown() diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js index bdd98690c..4e5246f0a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -10,7 +10,7 @@ export default async function updateDocument(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const allowedKeys = ['name', 'note', 'description']; + const allowedKeys = ['name', 'note', 'description', 'folderId']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; const parseUser = JSON.parse(JSON.stringify(token)); @@ -53,7 +53,7 @@ export default async function updateDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'update_document', + event: 'api_update_document', properties: { response_code: 200 }, }); } @@ -67,7 +67,7 @@ export default async function updateDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'update_document', + event: 'api_update_document', properties: { response_code: 404 }, }); } @@ -77,7 +77,7 @@ export default async function updateDocument(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'update_document', + event: 'api_update_document', properties: { response_code: 400 }, }); } diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js index ab3405c29..466721610 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -10,7 +10,7 @@ export default async function updateTemplate(request, response) { const token = await tokenQuery.first({ useMasterKey: true }); if (token !== undefined) { // Valid Token then proceed request - const allowedKeys = ['name', 'note', 'description']; + const allowedKeys = ['name', 'note', 'description', 'folderId']; const objectKeys = Object.keys(request.body); const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; const parseUser = JSON.parse(JSON.stringify(token)); @@ -53,7 +53,7 @@ export default async function updateTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'update_template', + event: 'api_update_template', properties: { response_code: 200 }, }); } @@ -67,7 +67,7 @@ export default async function updateTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'update_template', + event: 'api_update_template', properties: { response_code: 404 }, }); } @@ -77,7 +77,7 @@ export default async function updateTemplate(request, response) { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, - event: 'update_template', + event: 'api_update_template', properties: { response_code: 400 }, }); } diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js index 24bc07dae..199210639 100644 --- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js +++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js @@ -22,7 +22,16 @@ export default function reportJson(id, userId) { objectId: currentUserId, }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Note', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; // Need your sign report case '4Hhwbp482K': @@ -57,6 +66,8 @@ export default function reportJson(id, userId) { 'URL', 'ExtUserPtr.Name', 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', 'Signers.UserId', 'AuditTrail', ], @@ -81,7 +92,16 @@ export default function reportJson(id, userId) { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Note', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; // completed documents report case 'kQUoW4hUXz': @@ -106,6 +126,8 @@ export default function reportJson(id, userId) { 'SignedUrl', 'ExtUserPtr.Name', 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', 'TimeToCompleteDays', ], }; @@ -125,7 +147,16 @@ export default function reportJson(id, userId) { }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Note', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; // Expired Documents report case 'zNqBHXHsYH': @@ -155,7 +186,16 @@ export default function reportJson(id, userId) { objectId: currentUserId, }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Note', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; // Recently sent for signatures report show on dashboard case 'd9k3UfYHBc': @@ -177,7 +217,15 @@ export default function reportJson(id, userId) { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, }, - keys: ['Name', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; // Recent signature requests report show on dashboard case '5Go51Q7T8r': @@ -205,7 +253,16 @@ export default function reportJson(id, userId) { }, }, }, - keys: ['Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name', 'Signers.UserId', 'AuditTrail'], + keys: [ + 'Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.UserId', + 'AuditTrail', + 'Signers.Email', + 'Signers.Phone', + ], }; // Drafts report show on dashboard case 'kC5mfynCi4': @@ -227,7 +284,16 @@ export default function reportJson(id, userId) { objectId: currentUserId, }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Note', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; // contact book report case '5KhaPr482K': @@ -258,7 +324,16 @@ export default function reportJson(id, userId) { objectId: currentUserId, }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: [ + 'Name', + 'Note', + 'Folder.Name', + 'URL', + 'ExtUserPtr.Name', + 'Signers.Name', + 'Signers.Email', + 'Signers.Phone', + ], }; default: return null; From 7a9bebe035021f0f010ced2db05f2696e0468acb Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 15 Feb 2024 10:41:35 +0530 Subject: [PATCH 68/73] fix: document completion mail are not receiving --- apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 8ff68542b..bebaa36ce 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -269,7 +269,9 @@ async function PDF(i, n) { receiver: g, }; return ( - o.data.IsSendMail && sendMail(w), + o.data.IsSendMail && !1 === o.data.IsSendMail + ? console.log("don't send mail") + : sendMail(w), sendDoctoWebhook(o, U.imageUrl, 'signed', s?.data.results?.[0]), n && n.isCompleted && @@ -279,7 +281,9 @@ async function PDF(i, n) { pdfName: o.data.Name, receiver: o.data.ExtUserPtr.Email, }), - o.data.IsSendMail && sendCompletedMail(I), + o.data.IsSendMail && !1 === o.data.IsSendMail + ? console.log("don't send mail") + : sendCompletedMail(I), sendDoctoWebhook(o, U.imageUrl, 'completed')), fs.unlinkSync(x), console.log('New Signed PDF created called: ' + x), From 4f2801d901519f87c3170ae6847494f8a01f4efb Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 15 Feb 2024 11:06:27 +0530 Subject: [PATCH 69/73] =?UTF-8?q?refactor:=20change=20keyword=20in=20mail?= =?UTF-8?q?=20from=20opensign=20to=20OpenSign=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cloud/parsefunction/pdf/PDF.min.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index bebaa36ce..0c588349f 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -55,9 +55,9 @@ async function sendMail(e) { html: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png 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 Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " + s + - ' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + + ' Standard is attached to this email. 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 ' + t.Mail + - ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>', + ' 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>', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -80,9 +80,9 @@ async function sendCompletedMail(e) { html: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png 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 sign successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document" + s + - '. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + + '. 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 ' + t.Mail + - ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>', + ' 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>', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -238,13 +238,13 @@ async function PDF(i, n) { v && 0 < v.length ? plainAddPlaceholder({ pdfBuffer: e, - reason: 'Digitally signed by Open sign for ' + v?.join(', '), + reason: 'Digitally signed by OpenSign™ for ' + v?.join(', '), location: 'location', signatureLength: 1e4, }) : plainAddPlaceholder({ pdfBuffer: e, - reason: 'Digitally signed by Open sign for ' + m + ' <' + g + '>', + reason: 'Digitally signed by OpenSign™ for ' + m + ' <' + g + '>', location: 'location', signatureLength: 1e4, })), From 68050e3a35b579eb1a99ba3ac534892a8187a6d1 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 15 Feb 2024 15:43:32 +0530 Subject: [PATCH 70/73] feat: add Send in order to send mail sequentially for signing document --- apps/OpenSign/src/routes/Form.js | 31 +- .../v1/routes/CreateDocumentWithTemplate.js | 8 + .../v1/routes/createDocumentwithCoordinate.js | 7 + .../cloud/parsefunction/pdf/PDF.min.js | 4 +- .../src/Component/PdfRequestFiles.js | 419 +++++++++++------- .../src/Component/placeHolderSign.js | 6 +- 6 files changed, 320 insertions(+), 155 deletions(-) diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index 1069753e6..032454901 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -34,7 +34,8 @@ const Forms = (props) => { Name: "", Description: "", Note: "Please review and sign this document", - TimeToCompleteDays: 15 + TimeToCompleteDays: 15, + SendinOrder: "false" }); const [fileupload, setFileUpload] = useState([]); const [fileload, setfileload] = useState(false); @@ -161,6 +162,8 @@ const Forms = (props) => { "TimeToCompleteDays", parseInt(formData?.TimeToCompleteDays) ); + const isChecked = formData.SendinOrder === "true" ? true : false; + object.set("SendinOrder", isChecked); } object.set("URL", fileupload); object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); @@ -365,6 +368,32 @@ const Forms = (props) => { /> </div> )} + {props.title === "Request Signature" && ( + <div className="text-xs mt-2"> + <label className="block">Send In Order</label> + <div className="flex items-center gap-2 ml-2 mb-1"> + <input + type="radio" + value={"true"} + name="SendinOrder" + checked={formData.SendinOrder === "true"} + className="" + onChange={handleStrInput} + /> + <div className="text-center">Yes</div> + </div> + <div className="flex items-center gap-2 ml-2 mb-1"> + <input + type="radio" + value={"false"} + name="SendinOrder" + checked={formData.SendinOrder === "false"} + onChange={handleStrInput} + /> + <div className="text-center">No</div> + </div> + </div> + )} <div className="flex items-center mt-3 gap-2 text-white"> <button className={`${ diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 228db6705..1c4b9803f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -54,6 +54,8 @@ export default async function createDocumentWithTemplate(request, response) { const send_email = request.body.send_email; const email_subject = request.body.email_subject; const email_body = request.body.email_body; + const sendInOrder = request.body.sendInOrder || false; + try { const reqToken = request.headers['x-api-token']; if (!reqToken) { @@ -101,6 +103,9 @@ export default async function createDocumentWithTemplate(request, response) { object.set('Description', template.Description); } object.set('IsSendMail', send_email); + if (sendInOrder) { + object.set('SendinOrder', sendInOrder); + } let templateSigner = template?.Signers ? template?.Signers : []; let contact = []; @@ -196,6 +201,9 @@ export default async function createDocumentWithTemplate(request, response) { console.log("don't send mail"); } else { for (let i = 0; i < contact.length; i++) { + if (sendInOrder) { + contact.splice(1); + } try { const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index 527519038..5b04e2a3b 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -57,6 +57,7 @@ export default async function createDocumentwithCoordinate(request, response) { const fileData = request.files?.[0] ? request.files[0].buffer : null; const email_subject = request.body.email_subject; const email_body = request.body.email_body; + const sendInOrder = request.body.sendInOrder || false; // console.log('fileData ', fileData); const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); @@ -112,6 +113,9 @@ export default async function createDocumentwithCoordinate(request, response) { if (description) { object.set('Description', description); } + if (sendInOrder) { + object.set('SendinOrder', sendInOrder); + } object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); @@ -248,6 +252,9 @@ export default async function createDocumentwithCoordinate(request, response) { if (send_email === false) { console.log("don't send mail"); } else { + if (sendInOrder) { + contact.splice(1); + } for (let i = 0; i < contact.length; i++) { try { const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 0c588349f..85d56af52 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -238,13 +238,13 @@ async function PDF(i, n) { v && 0 < v.length ? plainAddPlaceholder({ pdfBuffer: e, - reason: 'Digitally signed by OpenSign™ for ' + v?.join(', '), + reason: 'Digitally signed by OpenSign for ' + v?.join(', '), location: 'location', signatureLength: 1e4, }) : plainAddPlaceholder({ pdfBuffer: e, - reason: 'Digitally signed by OpenSign™ for ' + m + ' <' + g + '>', + reason: 'Digitally signed by OpenSign for ' + m + ' <' + g + '>', location: 'location', signatureLength: 1e4, })), diff --git a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js index b935f9bea..992305225 100644 --- a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js +++ b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js @@ -79,6 +79,7 @@ function PdfRequestFiles() { const [isExpired, setIsExpired] = useState(false); const [alreadySign, setAlreadySign] = useState(false); const [containerWH, setContainerWH] = useState({}); + const [sendInOrder, setSendInOrder] = useState(false); const divRef = useRef(null); const isMobile = window.innerWidth < 767; const rowLevel = @@ -184,6 +185,7 @@ function PdfRequestFiles() { setAlreadySign(true); } else { const obj = documentData?.[0]; + setSendInOrder(obj?.SendinOrder || false); if ( obj && obj.Signers && @@ -328,175 +330,292 @@ function PdfRequestFiles() { }); }; + const checkSendInOrder = () => { + if (sendInOrder) { + const index = pdfDetails?.[0].Signers.findIndex( + (x) => x.Email === jsonSender.email + ); + const newIndex = index - 1; + if (newIndex !== -1) { + const user = pdfDetails?.[0].Signers[newIndex]; + const isPrevUserSigned = + pdfDetails?.[0].AuditTrail && + pdfDetails?.[0].AuditTrail.some( + (x) => + x.UserPtr.objectId === user.objectId && x.Activity === "Signed" + ); + if (isPrevUserSigned) { + return true; + } else { + return false; + } + } else { + return true; + } + } else { + return true; + } + }; //function for embed signature or image url in pdf async function embedImages() { - const checkUser = signerPos.filter( - (data) => data.signerObjId === signerObjectId - ); - if (checkUser && checkUser.length > 0) { - let checkSignUrl = []; - const checkSign = checkUser[0].placeHolder.filter( - (data, ind) => data.pos + const validateSigning = checkSendInOrder(); + if (validateSigning) { + const checkUser = signerPos.filter( + (data) => data.signerObjId === signerObjectId ); - for (let i = 0; i < checkSign.length; i++) { - const posData = checkSign[i].pos.filter((pos) => !pos.SignUrl); - if (posData && posData.length > 0) { - checkSignUrl.push(posData); + if (checkUser && checkUser.length > 0) { + let checkSignUrl = []; + const checkSign = checkUser[0].placeHolder.filter( + (data, ind) => data.pos + ); + for (let i = 0; i < checkSign.length; i++) { + const posData = checkSign[i].pos.filter((pos) => !pos.SignUrl); + if (posData && posData.length > 0) { + checkSignUrl.push(posData); + } } - } - if (checkSignUrl && checkSignUrl.length > 0) { - setIsAlert({ - isShow: true, - alertMessage: "Please complete your signature!" - }); - } else { - setIsUiLoading(true); - const pngUrl = checkUser[0].placeHolder; - // Load a PDFDocument from the existing PDF bytes - const existingPdfBytes = await fetch(pdfUrl).then((res) => - res.arrayBuffer() - ); - const pdfDoc = await PDFDocument.load(existingPdfBytes, { - ignoreEncryption: true - }); - // let pdfBase64; + if (checkSignUrl && checkSignUrl.length > 0) { + setIsAlert({ + isShow: true, + alertMessage: "Please complete your signature!" + }); + } else { + setIsUiLoading(true); + const pngUrl = checkUser[0].placeHolder; + // Load a PDFDocument from the existing PDF bytes + const existingPdfBytes = await fetch(pdfUrl).then((res) => + res.arrayBuffer() + ); + const pdfDoc = await PDFDocument.load(existingPdfBytes, { + ignoreEncryption: true + }); + // let pdfBase64; - //checking if signature is only one then send image url in jpeg formate to server - // if (pngUrl.length === 1 && pngUrl[0].pos.length === 1) { - // if (isDocId) { - // try { - // pdfBase64 = await getBase64FromUrl(pdfUrl); - // } catch (err) { - // console.log(err); - // } - // } else { - // //embed document's object id to all pages in pdf document - // try { - // await embedDocId(pdfDoc, documentId, allPages); - // } catch (err) { - // console.log(err); - // } - // try { - // pdfBase64 = await pdfDoc.saveAsBase64({ - // useObjectStreams: false - // }); - // } catch (err) { - // console.log(err); - // } - // } - // for (let pngData of pngUrl) { - // const imgUrlList = pngData.pos; - // const pageNo = pngData.pageNumber; - // imgUrlList.map(async (data) => { - // //cheking signUrl is defau;t signature url of custom url - // let ImgUrl = data.SignUrl; - // const checkUrl = urlValidator(ImgUrl); - // //if default signature url then convert it in base 64 - // if (checkUrl) { - // ImgUrl = await getBase64FromIMG(ImgUrl + "?get"); - // } - // //function for called convert png signatre to jpeg in base 64 - // convertPNGtoJPEG(ImgUrl) - // .then((jpegBase64Data) => { - // const removeBase64Fromjpeg = "data:image/jpeg;base64,"; - // const newImgUrl = jpegBase64Data.replace( - // removeBase64Fromjpeg, - // "" - // ); + //checking if signature is only one then send image url in jpeg formate to server + // if (pngUrl.length === 1 && pngUrl[0].pos.length === 1) { + // if (isDocId) { + // try { + // pdfBase64 = await getBase64FromUrl(pdfUrl); + // } catch (err) { + // console.log(err); + // } + // } else { + // //embed document's object id to all pages in pdf document + // try { + // await embedDocId(pdfDoc, documentId, allPages); + // } catch (err) { + // console.log(err); + // } + // try { + // pdfBase64 = await pdfDoc.saveAsBase64({ + // useObjectStreams: false + // }); + // } catch (err) { + // console.log(err); + // } + // } + // for (let pngData of pngUrl) { + // const imgUrlList = pngData.pos; + // const pageNo = pngData.pageNumber; + // imgUrlList.map(async (data) => { + // //cheking signUrl is defau;t signature url of custom url + // let ImgUrl = data.SignUrl; + // const checkUrl = urlValidator(ImgUrl); + // //if default signature url then convert it in base 64 + // if (checkUrl) { + // ImgUrl = await getBase64FromIMG(ImgUrl + "?get"); + // } + // //function for called convert png signatre to jpeg in base 64 + // convertPNGtoJPEG(ImgUrl) + // .then((jpegBase64Data) => { + // const removeBase64Fromjpeg = "data:image/jpeg;base64,"; + // const newImgUrl = jpegBase64Data.replace( + // removeBase64Fromjpeg, + // "" + // ); - // //function for call to embed signature in pdf and get digital signature pdf - // signPdfFun( - // newImgUrl, - // documentId, - // signerObjectId, - // pdfOriginalWidth, - // pngUrl, - // containerWH, - // setIsAlert, - // data, - // pdfBase64, - // pageNo - // ) - // .then((res) => { - // if (res && res.status === "success") { - // setPdfUrl(res.data); - // setIsSigned(true); - // setSignedSigners([]); - // setUnSignedSigners([]); - // getDocumentDetails(); - // } else { - // setIsAlert({ - // isShow: true, - // alertMessage: "something went wrong" - // }); - // } - // }) - // .catch((err) => { - // setIsAlert({ - // isShow: true, - // alertMessage: "something went wrong" - // }); - // }); - // }) - // .catch((error) => { - // console.error("Error:", error); - // }); - // }); - // } - // } - // //else if signature is more than one then embed all sign with the use of pdf-lib - // else if (pngUrl.length > 0 && pngUrl[0].pos.length > 0) { - const flag = false; - //embed document's object id to all pages in pdf document - if (!isDocId) { - await embedDocId(pdfDoc, documentId, allPages); - } - //embed multi signature in pdf - const pdfBytes = await multiSignEmbed( - pngUrl, - pdfDoc, - pdfOriginalWidth, - flag, - containerWH - ); - //function for call to embed signature in pdf and get digital signature pdf - try { - const res = await signPdfFun( - pdfBytes, - documentId, - signerObjectId, - pdfOriginalWidth, + // //function for call to embed signature in pdf and get digital signature pdf + // signPdfFun( + // newImgUrl, + // documentId, + // signerObjectId, + // pdfOriginalWidth, + // pngUrl, + // containerWH, + // setIsAlert, + // data, + // pdfBase64, + // pageNo + // ) + // .then((res) => { + // if (res && res.status === "success") { + // setPdfUrl(res.data); + // setIsSigned(true); + // setSignedSigners([]); + // setUnSignedSigners([]); + // getDocumentDetails(); + // } else { + // setIsAlert({ + // isShow: true, + // alertMessage: "something went wrong" + // }); + // } + // }) + // .catch((err) => { + // setIsAlert({ + // isShow: true, + // alertMessage: "something went wrong" + // }); + // }); + // }) + // .catch((error) => { + // console.error("Error:", error); + // }); + // }); + // } + // } + // //else if signature is more than one then embed all sign with the use of pdf-lib + // else if (pngUrl.length > 0 && pngUrl[0].pos.length > 0) { + const flag = false; + //embed document's object id to all pages in pdf document + if (!isDocId) { + await embedDocId(pdfDoc, documentId, allPages); + } + //embed multi signature in pdf + const pdfBytes = await multiSignEmbed( pngUrl, - containerWH, - setIsAlert + pdfDoc, + pdfOriginalWidth, + flag, + containerWH ); - if (res && res.status === "success") { - setPdfUrl(res.data); - setIsSigned(true); - setSignedSigners([]); - setUnSignedSigners([]); - getDocumentDetails(); - } else { + //function for call to embed signature in pdf and get digital signature pdf + try { + const res = await signPdfFun( + pdfBytes, + documentId, + signerObjectId, + pdfOriginalWidth, + pngUrl, + containerWH, + setIsAlert + ); + if (res && res.status === "success") { + setPdfUrl(res.data); + setIsSigned(true); + setSignedSigners([]); + setUnSignedSigners([]); + getDocumentDetails(); + if (sendInOrder) { + const index = pdfDetails?.[0].Signers.findIndex( + (x) => x.Email === jsonSender.email + ); + const newIndex = index + 1; + const user = pdfDetails?.[0].Signers[newIndex]; + if (user) { + let sendMail; + // console.log("pdfDetails", pdfDetails); + const expireDate = pdfDetails?.[0].ExpiryDate.iso; + const newDate = new Date(expireDate); + const localExpireDate = newDate.toLocaleDateString("en-US", { + day: "numeric", + month: "long", + year: "numeric" + }); + let sender = pdfDetails?.[0].ExtUserPtr.Email; + + try { + const imgPng = + "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; + let url = `${localStorage.getItem( + "baseUrl" + )}functions/sendmailv3/`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": + localStorage.getItem("parseAppId"), + sessionToken: localStorage.getItem("accesstoken") + }; + const serverUrl = localStorage.getItem("baseUrl"); + const newServer = serverUrl.replaceAll("/", "%2F"); + const objectId = user.objectId; + const serverParams = `${newServer}&${localStorage.getItem( + "parseAppId" + )}&${localStorage.getItem("_appName")}`; + + const hostUrl = + window.location.origin + "/loadmf/signmicroapp"; + let signPdf = `${hostUrl}/login/${pdfDetails?.[0].objectId}/${user.Email}/${objectId}/${serverParams}`; + const openSignUrl = + "https://www.opensignlabs.com/contact-us"; + const orgName = pdfDetails[0]?.ExtUserPtr.Company + ? pdfDetails[0].ExtUserPtr.Company + : ""; + const themeBGcolor = themeColor(); + let params = { + recipient: user.Email, + subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`, + 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;'> " + + pdfDetails?.[0].ExtUserPtr.Name + + " has requested you to review and sign <strong> " + + pdfDetails?.[0].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 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>" + }; + sendMail = await axios.post(url, params, { + headers: headers + }); + } catch (error) { + console.log("error", error); + } + } + } + } else { + setIsAlert({ + isShow: true, + alertMessage: "something went wrong" + }); + } + } catch (err) { setIsAlert({ isShow: true, alertMessage: "something went wrong" }); } - } catch (err) { - setIsAlert({ - isShow: true, - alertMessage: "something went wrong" - }); } - } - setIsSignPad(false); - // } + setIsSignPad(false); + // } + } else { + setIsAlert({ + isShow: true, + alertMessage: "something went wrong" + }); + } } else { setIsAlert({ isShow: true, - alertMessage: "something went wrong" + alertMessage: + "Please wait for your turn to sign this document, as it has been set up by the creator to be signed in a specific order; you'll be notified when it's your turn." }); } } diff --git a/microfrontends/SignDocuments/src/Component/placeHolderSign.js b/microfrontends/SignDocuments/src/Component/placeHolderSign.js index 5dd79e66b..ec16c84ae 100644 --- a/microfrontends/SignDocuments/src/Component/placeHolderSign.js +++ b/microfrontends/SignDocuments/src/Component/placeHolderSign.js @@ -661,8 +661,11 @@ function PlaceHolderSign() { year: "numeric" }); let sender = pdfDetails?.[0].ExtUserPtr.Email; - const signerMail = signersdata; + let signerMail = signersdata.slice(); + if (pdfDetails?.[0]?.SendinOrder && pdfDetails?.[0]?.SendinOrder === true) { + signerMail.splice(1); + } for (let i = 0; i < signerMail.length; i++) { try { const imgPng = @@ -691,7 +694,6 @@ function PlaceHolderSign() { recipient: signerMail[i].Email, subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`, 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 + From 97983c423ff1ada1531f13bfdb765d9b0dfbf550 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Thu, 15 Feb 2024 18:37:11 +0530 Subject: [PATCH 71/73] feat: add send in order in template --- apps/OpenSign/src/routes/Form.js | 2 +- .../v1/routes/CreateDocumentWithTemplate.js | 3 +- .../customRoute/v1/routes/createDocument.js | 4 ++ .../customRoute/v1/routes/createTemplate.js | 4 ++ .../v1/routes/createTemplatewithCoordinate.js | 4 ++ .../src/Component/TemplatePlaceholder.js | 3 +- .../src/Component/component/EditTemplate.js | 45 ++++++++++++++++++- .../SignDocuments/src/utils/Utils.js | 3 +- 8 files changed, 62 insertions(+), 6 deletions(-) diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index 032454901..8191b84b4 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -368,7 +368,7 @@ const Forms = (props) => { /> </div> )} - {props.title === "Request Signature" && ( + {props.title !== "Sign Yourself" && ( <div className="text-xs mt-2"> <label className="block">Send In Order</label> <div className="flex items-center gap-2 ml-2 mb-1"> diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 1c4b9803f..ebb0dbbe6 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -105,8 +105,9 @@ export default async function createDocumentWithTemplate(request, response) { object.set('IsSendMail', send_email); if (sendInOrder) { object.set('SendinOrder', sendInOrder); + } else if (template?.SendinOrder && template?.SendinOrder) { + object.set('SendinOrder', template?.SendinOrder); } - let templateSigner = template?.Signers ? template?.Signers : []; let contact = []; if (signers && signers.length > 0) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js index a57c20e58..bd9aced27 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -11,6 +11,7 @@ export default async function createDocument(request, response) { const base64File = request.body.file; const send_email = request.body.send_email || true; const fileData = request.files?.[0] ? request.files[0].buffer : null; + const SendinOrder = request.body.sendInOrder || false; // console.log('fileData ', fileData); const protocol = customAPIurl(); @@ -69,6 +70,9 @@ export default async function createDocument(request, response) { if (description) { object.set('Description', description); } + if (SendinOrder) { + object.set('SendinOrder', SendinOrder); + } object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index 1e835958a..a2b22d90f 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -8,6 +8,7 @@ export default async function createTemplate(request, response) { const signers = request.body?.signers; const folderId = request.body?.folderId; const base64File = request.body.file; + const SendinOrder = request.body.sendInOrder || false; const fileData = request.files?.[0] ? request.files[0].buffer : null; const baseUrl = new URL(process.env.SERVER_URL); @@ -61,6 +62,9 @@ export default async function createTemplate(request, response) { object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); + if (SendinOrder) { + object.set('SendinOrder', SendinOrder); + } if (signers && signers.length > 0) { let parseSigners; if (base64File) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js index 40f0a170c..62cab68da 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplatewithCoordinate.js @@ -10,6 +10,7 @@ export default async function createTemplatewithCoordinate(request, response) { const folderId = request.body.folderId; const base64File = request.body.file; const fileData = request.files?.[0] ? request.files[0].buffer : null; + const SendinOrder = request.body.sendInOrder || false; // console.log('fileData ', fileData); const protocol = customAPIurl(); @@ -63,6 +64,9 @@ export default async function createTemplatewithCoordinate(request, response) { if (description) { object.set('Description', description); } + if (SendinOrder) { + object.set('SendinOrder', SendinOrder); + } object.set('URL', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); diff --git a/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js b/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js index a8c34524d..ed8c54812 100644 --- a/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js +++ b/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js @@ -668,7 +668,8 @@ const TemplatePlaceholder = () => { Signers: signers, Name: pdfDetails[0]?.Name || "", Note: pdfDetails[0]?.Note || "", - Description: pdfDetails[0]?.Description || "" + Description: pdfDetails[0]?.Description || "", + SendinOrder: pdfDetails[0]?.SendinOrder || false }; await axios diff --git a/microfrontends/SignDocuments/src/Component/component/EditTemplate.js b/microfrontends/SignDocuments/src/Component/component/EditTemplate.js index f60091c6d..9290069ad 100644 --- a/microfrontends/SignDocuments/src/Component/component/EditTemplate.js +++ b/microfrontends/SignDocuments/src/Component/component/EditTemplate.js @@ -7,7 +7,8 @@ const EditTemplate = ({ template, onSuccess }) => { const [formData, setFormData] = useState({ Name: template?.Name || "", Note: template?.Note || "", - Description: template?.Description || "" + Description: template?.Description || "", + SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false" }); const handleStrInput = (e) => { @@ -22,7 +23,8 @@ const EditTemplate = ({ template, onSuccess }) => { const handleSubmit = async (e) => { e.preventDefault(); e.stopPropagation(); - const data = {...formData } + const isChecked = formData.SendinOrder === "true" ? true : false; + const data = { ...formData, SendinOrder: isChecked }; onSuccess(data); }; @@ -86,6 +88,45 @@ const EditTemplate = ({ template, onSuccess }) => { className="addUserInput" /> </div> + <div className="form-section"> + <label style={{ fontSize: 13 }}>Send In Order</label> + <div + style={{ + display: "flex", + alignItems: "center", + gap: 8, + marginLeft: 8, + marginBottom: 5 + }} + > + <input + type="radio" + value={"true"} + name="SendinOrder" + checked={formData.SendinOrder === "true"} + onChange={handleStrInput} + /> + <div style={{ fontSize: 12 }}>Yes</div> + </div> + <div + style={{ + display: "flex", + alignItems: "center", + gap: 8, + marginLeft: 8, + marginBottom: 5 + }} + > + <input + type="radio" + value={"false"} + name="SendinOrder" + checked={formData.SendinOrder === "false"} + onChange={handleStrInput} + /> + <div style={{ fontSize: 12 }}>No</div> + </div> + </div> {/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */} <div className="buttoncontainer"> <button type="submit" className="submitbutton"> diff --git a/microfrontends/SignDocuments/src/utils/Utils.js b/microfrontends/SignDocuments/src/utils/Utils.js index bdc28cf40..c409e5088 100644 --- a/microfrontends/SignDocuments/src/utils/Utils.js +++ b/microfrontends/SignDocuments/src/utils/Utils.js @@ -1002,7 +1002,8 @@ export const createDocument = async (template, placeholders, signerData) => { className: "_User", objectId: Doc.CreatedBy.objectId }, - Signers: signers + Signers: signers, + SendinOrder: Doc?.SendinOrder || false }; try { From edda20940bb67ccb8ef5322038a4d8338e363203 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 16 Feb 2024 16:27:20 +0530 Subject: [PATCH 72/73] change title of request signtuares form, change response of document and template response, change subject of mail --- apps/OpenSign/src/json/FormJson.js | 4 +- apps/OpenSign/src/routes/Form.js | 4 +- .../cloud/customRoute/v1/apiV1.js | 4 +- .../v1/routes/CreateDocumentWithTemplate.js | 22 +++--- .../v1/routes/createDocumentwithCoordinate.js | 18 ++--- .../customRoute/v1/routes/createTemplate.js | 2 +- .../{createDocument.js => draftDocument.js} | 2 +- .../customRoute/v1/routes/getDocument.js | 18 +++++ .../customRoute/v1/routes/getDocumentList.js | 72 +++++++++++++------ .../customRoute/v1/routes/getTemplate.js | 20 +++++- .../customRoute/v1/routes/getTemplateList.js | 39 +++++++--- .../files/verification_email_subject.txt | 2 +- 12 files changed, 147 insertions(+), 60 deletions(-) rename apps/OpenSignServer/cloud/customRoute/v1/routes/{createDocument.js => draftDocument.js} (98%) diff --git a/apps/OpenSign/src/json/FormJson.js b/apps/OpenSign/src/json/FormJson.js index 9edef57bf..8e0b4f6a1 100644 --- a/apps/OpenSign/src/json/FormJson.js +++ b/apps/OpenSign/src/json/FormJson.js @@ -8,9 +8,9 @@ export const formJson = { Cls: documentCls }, - //json form for request signature + //json form for request signatures "8mZzFxbG1z": { - title: "Request Signature", + title: "Request Signatures", msgVar: "Document", redirectRoute: "placeHolderSign", Cls: documentCls, diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index 8191b84b4..8eab4b04b 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -157,7 +157,7 @@ const Forms = (props) => { object.set("Name", formData?.Name); object.set("Description", formData?.Description); object.set("Note", formData?.Note); - if (props.title === "Request Signature") { + if (props.title === "Request Signatures") { object.set( "TimeToCompleteDays", parseInt(formData?.TimeToCompleteDays) @@ -352,7 +352,7 @@ const Forms = (props) => { </div> <SelectFolder onSuccess={handleFolder} folderCls={props.Cls} /> - {props.title === "Request Signature" && ( + {props.title === "Request Signatures" && ( <div className="text-xs mt-2"> <label className="block"> Time To Complete (Days) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 7befaec65..343db0d3c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -9,7 +9,7 @@ import getDocument from './routes/getDocument.js'; import getContact from './routes/getContact.js'; import deleteContact from './routes/deleteContact.js'; import getContactList from './routes/getContactList.js'; -import createDocument from './routes/createDocument.js'; +import draftDocument from './routes/draftDocument.js'; import createTemplate from './routes/createTemplate.js'; import getTemplate from './routes/getTemplate.js'; import deletedTemplate from './routes/deleteTemplate.js'; @@ -56,7 +56,7 @@ app.post('/createdocumentwithbinary', upload.array('file', 1), createDocumentwit app.post('/createdocument', createDocumentwithCoordinate); // create Document with base64 without placeholder -app.post('/draftdocument', createDocument); +app.post('/draftdocument', draftDocument); // create Document with templateId app.post('/createdocument/:template_id', createDocumentWithTemplate); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index ebb0dbbe6..6ef70f07a 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -201,10 +201,12 @@ export default async function createDocumentWithTemplate(request, response) { if (send_email === false) { console.log("don't send mail"); } else { - for (let i = 0; i < contact.length; i++) { - if (sendInOrder) { - contact.splice(1); - } + let contactMail = contact; + if (sendInOrder) { + contactMail = contact.slice(); + contactMail.splice(1); + } + for (let i = 0; i < contactMail.length; i++) { try { const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; @@ -214,10 +216,10 @@ export default async function createDocumentWithTemplate(request, response) { 'X-Parse-Master-Key': process.env.MASTER_KEY, }; - const objectId = contact[i].contactPtr.objectId; + const objectId = contactMail[i].contactPtr.objectId; const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; - let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; + let signPdf = `${hostUrl}/login/${res.id}/${contactMail[i].email}/${objectId}/${serverParams}`; const openSignUrl = 'https://www.opensignlabs.com/contact-us'; const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : ''; const themeBGcolor = '#47a3ad'; @@ -250,9 +252,9 @@ export default async function createDocumentWithTemplate(request, response) { sender_name: template.ExtUserPtr.Name, sender_mail: template.ExtUserPtr.Email, sender_phone: template.ExtUserPtr.Phone, - receiver_name: contact[i].name, - receiver_email: contact[i].email, - receiver_phone: contact[i].phone, + receiver_name: contactMail[i].name, + receiver_email: contactMail[i].email, + receiver_phone: contactMail[i].phone, expiry_date: localExpireDate, company_name: orgName, signing_url: signPdf, @@ -278,7 +280,7 @@ export default async function createDocumentWithTemplate(request, response) { const subject = replaceVar.subject; const html = replaceVar.body; let params = { - recipient: contact[i].email, + recipient: contactMail[i].email, subject: subject, from: sender, html: html, diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index 5b04e2a3b..0ca92d067 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -252,10 +252,12 @@ export default async function createDocumentwithCoordinate(request, response) { if (send_email === false) { console.log("don't send mail"); } else { + let contactMail = contact; if (sendInOrder) { - contact.splice(1); + contactMail = contact.slice(); + contactMail.splice(1); } - for (let i = 0; i < contact.length; i++) { + for (let i = 0; i < contactMail.length; i++) { try { const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; @@ -265,10 +267,10 @@ export default async function createDocumentwithCoordinate(request, response) { 'X-Parse-Master-Key': process.env.MASTER_KEY, }; - const objectId = contact[i].contactPtr.objectId; + const objectId = contactMail[i].contactPtr.objectId; const hostUrl = baseUrl.origin + '/loadmf/signmicroapp'; - let signPdf = `${hostUrl}/login/${res.id}/${contact[i].email}/${objectId}/${serverParams}`; + let signPdf = `${hostUrl}/login/${res.id}/${contactMail[i].email}/${objectId}/${serverParams}`; const openSignUrl = 'https://www.opensignlabs.com/contact-us'; const orgName = parseExtUser.Company ? parseExtUser.Company : ''; const themeBGcolor = '#47a3ad'; @@ -300,9 +302,9 @@ export default async function createDocumentwithCoordinate(request, response) { sender_name: parseExtUser.Name, sender_mail: parseExtUser.Email, sender_phone: parseExtUser.Phone, - receiver_name: contact[i].name, - receiver_email: contact[i].email, - receiver_phone: contact[i].phone, + receiver_name: contactMail[i].name, + receiver_email: contactMail[i].email, + receiver_phone: contactMail[i].phone, expiry_date: localExpireDate, company_name: orgName, signing_url: signPdf, @@ -328,7 +330,7 @@ export default async function createDocumentwithCoordinate(request, response) { const html = replaceVar.body; let params = { - recipient: contact[i].email, + recipient: contactMail[i].email, subject: subject, from: sender, html: html, diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js index a2b22d90f..df8b6eacd 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -123,7 +123,7 @@ export default async function createTemplate(request, response) { } return response.json({ objectId: res.id, - url: baseUrl.p + '/load/signmicroapp/template/' + res.id, + url: baseUrl.origin + '/load/signmicroapp/template/' + res.id, }); } else { return response.status(405).json({ error: 'Invalid API Token!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/draftDocument.js similarity index 98% rename from apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js rename to apps/OpenSignServer/cloud/customRoute/v1/routes/draftDocument.js index bd9aced27..a2ba41d3c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/draftDocument.js @@ -2,7 +2,7 @@ import axios from 'axios'; import { customAPIurl } from '../../../../Utils.js'; // const randomId = () => Math.floor(1000 + Math.random() * 9000); -export default async function createDocument(request, response) { +export default async function draftDocument(request, response) { const name = request.body.title; const note = request.body.note; const description = request.body.description; diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index c02a3a93f..cc1e1e03c 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -23,6 +23,7 @@ export default async function getDocument(request, response) { Document.include('Signers'); Document.include('Folder'); Document.include('ExtUserPtr'); + Document.include('Placeholders.signerPtr'); const res = await Document.first({ useMasterKey: true }); if (res) { const document = JSON.parse(JSON.stringify(res)); @@ -41,8 +42,25 @@ export default async function getDocument(request, response) { file: document?.SignedUrl || document.URL, owner: document?.ExtUserPtr?.Name, signers: + document?.Placeholders?.map(y => ({ + role: y.Role, + name: y?.signerPtr?.Name || '', + email: y?.signerPtr?.Email || '', + phone: y?.signerPtr?.Phone || '', + widgets: y.placeHolder?.flatMap(x => + x?.pos.map(w => ({ + type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', + x: w.xPosition, + y: w.yPosition, + w: w?.Width || 150, + h: w?.Height || 60, + page: x?.pageNumber, + })) + ), + })) || document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], + sendInOrder: document?.SendinOrder || false, createdAt: document.createdAt, updatedAt: document.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index bab8fcc66..1f76b3853 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -61,38 +61,70 @@ export default async function getDocumentList(request, response) { 'X-Parse-Application-Id': appId, 'X-Parse-Master-Key': process.env.MASTER_KEY, }; - const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; - const res = await axios.get(url, { headers: headers }); - if (res.data && res.data.results.length > 0) { + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys},Placeholders&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr`; + try { + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results.length > 0) { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_get_document_list_by_status', + properties: { response_code: 200, doc_type: docType }, + }); + } + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + title: x.Name, + note: x.Note || '', + folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: + x?.Placeholders?.map(y => ({ + role: y.Role, + name: y?.signerPtr?.Name || '', + email: y?.signerPtr?.Email || '', + phone: y?.signerPtr?.Phone || '', + widgets: y.placeHolder?.flatMap(x => + x?.pos.map(w => ({ + type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', + x: w.xPosition, + y: w.yPosition, + w: w?.Width || 150, + h: w?.Height || 60, + page: x?.pageNumber, + })) + ), + })) || + x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || + [], + sendInOrder: x?.SendinOrder || false, + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); + return response.json({ result: updateRes }); + } else { + return response.json({ result: [] }); + } + } catch (err) { + console.log('err in getdocument list', err); if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, event: 'api_get_document_list_by_status', - properties: { response_code: 200 }, + properties: { response_code: 400, doc_type: docType }, }); } - const updateRes = res.data.results.map(x => ({ - objectId: x.objectId, - title: x.Name, - note: x.Note || '', - folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', - file: x?.SignedUrl || x.URL, - owner: x?.ExtUserPtr?.Name, - signers: - x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], - createdAt: x.createdAt, - updatedAt: x.updatedAt, - })); - return response.json({ result: updateRes }); - } else { - return response.json({ result: [] }); + return response + .status(400) + .json({ error: 'Something went wrong, please try again later!' }); } } else { if (request.posthog) { request.posthog?.capture({ distinctId: parseUser.userId.email, event: 'api_get_document_list_by_status', - properties: { response_code: 404 }, + properties: { response_code: 404, doc_type: docType }, }); } return response.status(404).json({ error: 'Report not available!' }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js index 4b9079a9c..7b3daa28d 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -24,6 +24,7 @@ export default async function getTemplate(request, response) { Template.include('Signers'); Template.include('Folder'); Template.include('ExtUserPtr'); + Template.include('Placeholders.signerPtr'); const res = await Template.first({ useMasterKey: true }); if (res) { const template = JSON.parse(JSON.stringify(res)); @@ -43,8 +44,23 @@ export default async function getTemplate(request, response) { file: template?.SignedUrl || template?.URL, owner: template?.ExtUserPtr?.Name, signers: - template?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || - [], + template?.Placeholders?.map(y => ({ + role: y.Role, + name: y?.signerPtr?.Name || '', + email: y?.signerPtr?.Email || '', + phone: y?.signerPtr?.Phone || '', + widgets: y.placeHolder?.flatMap(x => + x?.pos.map(w => ({ + type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', + x: w.xPosition, + y: w.yPosition, + w: w?.Width || 150, + h: w?.Height || 60, + page: x?.pageNumber, + })) + ), + })) || [], + sendInOrder: template?.SendinOrder || false, createdAt: template.createdAt, updatedAt: template.updatedAt, }); diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js index b47a9101a..fb1e1ae74 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -42,6 +42,7 @@ export default async function getTemplatetList(request, response) { 'Signers.Name', 'Signers.Email', 'Signers.Phone', + 'Placeholders', ]; const orderBy = '-updatedAt'; const strParams = JSON.stringify(params); @@ -51,7 +52,7 @@ export default async function getTemplatetList(request, response) { 'X-Parse-Application-Id': appId, 'X-Parse-Master-Key': process.env.MASTER_KEY, }; - const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr`; const res = await axios.get(url, { headers: headers }); if (res.data && res.data.results.length > 0) { if (request.posthog) { @@ -61,17 +62,33 @@ export default async function getTemplatetList(request, response) { properties: { response_code: 200 }, }); } - const updateRes = res.data.results.map(x => ({ - objectId: x.objectId, - title: x.Name, - note: x.Note || '', - folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', - file: x?.SignedUrl || x.URL, - owner: x?.ExtUserPtr?.Name, + const updateRes = res.data.results.map(template => ({ + objectId: template.objectId, + title: template.Name, + note: template.Note || '', + folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '', + file: template?.SignedUrl || template.URL, + owner: template?.ExtUserPtr?.Name, signers: - x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || [], - createdAt: x.createdAt, - updatedAt: x.updatedAt, + template?.Placeholders?.map(y => ({ + role: y.Role, + name: y?.signerPtr?.Name || '', + email: y?.signerPtr?.Email || '', + phone: y?.signerPtr?.Phone || '', + widgets: y.placeHolder?.flatMap(x => + x?.pos.map(w => ({ + type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature', + x: w.xPosition, + y: w.yPosition, + w: w?.Width || 150, + h: w?.Height || 60, + page: x?.pageNumber, + })) + ), + })) || [], + sendInOrder: template?.SendinOrder || false, + createdAt: template.createdAt, + updatedAt: template.updatedAt, })); return response.json({ result: updateRes }); diff --git a/apps/OpenSignServer/files/verification_email_subject.txt b/apps/OpenSignServer/files/verification_email_subject.txt index 07ca5a6ef..0f8684f2f 100644 --- a/apps/OpenSignServer/files/verification_email_subject.txt +++ b/apps/OpenSignServer/files/verification_email_subject.txt @@ -1 +1 @@ -Email Address Verification \ No newline at end of file +OpenSign™ Email Address Verification \ No newline at end of file From ff4879a9845e624e25dd00f965f7ab9ca4a9889a Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Fri, 16 Feb 2024 19:54:39 +0530 Subject: [PATCH 73/73] fix: change doctype in get document list API --- .../cloud/customRoute/v1/routes/getDocumentList.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 1f76b3853..011ef7807 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -28,22 +28,22 @@ export default async function getDocumentList(request, response) { const skip = request?.query?.skip ? request.query.skip : 0; let reportId; switch (docType) { - case 'draftdocuments': + case 'draft': reportId = 'ByHuevtCFY'; break; case 'signaturerequest': reportId = '4Hhwbp482K'; break; - case 'inprogressdocuments': + case 'inprogress': reportId = '1MwEuxLEkF'; break; - case 'completedocuments': + case 'completed': reportId = 'kQUoW4hUXz'; break; - case 'expiredocuments': + case 'expired': reportId = 'zNqBHXHsYH'; break; - case 'declinedocuments': + case 'declined': reportId = 'UPr2Fm5WY3'; break; default: