diff --git a/.all-contributorsrc b/.all-contributorsrc index aebf49231..c6fe8646b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -196,6 +196,15 @@ "contributions": [ "code" ] + }, + { + "login": "VikramNagwal", + "name": "Vikram", + "avatar_url": "https://avatars.githubusercontent.com/u/123088024?v=4", + "profile": "https://github.com/VikramNagwal", + "contributions": [ + "code" + ] } ] } diff --git a/.env.local_dev b/.env.local_dev index a04faba14..2303bf980 100644 --- a/.env.local_dev +++ b/.env.local_dev @@ -45,14 +45,14 @@ DO_REGION=us-west USE_LOCAL=TRUE # Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) ********************************************************************************************************************* -MAILGUN_API_KEY=XXXXX +MAILGUN_API_KEY= MAILGUN_DOMAIN=mail.yourdomain.com MAILGUN_SENDER=postmaster@mail.yourdomain.com SMTP_ENABLE= -SMTP_HOST= -SMTP_PORT= -SMTP_USER_EMAIL= -SMTP_PASS= +SMTP_HOST=smtp.yourhost.com +SMTP_PORT=443 +SMTP_USER_EMAIL=mailer@yourdomain.com +SMTP_PASS=password # Base64 encoded PFX or p12 document signing certificate file ********************************************************************************************************************* diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..7983b7ed8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + # maintain dependencies for frontend + - package-ecosystem: "npm" # See documentation for possible values + directory: "/apps/OpenSign" # Location of package manifests + schedule: + interval: "weekly" + # maintain dependencies for server + - package-ecosystem: "npm" # See documentation for possible values + directory: "/apps/OpenSignServer" # Location of package manifests + schedule: + interval: "weekly" + # maintain dependencies for microfrontends + - package-ecosystem: "npm" # See documentation for possible values + directory: "microfrontends/SignDocuments" # Location of package manifests + schedule: + interval: "weekly" diff --git a/README.md b/README.md index 510848dd2..9c5d5b378 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,9 @@ We would like to thank all our contributors and users for their support and feed Govinda Kocharekar
Govinda Kocharekar

💻 Bilal Ahmad Bhat
Bilal Ahmad Bhat

💻 + + Vikram
Vikram

💻 + diff --git a/apps/OpenSign/public/index.html b/apps/OpenSign/public/index.html index 83788c7ff..c12d8c701 100644 --- a/apps/OpenSign/public/index.html +++ b/apps/OpenSign/public/index.html @@ -31,7 +31,7 @@ - Open sign + OpenSign™ @@ -50,4 +50,4 @@ --> - \ No newline at end of file + diff --git a/apps/OpenSign/public/version.txt b/apps/OpenSign/public/version.txt index 3e82ea442..e69de29bb 100644 --- a/apps/OpenSign/public/version.txt +++ b/apps/OpenSign/public/version.txt @@ -1 +0,0 @@ -v1.0.5-beta diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index b14bfb284..3e0119d85 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -16,6 +16,7 @@ import ChangePassword from "./routes/ChangePassword"; import ReportMicroapp from "./components/ReportMicroapp"; import LoadMf from "./routes/LoadMf"; import GenerateToken from "./routes/GenerateToken"; +import ValidateRoute from "./primitives/ValidateRoute"; function App() { const [isloading, setIsLoading] = useState(true); @@ -59,8 +60,24 @@ function App() { ) : ( - } /> - } /> + + + + } + /> + + + + } + /> } /> } /> {process.env.REACT_APP_ENABLE_SUBSCRIPTION && ( diff --git a/apps/OpenSign/src/components/AppendFormInForm.js b/apps/OpenSign/src/components/AppendFormInForm.js index 2d61d4597..47679d033 100644 --- a/apps/OpenSign/src/components/AppendFormInForm.js +++ b/apps/OpenSign/src/components/AppendFormInForm.js @@ -32,6 +32,7 @@ const AppendFormInForm = (props) => { try { const query = new Parse.Query("contracts_Contactbook"); query.equalTo("CreatedBy", user); + query.notEqualTo("IsDeleted", true); query.equalTo("Email", user.getEmail()); const res = await query.first(); // console.log(res); @@ -45,6 +46,7 @@ const AppendFormInForm = (props) => { // Define a function to handle form submission const handleSubmit = async (e) => { e.preventDefault(); + e.stopPropagation(); setIsLoader(true); Parse.serverURL = parseBaseUrl; Parse.initialize(parseAppId); @@ -104,13 +106,18 @@ const AppendFormInForm = (props) => { const res = await contactQuery.save(); const parseData = JSON.parse(JSON.stringify(res)); - props.details({ - value: parseData[props.valueKey], - label: parseData[props.displayKey] - }); + 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); // Reset the form fields @@ -157,13 +164,18 @@ const AppendFormInForm = (props) => { const res = await contactQuery.save(); const parseData = JSON.parse(JSON.stringify(res)); - props.details({ - value: parseData[props.valueKey], - label: parseData[props.displayKey] - }); + 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); // Reset the form fields setAddYourself(false); diff --git a/apps/OpenSign/src/components/LoginFacebook.js b/apps/OpenSign/src/components/LoginFacebook.js index 1dd0297a4..033208d57 100644 --- a/apps/OpenSign/src/components/LoginFacebook.js +++ b/apps/OpenSign/src/components/LoginFacebook.js @@ -86,7 +86,7 @@ const LoginFacebook = ({ email: userDetails.Email, // "passsword":userDetails.Phone, phone: userDetails.Phone, - role: "contracts_Admin", + role: "contracts_User", company: userDetails.Company } }; diff --git a/apps/OpenSign/src/components/LoginGoogle.js b/apps/OpenSign/src/components/LoginGoogle.js index e0b3ed6c1..a95f903bf 100644 --- a/apps/OpenSign/src/components/LoginGoogle.js +++ b/apps/OpenSign/src/components/LoginGoogle.js @@ -148,7 +148,7 @@ const GoogleSignInBtn = ({ email: userDetails.Email, // "passsword":userDetails.Phone, phone: userDetails.Phone, - role: "contracts_Admin", + role: "contracts_User", company: userDetails.Company, jobTitle: userDetails.Destination } diff --git a/apps/OpenSign/src/components/TreeWidget.js b/apps/OpenSign/src/components/TreeWidget.js index b028ffb62..569112d71 100644 --- a/apps/OpenSign/src/components/TreeWidget.js +++ b/apps/OpenSign/src/components/TreeWidget.js @@ -5,7 +5,7 @@ import Parse from "parse"; import axios from "axios"; import "../styles/spinner.css"; import TreeFormComponent from "./TreeFormComponent"; -import TreeEditForm from "./TreeEditForm"; +// import TreeEditForm from "./TreeEditForm"; import "../styles/modal.css"; import Modal from "react-modal"; @@ -22,7 +22,7 @@ const TreeWidget = (props) => { const [schemaState, setSchemaState] = useState({}); const [TabURL, setTabURL] = useState(""); const [editable, setEditable] = useState(false); - const [editId, setEditId] = useState(""); + // const [editId, setEditId] = useState(""); const [defaultState, setDefaultState] = useState(false); const [isShowModal, setIsShowModal] = useState(false); const selectFolderHandle = async () => { @@ -472,6 +472,8 @@ const TreeWidget = (props) => { 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, { @@ -698,7 +700,7 @@ const TreeWidget = (props) => { ))}
- {editable && ( + {/* {editable && ( { selectFolderHandle(); }} /> - )} + )} */} {isAddField && !loader && !editable && ( { - {fldr[props.schema.data.FolderTypeField] === + {/* {fldr[props.schema.data.FolderTypeField] === props.schema.data.FolderTypeValue && ( { aria-hidden="true" > - )} + )} */} ) )} diff --git a/apps/OpenSign/src/components/fields/CreateFolder.js b/apps/OpenSign/src/components/fields/CreateFolder.js new file mode 100644 index 000000000..7c13e6145 --- /dev/null +++ b/apps/OpenSign/src/components/fields/CreateFolder.js @@ -0,0 +1,147 @@ +import React, { useEffect, useState } from "react"; +import Parse from "parse"; +import Alert from "../../primitives/Alert"; + +const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => { + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: parentFolderId + }; + const [name, setName] = useState(""); + const [folderList, setFolderList] = useState([]); + const [isAlert, setIsAlert] = useState(false); + const [selectedParent, setSelectedParent] = useState(); + const [alert, setAlert] = useState({ type: "info", message: "" }); + useEffect(() => { + fetchFolder(); + // eslint-disable-next-line + }, []); + + const fetchFolder = async () => { + try { + const FolderQuery = new Parse.Query(folderCls); + if (parentFolderId) { + FolderQuery.equalTo("Folder", folderPtr); + FolderQuery.equalTo("Type", "Folder"); + } else { + FolderQuery.doesNotExist("Folder"); + FolderQuery.equalTo("Type", "Folder"); + } + + const res = await FolderQuery.find(); + if (res) { + const result = JSON.parse(JSON.stringify(res)); + if (result) { + setFolderList(result); + } + } + } catch (error) { + console.log("Err ", error); + } + }; + const handleCreateFolder = async (event) => { + event.preventDefault(); + if (name) { + const currentUser = Parse.User.current(); + const exsitQuery = new Parse.Query(folderCls); + exsitQuery.equalTo("Name", name); + exsitQuery.equalTo("Type", "Folder"); + if (parentFolderId) { + exsitQuery.equalTo("Folder", folderPtr); + } + const templExist = await exsitQuery.first(); + if (templExist) { + setAlert({ type: "dange", message: "Folder already exist!" }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + } else { + const template = new Parse.Object(folderCls); + template.set("Name", name); + template.set("Type", "Folder"); + + if (selectedParent) { + template.set("Folder", { + __type: "Pointer", + className: folderCls, + objectId: selectedParent + }); + } else if (parentFolderId) { + template.set("Folder", folderPtr); + } + template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); + const res = await template.save(); + if (res) { + setAlert({ + type: "success", + message: "Folder created successfully!" + }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + if (onSuccess) { + onSuccess(res); + } + } + } + } else { + setAlert({ type: "info", message: "Please fill folder name" }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + } + }; + const handleOptions = (e) => { + setSelectedParent(e.target.value); + }; + return ( +
+ {isAlert && {alert.message}} +
+

Create Folder

+
+ + setName(e.target.value)} + required + /> +
+
+ + +
+
+ +
+
+
+ ); +}; + +export default CreateFolder; diff --git a/apps/OpenSign/src/components/fields/DropboxChoose.js b/apps/OpenSign/src/components/fields/DropboxChoose.js new file mode 100644 index 000000000..a97e2e20f --- /dev/null +++ b/apps/OpenSign/src/components/fields/DropboxChoose.js @@ -0,0 +1,60 @@ +import React, { useCallback, useMemo } from "react"; +import { useDropScript } from "../../hook/useScript"; + +const DROPBOX_APP_KEY = process.env.REACT_APP_DROPBOX_API_KEY; // App key +const DROPBOX_SDK_URL = "https://www.dropbox.com/static/api/2/dropins.js"; +const DROPBOX_SCRIPT_ID = "dropboxjs"; + +export default function DropboxChooser({ children, onSuccess, onCancel }) { + useDropScript(DROPBOX_SDK_URL, { + attrs: { + id: DROPBOX_SCRIPT_ID, + "data-app-key": DROPBOX_APP_KEY + } + }); + + const options = useMemo( + () => ({ + // Required. Called when a user selects an item in the Chooser. + success: (files) => { + // console.log("success", files); + onSuccess && onSuccess(files); + }, + // Optional. Called when the user closes the dialog without selecting a file + // and does not include any parameters. + cancel: () => { + console.log("cancel"); + onCancel && onCancel(); + }, + + // Optional. "preview" (default) is a preview link to the document for sharing, + // "direct" is an expiring link to download the contents of the file. For more + linkType: "direct", // or "preview" + multiselect: false, // 是否支持多选 + extensions: [".pdf"], + + // Optional. A value of false (default) limits selection to files, + // while true allows the user to select both folders and files. + // You cannot specify `linkType: "direct"` when using `folderselect: true`. + folderselect: false // or true + }), + [onSuccess, onCancel] + ); + + const handleChoose = useCallback((e) => { + e.preventDefault() + if (window.Dropbox) { + window.Dropbox.choose(options); + } + }, [options]); + + return ( +
+ {children || ( + + )} +
+ ); +} diff --git a/apps/OpenSign/src/components/fields/FileUpload.js b/apps/OpenSign/src/components/fields/FileUpload.js index 226640d44..e6c632a02 100644 --- a/apps/OpenSign/src/components/fields/FileUpload.js +++ b/apps/OpenSign/src/components/fields/FileUpload.js @@ -2,14 +2,12 @@ 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 [localValue, setLocalValue] = useState(""); const [Message] = useState(false); const [percentage, setpercentage] = useState(0); @@ -25,7 +23,6 @@ const FileUpload = (props) => { const onChange = (e) => { try { let files = e.target.files; - setLocalValue(e.target.files); if (typeof files[0] !== "undefined") { if (props.schema.filetypes && props.schema.filetypes.length > 0) { var fileName = files[0].name; @@ -106,6 +103,56 @@ const FileUpload = (props) => { 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 && @@ -207,55 +254,55 @@ const FileUpload = (props) => { <> - {localValue ? ( - - ) : props.formData ? ( -
- file selected : {props.formData.split("/")[3]} + {props.formData ? ( +
+
+
+ file selected : {props.formData?.split("/")[3]?.split("_")[1]} +
+
{ + console.log("clicked"); + setFileUpload([]); + props.onChange(undefined); + }} + className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500" + > + +
+
+ {process.env.REACT_APP_DROPBOX_API_KEY && ( + + )}
) : ( - +
+ + {process.env.REACT_APP_DROPBOX_API_KEY && ( + + )} +
)} diff --git a/apps/OpenSign/src/components/fields/SelectFolder.js b/apps/OpenSign/src/components/fields/SelectFolder.js new file mode 100644 index 000000000..38694b740 --- /dev/null +++ b/apps/OpenSign/src/components/fields/SelectFolder.js @@ -0,0 +1,261 @@ +import React, { useEffect, useState } from "react"; +import Parse from "parse"; +import CreateFolder from "./CreateFolder"; +import ModalUi from "../../primitives/ModalUi"; + +const SelectFolder = ({ required, onSuccess, folderCls }) => { + const [isOpen, SetIsOpen] = useState(false); + const [clickFolder, setClickFolder] = useState(""); + const [selectFolder, setSelectedFolder] = useState({}); + const [folderList, setFolderList] = useState([]); + const [tabList, setTabList] = useState([]); + const [isLoader, setIsLoader] = useState(false); + const [folderPath, setFolderPath] = useState(""); + const [isAdd, setIsAdd] = useState(false); + useEffect(() => { + if (isOpen) { + setIsAdd(false); + setClickFolder({}); + setFolderList([]); + setTabList([]); + fetchFolder(); + } + // eslint-disable-next-line + }, [isOpen]); + const fetchFolder = async (folderPtr) => { + setIsLoader(true); + try { + const FolderQuery = new Parse.Query(folderCls); + if (folderPtr) { + FolderQuery.equalTo("Folder", folderPtr); + FolderQuery.equalTo("Type", "Folder"); + } else { + FolderQuery.doesNotExist("Folder"); + FolderQuery.equalTo("Type", "Folder"); + } + + const res = await FolderQuery.find(); + if (res) { + const result = JSON.parse(JSON.stringify(res)); + if (result) { + setFolderList(result); + setIsLoader(false); + } + setIsLoader(false); + } + } catch (error) { + setIsLoader(false); + } + }; + const handleSelect = (item) => { + setFolderList([]); + setClickFolder({ ObjectId: item.objectId, Name: item.Name }); + if (tabList.length > 0) { + const tab = tabList.some((x) => x.objectId === item.objectId); + if (!tab) { + setTabList((tabs) => [...tabs, item]); + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: item.objectId + }; + fetchFolder(folderPtr); + } + } else { + setTabList((tabs) => [...tabs, item]); + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: item.objectId + }; + + fetchFolder(folderPtr); + } + }; + + const handleSubmit = () => { + let url = "Root"; + tabList.forEach((t) => { + url = url + " / " + t.Name; + }); + setFolderPath(url); + setSelectedFolder(clickFolder); + if (onSuccess) { + onSuccess(clickFolder); + } + SetIsOpen(false); + }; + const handleCancel = () => { + SetIsOpen(false); + setClickFolder({}); + setFolderList([]); + setTabList([]); + }; + + const removeTabListItem = async (e, i) => { + e.preventDefault(); + // setEditable(false); + if (!isAdd) { + setIsLoader(true); + let folderPtr; + if (i) { + setFolderList([]); + let list = tabList.filter((itm, j) => { + if (j <= i) { + return itm; + } + }); + let _len = list.length - 1; + folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: list[_len].objectId + }; + setTabList(list); + } else { + setClickFolder({}); + setSelectedFolder({}); + setFolderList([]); + setTabList([]); + } + fetchFolder(folderPtr); + } + }; + const handleCreate = () => { + setIsAdd(!isAdd); + }; + const handleAddFolder = () => { + setFolderList([]); + if (clickFolder && clickFolder.ObjectId) { + fetchFolder({ + __type: "Pointer", + className: folderCls, + objectId: clickFolder.ObjectId + }); + } else { + fetchFolder(); + } + handleCreate(); + }; + return ( +
+
+ +
+
+
+ +
+
+
+

+ {selectFolder && selectFolder.Name ? selectFolder.Name : "Root"} +

+
SetIsOpen(true)}> + +
+
+

+ {selectFolder && selectFolder.Name ? `(${folderPath})` : ""} +

+
+
+ +
+
+ removeTabListItem(e)} + > + Root /{" "} + + {tabList && + tabList.map((tab, i) => ( + + removeTabListItem(e, i)} + > + {tab.Name} + + {" / "} + + ))} +
+
+
+ {!isAdd && + folderList.length > 0 && + folderList.map((folder) => ( +
handleSelect(folder)} + > +
+ + {folder.Name} +
+
+ ))} + {isAdd && ( + + )} + {isLoader && ( +
+ +
+ )} +
+
+
+
+
+ {isAdd ? ( + + ) : ( + + )} +
+
+ +
+
+
+
+ ); +}; + +export default SelectFolder; diff --git a/apps/OpenSign/src/components/fields/SignersInput.js b/apps/OpenSign/src/components/fields/SignersInput.js new file mode 100644 index 000000000..0e9697965 --- /dev/null +++ b/apps/OpenSign/src/components/fields/SignersInput.js @@ -0,0 +1,190 @@ +import React, { useState, useEffect } from "react"; +import Select from "react-select"; +import AppendFormInForm from "../AppendFormInForm"; +import Modal from "react-modal"; +import Parse from "parse"; +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 SignersInput = (props) => { + Modal.setAppElement("body"); + 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); + }; + + const GetSelectListData = async () => { + try { + const currentUser = Parse.User.current(); + const contactbook = new Parse.Query("contracts_Contactbook"); + contactbook.equalTo( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + contactbook.notEqualTo("IsDeleted", true); + const contactRes = await contactbook.find(); + if (contactRes) { + const res = JSON.parse(JSON.stringify(contactRes)); + let list = []; + + // let _selected = []; + res.forEach((x) => { + let obj = { + label: x.Name, + value: x.objectId, + isChecked: true + }; + + list.push(obj); + }); + setState(list); + } + } catch (error) { + console.log("err", error); + } + }; + + useEffect(() => { + GetSelectListData(); + }, []); + + useEffect(() => { + if (selected && selected.length) { + let newData = []; + selected.forEach((x) => { + newData.push(x.value); + }); + if (props.onChange) { + props.onChange(newData); + } + } + + // eslint-disable-next-line + }, [selected]); + + 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([...state, data]); + if (selected.length > 0) { + setSelected([...selected, data]); + } else { + setSelected([data]); + } + }; + + return ( +
+ +
+
+ handleFileInput(e)} + accept="application/pdf,application/vnd.ms-excel" + required + /> + {process.env.REACT_APP_DROPBOX_API_KEY && ( + + )} +
+ )} +
+
+ + handleStrInput(e)} + required + /> +
+
+ + handleStrInput(e)} + required + /> +
+
+ + handleStrInput(e)} + /> +
+ {/* */} + +
+ +
handleReset()} + > + Reset +
+
+ +
+ ); +}; + +export default TemplateForm; diff --git a/apps/OpenSign/src/primitives/ValidateRoute.js b/apps/OpenSign/src/primitives/ValidateRoute.js new file mode 100644 index 000000000..62202dfe6 --- /dev/null +++ b/apps/OpenSign/src/primitives/ValidateRoute.js @@ -0,0 +1,34 @@ +import React, { useEffect } from "react"; +import Parse from "parse"; + +const ValidateRoute = ({ children }) => { + 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) { + handlelogout(); + } + } catch (error) { + handlelogout(); + } + })(); + }, []); + const handlelogout = async () => { + try { + Parse.User.logOut(); + localStorage.removeItem("accesstoken"); + } catch (err) { + console.log("err ", err); + } finally { + localStorage.removeItem("accesstoken"); + } + }; + return
{children}
; +}; + +export default ValidateRoute; diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index fd5c67449..2c6c67709 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -25,6 +25,7 @@ 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 }; @@ -41,15 +42,19 @@ const fields = () => { function FormBuilderFn(props) { const { id } = useParams(); const navigate = useNavigate(); - return ( - - ); + if (id === "template") { + return ; + } else { + return ( + + ); + } } class FormBuilder extends Component { state = { diff --git a/apps/OpenSign/src/routes/Pgsignup.js b/apps/OpenSign/src/routes/Pgsignup.js index 5a48be5f8..af4cc0108 100644 --- a/apps/OpenSign/src/routes/Pgsignup.js +++ b/apps/OpenSign/src/routes/Pgsignup.js @@ -74,8 +74,8 @@ const PgSignUp = (props) => { const res = await Parse.Cloud.run("getUserDetails", params); // console.log("res", res); if (res) { - const checkUser = new Parse.Query(extClass); - const updateQuery = await checkUser.get(res.id); + const updateQuery = new Parse.Object(extClass); + updateQuery.id = res.id; updateQuery.set( "Next_billing_date", new Date(zohoRes.data.result.nextBillingDate) diff --git a/apps/OpenSign/src/routes/PlanSubscriptions.js b/apps/OpenSign/src/routes/PlanSubscriptions.js index 6a3851f1f..00ad2fa62 100644 --- a/apps/OpenSign/src/routes/PlanSubscriptions.js +++ b/apps/OpenSign/src/routes/PlanSubscriptions.js @@ -136,8 +136,13 @@ const PlanSubscriptions = () => {

{item.subtitle}

+ diff --git a/apps/OpenSign/src/routes/Report.js b/apps/OpenSign/src/routes/Report.js index 88e80417f..af3273095 100644 --- a/apps/OpenSign/src/routes/Report.js +++ b/apps/OpenSign/src/routes/Report.js @@ -15,6 +15,7 @@ const Report = () => { const [heading, setHeading] = useState([]); const [isNextRecord, setIsNextRecord] = useState(false); const [isMoreDocs, setIsMoreDocs] = useState(true); + const [form, setForm]= useState("") const abortController = new AbortController(); const docPerPage = 10; @@ -50,6 +51,7 @@ const Report = () => { setActions(json.actions); setHeading(json.heading); setReportName(json.reportName); + setForm(json.form) Parse.serverURL = localStorage.getItem("BaseUrl12"); Parse.initialize(localStorage.getItem("AppID12")); const currentUser = Parse.User.current().id; @@ -154,6 +156,7 @@ const Report = () => { setIsNextRecord={setIsNextRecord} isMoreDocs={isMoreDocs} docPerPage={docPerPage} + form={form} /> ) : (
diff --git a/apps/OpenSign/src/routes/UserProfile.js b/apps/OpenSign/src/routes/UserProfile.js index 5dc747329..5a2120375 100644 --- a/apps/OpenSign/src/routes/UserProfile.js +++ b/apps/OpenSign/src/routes/UserProfile.js @@ -158,124 +158,126 @@ function UserProfile() { >
) : ( -
-
-
- dp -
- {editmode && ( - { - let files = e.target.files; - fileUpload(files[0]); - }} - /> - )} - {percentage !== 0 && ( -
-
-
-
- {percentage}% +
+
+
+
+ dp +
+ {editmode && ( + { + let files = e.target.files; + fileUpload(files[0]); + }} + /> + )} + {percentage !== 0 && ( +
+
+
+
+ {percentage}% +
+ )} +
+ {localStorage.getItem("_user_role")}
- )} -
- {localStorage.getItem("_user_role")}
-
-
    -
  • - Name:{" "} - {editmode ? ( - SetName(e.target.value)} - /> - ) : ( - {localStorage.getItem("username")} - )} -
  • -
  • - Phone:{" "} - {editmode ? ( - SetPhone(e.target.value)} - value={Phone} - /> - ) : ( - {UserProfile && UserProfile.phone} - )} -
  • -
  • - Email:{" "} - {UserProfile && UserProfile.email} -
  • -
  • - Is Email verified:{" "} - - {UserProfile && UserProfile.emailVerified - ? "Verified" - : "Not verified"} - -
  • -
-
- {editmode ? ( - - ) : ( + Name:{" "} + {editmode ? ( + SetName(e.target.value)} + /> + ) : ( + {localStorage.getItem("username")} + )} + +
  • + Phone:{" "} + {editmode ? ( + SetPhone(e.target.value)} + value={Phone} + /> + ) : ( + {UserProfile && UserProfile.phone} + )} +
  • +
  • + Email:{" "} + {UserProfile && UserProfile.email} +
  • +
  • + Is Email verified:{" "} + + {UserProfile && UserProfile.emailVerified + ? "Verified" + : "Not verified"} + +
  • + +
    + {editmode ? ( + + ) : ( + + )} - )} - +
    )} diff --git a/apps/OpenSign/src/styles/loader.css b/apps/OpenSign/src/styles/loader.css index a401728ee..e6e1624f8 100644 --- a/apps/OpenSign/src/styles/loader.css +++ b/apps/OpenSign/src/styles/loader.css @@ -2211,7 +2211,5 @@ background-position: -2em 0; } } - .box:nth-of-type(n + 43) { - display: none; - } - \ No newline at end of file + + diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index 97b5ab466..c29d384cd 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -19,6 +19,8 @@ import getDrive from './parsefunction/getDrive.js'; import getReport from './parsefunction/getReport.js'; import generateApiToken from './parsefunction/generateApiToken.js'; import getapitoken from './parsefunction/getapitoken.js'; +import TemplateAfterSave from './parsefunction/TemplateAfterSave.js'; +import GetTemplate from './parsefunction/GetTemplate.js'; Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('UserGroups', getUserGroups); @@ -28,9 +30,6 @@ Parse.Cloud.define('googlesign', GoogleSign); Parse.Cloud.define('zohodetails', ZohoDetails); Parse.Cloud.define('usersignup', usersignup); Parse.Cloud.define('facebooksign', FacebookSign); -Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); -Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); -Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1); Parse.Cloud.define('sendmail', SendMailv1); Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); @@ -41,3 +40,10 @@ 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.afterSave('contracts_Document', DocumentAftersave); +Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); +Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); +Parse.Cloud.afterSave("contracts_Template", TemplateAfterSave) diff --git a/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js b/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js index d49794c0e..644a2a763 100644 --- a/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js @@ -16,6 +16,7 @@ async function ContactbookAftersave(request) { acl.setWriteAccess(object.get('UserId'), true); object.setACL(acl); + object.set('IsDeleted', false) // Continue saving the object return object.save(null, { useMasterKey: true }); } diff --git a/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js new file mode 100644 index 000000000..768827eee --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js @@ -0,0 +1,53 @@ +import axios from 'axios'; + +export default async function GetTemplate(request) { + const serverUrl = process.env.SERVER_URL; + const templateId = request.params.templateId; + + 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; + // console.log("templateId ", templateId) + // console.log("userId ",userId) + if (templateId && userId) { + try { + const template = new Parse.Query('contracts_Template'); + template.equalTo('objectId', templateId); + template.include('ExtUserPtr'); + template.include('Signers'); + template.include('CreateBy'); + const res = await template.first({ useMasterKey: true }); + // console.log("res ", res) + if (res) { + // console.log("res ",res) + const acl = res.getACL(); + console.log("acl", acl.getReadAccess(userId)) + if (acl && acl.getReadAccess(userId)) { + return res; + } else { + return { error: "You don't have access of this document!" }; + } + } else { + return { error: "You don't have access of this document!" }; + } + } catch (err) { + console.log('err', err); + return err; + } + } else { + return { error: 'Please pass required parameters!' }; + } + } catch (err) { + console.log('err', err); + if (err.code == 209) { + return { error: 'Invalid session token' }; + } else { + return { error: "You don't have access of this document!" }; + } + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js new file mode 100644 index 000000000..7d22ccb86 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -0,0 +1,83 @@ +export default async function TemplateAfterSave(request) { + try { + if (!request.original) { + console.log('new entry is insert in contracts_Template'); + // update acl of New Document If There are signers present in array + const signers = request.object.get('Signers'); + + if (signers && signers.length > 0) { + await updateAclDoc(request.object.id); + } else { + await updateSelfDoc(request.object.id); + } + } else { + if (request.user) { + const signers = request.object.get('Signers'); + if (signers && signers.length > 0) { + await updateAclDoc(request.object.id); + } else { + await updateSelfDoc(request.object.id); + } + } + } + } catch (err) { + console.log('err in aftersave of contracts_Template'); + console.log(err); + } + + async function updateAclDoc(objId) { + // console.log("In side updateAclDoc func") + // console.log(objId) + const Query = new Parse.Query('contracts_Template'); + Query.include('Signers'); + const updateACL = await Query.get(objId, { useMasterKey: true }); + const res = JSON.parse(JSON.stringify(updateACL)); + // console.log("res"); + // console.log(JSON.stringify(res)); + const UsersPtr = res.Signers.map(item => item.UserId); + + if (res.Signers[0].ExtUserPtr) { + const ExtUserSigners = res.Signers.map(item => { + return { + __type: 'Pointer', + className: 'contracts_Users', + objectId: item.ExtUserPtr.objectId, + }; + }); + updateACL.set('Signers', ExtUserSigners); + } + + // console.log("UsersPtr") + // console.log(JSON.stringify(UsersPtr)) + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); + + UsersPtr.forEach(x => { + newACL.setReadAccess(x.objectId, true); + newACL.setWriteAccess(x.objectId, true); + }); + + updateACL.setACL(newACL); + updateACL.save(null, { useMasterKey: true }); + } + + 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)); + // 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); + updateACL.setACL(newACL); + updateACL.save(null, { useMasterKey: true }); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/getDocument.js b/apps/OpenSignServer/cloud/parsefunction/getDocument.js index 9e4d71ff3..a88a97cf4 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getDocument.js +++ b/apps/OpenSignServer/cloud/parsefunction/getDocument.js @@ -21,6 +21,7 @@ export default async function getDocument(request) { query.include('Signers'); query.include('AuditTrail.UserPtr'); query.include('Placeholders'); + query.notEqualTo('IsArchive', true) const res = await query.first({ useMasterKey: true }); if (res) { const acl = res.getACL(); @@ -40,7 +41,7 @@ export default async function getDocument(request) { return { error: 'Please pass required parameters!' }; } } catch (err) { - console.log('err'); + console.log('err', err); if (err.code == 209) { return { error: 'Invalid session token' }; } else { diff --git a/apps/OpenSignServer/cloud/parsefunction/getDrive.js b/apps/OpenSignServer/cloud/parsefunction/getDrive.js index 5c0d31a8e..516ca9764 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getDrive.js +++ b/apps/OpenSignServer/cloud/parsefunction/getDrive.js @@ -16,9 +16,9 @@ export default async function getDrive(request) { if (userId) { let url; if (docId) { - url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}]}&include=ExtUserPtr,Signers,Folder`; + url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers,Folder`; } else { - url = `${classUrl}?where={"Folder":{"$exists":false},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}]}&include=ExtUserPtr,Signers`; + url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers`; } try { const res = await axios.get(url, { diff --git a/apps/OpenSignServer/cloud/parsefunction/getReport.js b/apps/OpenSignServer/cloud/parsefunction/getReport.js index 759765aaa..ee72f0d20 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getReport.js +++ b/apps/OpenSignServer/cloud/parsefunction/getReport.js @@ -19,7 +19,7 @@ export default async function getReport(request) { const userId = userRes.data && userRes.data.objectId; if (userId) { const json = reportId && reportJson(reportId, userId); - const clsName = reportId === '5KhaPr482K' ? 'contracts_Contactbook' : 'contracts_Document'; + const clsName = json?.reportClass ? json.reportClass : 'contracts_Document'; if (json) { const { params, keys } = json; const orderBy = '-updatedAt'; diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 3bbabdad2..b6f989cb7 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -2,7 +2,7 @@ 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 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,20 +19,20 @@ async function uploadFile(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 p = { SignedUrl: s, AuditTrail: e, IsCompleted: a }; await axios.put(serverUrl + '/classes/contracts_Document/' + t, p, { headers: { @@ -61,7 +61,7 @@ async function sendMail(e) { s + ' Standard is attached to this email. Kindly download the document from the attachment.

    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.

    ', + ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.

    ' }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -86,7 +86,7 @@ async function sendCompletedMail(e) { s + '. Kindly download the document from the attachment.

    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.

    ', + ' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.

    ', }; await axios.post(serverUrl + '/functions/sendmailv3', a, { headers: { @@ -96,115 +96,135 @@ async function sendCompletedMail(e) { }, }); } -async function PDF(s, r) { +async function PDF(i, n) { try { - var i = s.params.sign, - e = s.params.docId, - o = s.params.userId, - n = await axios.get(serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr', { - headers: { - 'Content-Type': 'application/json', - 'X-Parse-Application-Id': APPID, - 'X-Parse-Master-Key': masterKEY, - }, - }), - d = await axios.get(serverUrl + '/users/me', { + i.params.sign; + var e = i.params.docId, + a = i.params.userId, + o = await axios.get( + serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers', + { + headers: { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': APPID, + 'X-Parse-Master-Key': masterKEY, + }, + } + ), + t = await axios.get(serverUrl + '/users/me', { headers: { 'X-Parse-Application-Id': APPID, - 'X-Parse-Session-Token': s.headers.sessiontoken, + 'X-Parse-Session-Token': i.headers.sessiontoken, }, }); - if (!d.data || !d.data.objectId) return { status: 'error', message: 'this user not allowed!' }; + if (!t.data || !t.data.objectId) return { status: 'error', message: 'this user not allowed!' }; { - var l, + var d, + l, p, - c, - m = JSON.stringify({ objectId: o }); - let a, t; - t = o - ? (l = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + m, { + c = JSON.stringify({ objectId: a }); + let s, r; + r = a + ? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, { headers: { 'X-Parse-Application-Id': APPID, - 'X-Parse-Session-Token': s.headers.sessiontoken, + 'X-Parse-Session-Token': i.headers.sessiontoken, }, - })).data && 0 < l.data.results.length - ? ((a = l), 'contracts_Contactbook') - : ((a = await axios.get(serverUrl + '/classes/contracts_Users?where=' + m, { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Master-Key': masterKEY, - }, + })).data && 0 < d.data.results.length + ? ((s = d), 'contracts_Contactbook') + : ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, { + headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY }, })), 'contracts_Users') - : ((p = JSON.stringify({ - UserId: { __type: 'Pointer', className: '_User', objectId: d.data.objectId }, + : ((l = JSON.stringify({ + UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId }, })), - (c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, { - headers: { - 'X-Parse-Application-Id': APPID, - 'X-Parse-Master-Key': masterKEY, - }, - })).data && 0 < c.data.results.length - ? ((a = c), 'contracts_Users') - : ((a = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, { + (p = 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') + : ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + l, { headers: { 'X-Parse-Application-Id': APPID, - 'X-Parse-Session-Token': s.headers.sessiontoken, + 'X-Parse-Session-Token': i.headers.sessiontoken, }, })), 'contracts_Contactbook')); - var g = a.data.results[0].Name, - h = a.data.results[0].Email; - if (!s.params.pdfFile) return { status: 'error', message: 'pdf file not present!' }; + var m = s.data.results[0].Name, + g = s.data.results[0].Email; + if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' }; { - let e = Buffer.from(s.params.pdfFile, 'base64'); + let e = Buffer.from(i.params.pdfFile, 'base64'); var u = process.env.PFX_BASE64, - f = Buffer.from(u, 'base64'); - e = i - ? plainplaceholder({ - pdfBuffer: e, - reason: 'Digitally signed by Open sign for ' + g + ' <' + h + '>', - location: 'test location', - signatureLength: 1e4, - sign: i, - }) - : plainAddPlaceholder({ - pdfBuffer: e, - reason: 'Digitally signed by Open sign for ' + g + ' <' + h + '>', - location: 'test location', - signatureLength: 1e4, - }); - var y = await new SignPDF(e, f).signPDF(), - v = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`, - P = (fs.writeFileSync(v, y), await uploadFile(v)); - if (P && P.imageUrl) { - const r = await updateDoc( - s.params.docId, - P.imageUrl, - a.data.results[0].objectId, - s.headers['x-real-ip'], - n.data, - t + h = Buffer.from(u, 'base64'), + f = { + UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId }, + SignedUrl: '', + Activity: 'Signed', + ipAddress: i.headers['x-real-ip'], + }; + let a; + var y = (a = + o.data.AuditTrail && 0 < o.data.AuditTrail.length + ? [...o.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) || + !(t = !0) + ); + var v, + P, + x = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`, + A = + (t + ? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), + (e = + v && 0 < v.length + ? plainAddPlaceholder({ + pdfBuffer: e, + reason: 'Digitally signed by Open sign for ' + v?.join(', '), + location: 'location', + signatureLength: 1e4, + }) + : plainAddPlaceholder({ + pdfBuffer: e, + reason: 'Digitally signed by Open sign for ' + m + ' <' + g + '>', + location: 'location', + signatureLength: 1e4, + })), + (P = await new SignPDF(e, h).signPDF()), + fs.writeFileSync(x, P)) + : fs.writeFileSync(x, e), + await uploadFile(x)); + if (A && A.imageUrl) { + const n = await updateDoc( + i.params.docId, + A.imageUrl, + s.data.results[0].objectId, + i.headers['x-real-ip'], + o.data, + r ); return ( sendMail({ - url: P.imageUrl, - sender: { Mail: n.data.ExtUserPtr.Email, Name: n.data.ExtUserPtr.Name }, - pdfName: n.data.Name, - receiver: h, + url: A.imageUrl, + sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name }, + pdfName: o.data.Name, + receiver: g, }), - r && - r.isCompleted && + n && + n.isCompleted && sendCompletedMail({ - url: P.imageUrl, - sender: { Mail: n.data.ExtUserPtr.Email, Name: 'Open sign' }, - pdfName: n.data.Name, - receiver: n.data.ExtUserPtr.Email, + url: A.imageUrl, + sender: { Mail: o.data.ExtUserPtr.Email, Name: 'Open sign' }, + pdfName: o.data.Name, + receiver: o.data.ExtUserPtr.Email, }), - fs.unlinkSync(v), - console.log('New Signed PDF created called: ' + v), - 'success' === r.message - ? { status: 'success', data: P.imageUrl } + fs.unlinkSync(x), + console.log('New Signed PDF created called: ' + x), + 'success' === n.message + ? { status: 'success', data: A.imageUrl } : { status: 'error', message: 'please provide required parameters!' } ); } diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js index 8ad9c47df..2031cd076 100644 --- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js +++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js @@ -7,11 +7,11 @@ export default function reportJson(id, userId) { return { reportName: 'Draft Documents', params: { - Type: null, - $or: [ - { Signers: null, SignedUrl: null }, - { Signers: { $exists: true }, Placeholders: null }, - ], + Type: { $ne: 'Folder' }, + IsCompleted: { $ne: true }, + IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, + $or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }], CreatedBy: { __type: 'Pointer', className: '_User', @@ -28,10 +28,23 @@ export default function reportJson(id, userId) { Type: { $ne: 'Folder' }, IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, Placeholders: { $ne: null }, + Signers: { + $inQuery: { + where: { + UserId: { + __type: 'Pointer', + className: '_User', + objectId: currentUserId, + }, + }, + className: 'contracts_Contactbook', + }, + }, }, keys: [ 'Name', @@ -50,10 +63,11 @@ export default function reportJson(id, userId) { reportName: 'In-progress documents', params: { Type: { $ne: 'Folder' }, - Signers: { $ne: null }, + Signers: { $exists: true, $ne: [] }, Placeholders: { $ne: null }, IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, CreatedBy: { __type: 'Pointer', className: '_User', @@ -70,7 +84,7 @@ export default function reportJson(id, userId) { return { reportName: 'Completed Documents', params: { - Type: null, + Type: { $ne: 'Folder' }, IsCompleted: true, CreatedBy: { __type: 'Pointer', @@ -78,6 +92,7 @@ export default function reportJson(id, userId) { objectId: currentUserId, }, IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, }, keys: [ 'Name', @@ -96,6 +111,7 @@ export default function reportJson(id, userId) { reportName: 'Declined Documents', params: { Type: null, + IsArchive: { $ne: true }, IsDeclined: true, CreatedBy: { __type: 'Pointer', @@ -113,6 +129,7 @@ export default function reportJson(id, userId) { params: { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, Type: { $ne: 'Folder' }, $and: [ { @@ -141,10 +158,11 @@ export default function reportJson(id, userId) { reportName: 'Recently sent for signatures', params: { Type: { $ne: 'Folder' }, - Signers: { $ne: null }, + Signers: { $exists: true, $ne: [] }, Placeholders: { $ne: null }, IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, CreatedBy: { __type: 'Pointer', className: '_User', @@ -154,7 +172,7 @@ 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', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], }; // Recent signature requests report show on dashboard case '5Go51Q7T8r': @@ -164,32 +182,36 @@ export default function reportJson(id, userId) { Type: { $ne: 'Folder' }, IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, ExpiryDate: { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, Placeholders: { $ne: null }, + Signers: { + $inQuery: { + where: { + UserId: { + __type: 'Pointer', + className: '_User', + objectId: currentUserId, + }, + }, + className: 'contracts_Contactbook', + }, + }, }, - keys: [ - 'Name', - 'Note', - 'Folder.Name', - 'URL', - 'ExtUserPtr.Name', - 'Signers.Name', - 'Signers.UserId', - 'AuditTrail', - ], + keys: ['Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name', 'Signers.UserId', 'AuditTrail'], }; // Drafts report show on dashboard case 'kC5mfynCi4': return { reportName: 'Drafts', params: { - Type: null, - $or: [ - { Signers: null, SignedUrl: null }, - { Signers: { $exists: true }, Placeholders: null }, - ], + Type: { $ne: 'Folder' }, + IsCompleted: { $ne: true }, + IsDeclined: { $ne: true }, + IsArchive: { $ne: true }, + $or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }], CreatedBy: { __type: 'Pointer', className: '_User', @@ -202,6 +224,7 @@ export default function reportJson(id, userId) { case '5KhaPr482K': return { reportName: 'Contactbook', + reportClass: 'contracts_Contactbook', params: { CreatedBy: { __type: 'Pointer', @@ -212,6 +235,22 @@ export default function reportJson(id, userId) { }, keys: ['Name', 'Email', 'Phone'], }; + // Templates report + case '6TeaPr321t': + return { + reportName: 'Templates', + reportClass: 'contracts_Template', + params: { + Type: { $ne: 'Folder' }, + IsArchive: { $ne: true }, + CreatedBy: { + __type: 'Pointer', + className: '_User', + objectId: currentUserId, + }, + }, + keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + }; default: return null; } diff --git a/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs b/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs index 9581be3a8..2bb108b99 100644 --- a/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs +++ b/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs @@ -38,7 +38,7 @@ exports.up = async Parse => { pageType: 'form', description: '', objectId: '8mZzFxbG1z', - }, + } ], }, { diff --git a/apps/OpenSignServer/databases/migrations/20231208132950-update_template_menu.cjs b/apps/OpenSignServer/databases/migrations/20231208132950-update_template_menu.cjs new file mode 100644 index 000000000..e092c2db5 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20231208132950-update_template_menu.cjs @@ -0,0 +1,588 @@ +/** + * + * @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', + }, + ], + }, + ]); + + 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', + }, + ], + }, + ]); + // 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: 'fas fa-file-signature', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + ], + }, + { + icon: 'fas fa-folder', + title: 'OpenSignDrive™', + 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: '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: 'fas fa-file-signature', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + ], + }, + { + icon: 'fas fa-folder', + title: 'OpenSignDrive™', + 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: '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 }); +}; \ No newline at end of file diff --git a/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs b/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs new file mode 100644 index 000000000..295a9840e --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs @@ -0,0 +1,40 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'contracts_Template'; + const schema = new Parse.Schema(className); + + schema.addString('Name'); + schema.addString('URL'); + schema.addString('Note'); + schema.addString('Description'); + schema.addArray('Signers'); + schema.addBoolean('IsArchive'); + schema.addArray('Placeholders'); + schema.addPointer('Folder', 'contracts_Template'); + schema.addString('Type'); + schema.addPointer('CreatedBy', '_User'); + schema.addPointer('ExtUserPtr', 'contracts_Users'); + schema.addBoolean('EnablePhoneOTP') + schema.addBoolean('EnableEmailOTP') + schema.addBoolean('SendinOrder') + schema.addBoolean('SentToOthers') + schema.addBoolean('AutomaticReminders') + + + + return schema.save(); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + const className = 'contracts_Template'; + const schema = new Parse.Schema(className); + + return schema.purge().then(() => schema.delete()); +}; \ No newline at end of file diff --git a/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs new file mode 100644 index 000000000..1a95b4f46 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs @@ -0,0 +1,23 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + // TODO: set className here + const className = 'contracts_Document'; + const schema = new Parse.Schema(className); + schema.addBoolean('IsArchive'); + return schema.update(); + }; + + /** + * + * @param {Parse} Parse + */ + exports.down = async Parse => { + // TODO: set className here + const className = 'contracts_Document'; + const schema = new Parse.Schema(className); + schema.deleteField('IsArchive'); + return schema.update(); + }; \ No newline at end of file diff --git a/apps/OpenSignServer/exports/exported_file_2928.pdf b/apps/OpenSignServer/exports/exported_file_2928.pdf deleted file mode 100644 index 1602a4456..000000000 Binary files a/apps/OpenSignServer/exports/exported_file_2928.pdf and /dev/null differ diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index c5b621de7..b69429e59 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -70,7 +70,9 @@ if (process.env.SMTP_ENABLE) { export const config = { databaseURI: process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev', - cloud: process.env.CLOUD || __dirname + '/cloud/main.js', + cloud: function () { + import('./cloud/main.js'); + }, appId: process.env.APP_ID || 'myAppId', masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret! masterKeyIps: ['0.0.0.0/0', '::1'], // '::1' @@ -174,12 +176,6 @@ app.get('/', function (req, res) { res.status(200).send('open-sign-server is running !!!'); }); -// There will be a test page available on the /test path of your server url -// Remove this before launching your app -app.get('/test', function (req, res) { - res.sendFile(path.join(__dirname, '/public/test.html')); -}); - if (!process.env.TESTING) { const port = process.env.PORT || 8080; const httpServer = http.createServer(app); diff --git a/microfrontends/SignDocuments/package-lock.json b/microfrontends/SignDocuments/package-lock.json index 4598b6dad..aeedb863c 100644 --- a/microfrontends/SignDocuments/package-lock.json +++ b/microfrontends/SignDocuments/package-lock.json @@ -29,11 +29,13 @@ "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", + "react-helmet": "^6.1.0", "react-pdf": "^7.4.0", "react-rnd": "^10.4.1", "react-router-dom": "^6.16.0", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.1", + "react-select": "^5.8.0", "react-signature-canvas": "^1.0.6", "reactour": "^1.19.1", "select-dom": "^9.0.0", @@ -2310,6 +2312,65 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", @@ -2322,8 +2383,52 @@ "node_modules/@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", - "peer": true + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", + "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, "node_modules/@emotion/stylis": { "version": "0.8.5", @@ -2337,6 +2442,24 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "peer": true }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -10608,6 +10731,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -14810,6 +14938,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -17748,6 +17881,25 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "dependencies": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -18003,6 +18155,34 @@ "react": ">=16.0.0" } }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-side-effect": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-signature-canvas": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz", @@ -19527,6 +19707,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -20443,6 +20628,19 @@ } } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/microfrontends/SignDocuments/package.json b/microfrontends/SignDocuments/package.json index 5bc6f7685..c0e70c06d 100644 --- a/microfrontends/SignDocuments/package.json +++ b/microfrontends/SignDocuments/package.json @@ -25,11 +25,13 @@ "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", + "react-helmet": "^6.1.0", "react-pdf": "^7.4.0", "react-rnd": "^10.4.1", "react-router-dom": "^6.16.0", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.1", + "react-select": "^5.8.0", "react-signature-canvas": "^1.0.6", "reactour": "^1.19.1", "select-dom": "^9.0.0", diff --git a/microfrontends/SignDocuments/public/index.html b/microfrontends/SignDocuments/public/index.html index bf27a008e..b3ac89822 100644 --- a/microfrontends/SignDocuments/public/index.html +++ b/microfrontends/SignDocuments/public/index.html @@ -47,7 +47,7 @@ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" /> - OpenSign App + OpenSign™ diff --git a/microfrontends/SignDocuments/src/Component/DraftDocument.js b/microfrontends/SignDocuments/src/Component/DraftDocument.js index 95ab370b9..8384871f4 100644 --- a/microfrontends/SignDocuments/src/Component/DraftDocument.js +++ b/microfrontends/SignDocuments/src/Component/DraftDocument.js @@ -47,65 +47,34 @@ function DraftDocument() { //check document type and render on signyour self and placeholder route const handleDraftDoc = () => { const data = pdfDetails[0]; - const checkSignerExist = - pdfDetails[0] && pdfDetails[0].Signers && pdfDetails[0].Signers; - const isPlaceholder = - pdfDetails[0].Placeholders && pdfDetails[0].Placeholders; - const isDecline = data.IsDeclined && data.IsDeclined; - const signUrl = data.SignedUrl && data.SignedUrl; - const expireDate = - pdfDetails[0] && - pdfDetails[0].ExpiryDate.iso && - pdfDetails[0].ExpiryDate.iso; - const expireUpdateDate = new Date(expireDate).getTime(); - const currDate = new Date().getTime(); const hostUrl = getHostUrl(); + const signerExist = data.Signers && data.Signers; + const isDecline = data.IsDeclined && data.IsDeclined; + const isPlaceholder = data.Placeholders && data.Placeholders; - //checking document is completed and signer exist then navigate to pdfRequestFiles file - if (data.IsCompleted && checkSignerExist) { - navigate(`${hostUrl}pdfRequestFiles`); + //checking if document has completed and request signature flow + if (data?.IsCompleted && signerExist?.length > 0) { + navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); } - //checking document is completed and signer does not exist then navigate to recipientSignPdf file - else if (data.IsCompleted && !checkSignerExist) { - navigate(`${hostUrl}signaturePdf`); + //checking if document has completed and signyour-self flow + else if (!signerExist && !isPlaceholder) { + navigate(`${hostUrl}signaturePdf/${data.objectId}`); } - //checking document is declined by someone then navigate to pdfRequestFiles file + //checking if document has declined by someone else if (isDecline) { - navigate(`${hostUrl}pdfRequestFiles`); + navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); + //checking draft type document } - //checking document has expired and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file - //draft type request sign document + //Inprogress document + else if (isPlaceholder?.length > 0 && signerExist?.length > 0) { + navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); + } //placeholder draft document else if ( - currDate > expireUpdateDate && - checkSignerExist && - !isPlaceholder + (signerExist?.length > 0 && + (!isPlaceholder || isPlaceholder?.length === 0)) || + ((!signerExist || signerExist?.length === 0) && isPlaceholder?.length > 0) ) { - navigate(`${hostUrl}placeHolderSign`); - } - //checking document has expired and signers does not exist and document not signed yet then navigate to pdfRequestFiles file - //draft type signyouselfdocument - else if ( - currDate > expireUpdateDate && - !checkSignerExist && - !isPlaceholder && - !signUrl - ) { - // window.location.hash = `/signaturePdf`; - navigate(`${hostUrl}signaturePdf`); - } - //checking document has expired and signers exist and document then navigate to pdfRequestFiles file - else if (currDate > expireUpdateDate) { - // window.location.hash = `/pdfRequestFiles`; - navigate(`${hostUrl}pdfRequestFiles`); - } - //checking document has expired not been expired yet and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file - //draft type request sign document - else if (!signUrl && checkSignerExist) { - navigate(`${hostUrl}placeHolderSign`); - // window.location.hash = `/placeHolderSign`; - } else { - // window.location.hash = `/signaturePdf/`; - navigate(`${hostUrl}signaturePdf`); + navigate(`${hostUrl}placeHolderSign/${data.objectId}`); } }; diff --git a/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js b/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js index df62c822d..760ce39af 100644 --- a/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js +++ b/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js @@ -10,6 +10,9 @@ import { getHostUrl } from "../../../utils/Utils"; import { useNavigate } from "react-router-dom"; import Table from "react-bootstrap/Table"; import * as HoverCard from "@radix-ui/react-hover-card"; +import SelectFolder from "../../../premitives/SelectFolder"; +import ModalUi from "../../../premitives/ModalUi"; +import { themeColor } from "../../../utils/ThemeColor/backColor"; function PdfFileComponent({ pdfData, @@ -17,12 +20,20 @@ function PdfFileComponent({ setDocId, setIsLoading, setPdfData, - isList, + isList }) { const [rename, setRename] = useState(""); const [renameValue, setRenameValue] = useState(""); const inputRef = useRef(null); - + const [isOpenMoveModal, setIsOpenMoveModal] = useState(false); + const [selectDoc, setSelectDoc] = useState(); + const [isDeleteDoc, setIsDeleteDoc] = useState(false); + const contextMenu = [ + { type: "Download", icon: "fa-solid fa-arrow-down" }, + { type: "Rename", icon: "fa-solid fa-font" }, + { type: "Move", icon: "fa-solid fa-file-export" }, + { type: "Delete", icon: "fa-solid fa-trash" } + ]; const navigate = useNavigate(); //to focus input box on press rename to change doc name @@ -39,12 +50,12 @@ function PdfFileComponent({ const handleOnclikFolder = (data) => { const folderData = { name: data.Name, - objectId: data.objectId, + objectId: data.objectId }; setFolderName((prev) => [...prev, folderData]); const loadObj = { isLoad: true, - message: "This might take some time", + message: "This might take some time" }; setIsLoading(loadObj); @@ -57,7 +68,7 @@ function PdfFileComponent({ if (trimmedValue.length > 0) { const updateName = { - Name: renameValue, + Name: renameValue }; const docId = data.objectId; @@ -83,8 +94,8 @@ function PdfFileComponent({ headers: { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), - "X-Parse-Session-Token": localStorage.getItem("accesstoken"), - }, + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } } ) .then((result) => { @@ -99,79 +110,176 @@ function PdfFileComponent({ //function for navigate user to microapp-signature component const checkPdfStatus = async (data) => { - const hostUrl = getHostUrl(); - const expireDate = data.ExpiryDate.iso; - const expireUpdateDate = new Date(expireDate).getTime(); - const currDate = new Date().getTime(); + const signerExist = data.Signers && data.Signers; - const signUrl = data.SignedUrl && data.SignedUrl; const isDecline = data.IsDeclined && data.IsDeclined; const isPlaceholder = data.Placeholders && data.Placeholders; - //checking and navigate to signyouself page - const checkPlaceHolder = data.Placeholders; - //checking if document has completed - if (data.IsCompleted && signerExist) { - navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); - // window.location.hash = `/pdfRequestFiles/${data.objectId}`; - } else if (data.IsCompleted && !signerExist) { - navigate( - `${hostUrl}signaturePdf/${data.objectId}` - ); - // window.location.hash = `/recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`; + //checking if document has completed and request signature flow + if (data?.IsCompleted && signerExist?.length > 0) { + navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); + } + //checking if document has completed and signyour-self flow + else if (!signerExist && !isPlaceholder) { + navigate(`${hostUrl}signaturePdf/${data.objectId}`); } //checking if document has declined by someone else if (isDecline) { navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); - // window.location.hash = `/pdfRequestFiles/${data.objectId}`; - } else if (currDate > expireUpdateDate && signerExist && !isPlaceholder) { - // window.location.hash = `/placeHolderSign/${data.objectId}`; - navigate(`${hostUrl}placeHolderSign/${data.objectId}`); - } else if ( - currDate > expireUpdateDate && - !signerExist && - !isPlaceholder && - !signUrl - ) { - navigate(`${hostUrl}signaturePdf/${data.objectId}`); - // window.location.hash = `/signaturePdf/${data.objectId}`; + //checking draft type document } - //checking if document has expired - else if (currDate > expireUpdateDate) { + //Inprogress document + else if (isPlaceholder?.length > 0 && signerExist?.length > 0) { navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); - // window.location.hash = `/pdfRequestFiles/${data.objectId}`; - } //checking if document is draft signers type and signers placeholder does not placed yet - else if (!signUrl && signerExist) { - // window.location.hash = `/placeHolderSign/${data.objectId}`; - navigate(`${hostUrl}placeHolderSign/${data.objectId}`); - } - //checking if document is request type and signers placeholder exist and does not completed yet - //then user can check progress of document and sign also + } //placeholder draft document else if ( - checkPlaceHolder && - checkPlaceHolder.length > 0 && - !data.IsCompleted + (signerExist?.length > 0 && + (!isPlaceholder || isPlaceholder?.length === 0)) || + ((!signerExist || signerExist?.length === 0) && isPlaceholder?.length > 0) ) { - navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`); - // window.location.hash = `/pdfRequestFiles/${data.objectId}`; + navigate(`${hostUrl}placeHolderSign/${data.objectId}`); } - //checking document is draft and signyourself type then user can sign document - else { - navigate(`${hostUrl}signaturePdf/${data.objectId}`); - // navigate(`/signaturePdf/${data.objectId}`); - // window.location.hash = `/signaturePdf/${data.objectId}`; + }; + + const handleMenuItemClick = (selectType, data) => { + switch (selectType) { + case "Download": + const pdfName = data && data.Name; + const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL; + saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`); + break; + case "Rename": + setRenameValue(data.Name); + setRename(data.objectId); + break; + case "Delete": + setIsDeleteDoc(true); + setSelectDoc(data); + break; + + case "Move": + handleMoveDocument(data); + break; } }; + //function for delete document + const handleDeleteDocument = async (docData) => { + setIsDeleteDoc(false); + const docId = docData.objectId; + const data = { + IsArchive: true + }; + + await axios + .put( + `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( + "_appName" + )}_Document/${docId}`, + 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; + const updatedData = pdfData.filter((x) => x.objectId !== docId); + setPdfData(updatedData); + }) + .catch((err) => { + console.log("err", err); + }); + }; + const handleMoveDocument = async (docData) => { + setIsOpenMoveModal(true); + setSelectDoc(docData); + }; + //function for move document from one folder to another folder + const handleMoveFolder = async (selectFolderData) => { + const selecFolderId = selectDoc?.Folder?.objectId; + const moveFolderId = selectFolderData?.ObjectId; + let updateDocId = selectDoc?.objectId; + let updateData; + const checkExist = moveFolderId + ? selecFolderId === moveFolderId + ? true + : false + : selecFolderId + ? false + : true; + if (!checkExist) { + if (moveFolderId) { + updateData = { + Folder: { + __type: "Pointer", + className: `${localStorage.getItem("_appName")}_Document`, + objectId: moveFolderId + } + }; + } else { + updateData = { + Folder: { __op: "Delete" } + }; + } + + await axios + .put( + `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( + "_appName" + )}_Document/${updateDocId}`, + updateData, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } + } + ) + + .then((Listdata) => { + // console.log("Listdata ", Listdata); + const json = Listdata.data; + + const updatedData = pdfData.filter((x) => x.objectId !== updateDocId); + setPdfData(updatedData); + }) + .catch((err) => { + console.log("err", err); + }); + + setIsOpenMoveModal(false); + } else { + alert("folder already exist!"); + setIsOpenMoveModal(false); + } + }; + + const sanitizeFileName = (pdfName) => { + // Replace spaces with underscore + return pdfName.replace(/ /g, "_"); + }; + + const handleEnterPress = (e, data) => { + if (e.key === "Enter") { + handledRenameDoc(data); + } + }; + + const handleDraftDoc = (data) => { + window.location.hash = `/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie?${data.objectId}`; + }; //component to handle type of document and render according to type const handleFolderData = (data, ind, listType) => { - // console.log("data", data); let createddate, status, isDecline, signerExist, - isExpire, isComplete, signUrl, isPlaceholder; @@ -186,64 +294,48 @@ function PdfFileComponent({ signUrl = data.SignedUrl && data.SignedUrl; const expireUpdateDate = new Date(expireDate).getTime(); const currDate = new Date().getTime(); - + let isExpire = false; if (currDate > expireUpdateDate) { isExpire = true; - } else { - isExpire = false; } + if (isComplete) { status = "Completed"; } else if (isDecline) { status = "Declined"; - } else if (isExpire && !isPlaceholder && signerExist) { - // status = "Expired"; + } else if (!signerExist || signerExist?.length === 0) { status = "Draft"; - } else if (isExpire && !isPlaceholder && !signerExist && !signUrl) { - // status = "Expired"; + } else if ( + signerExist?.length > 0 && + (!isPlaceholder || isPlaceholder?.length === 0) + ) { status = "Draft"; } else if (isExpire) { status = "Expired"; - } else if (!signUrl) { - status = "Draft"; } else { - status = "InComplete"; + status = "In Progress"; } } - const handleDraftDoc = (data) => { - window.location.hash = `/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie?${data.objectId}`; + const signersName = () => { + const getSignersName = signerExist.map((data) => data.Name); + const signerName = getSignersName.join(","); + + return ( + + {signerName}{" "} + + ); }; - - const handleMenuItemClick = (selectType, data) => { - // console.log("data",data) - if (selectType === "Download") { - // console.log("download") - const pdfName = data && data.Name; - const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL; - saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`); - } else if (selectType === "Rename") { - // console.log("rename") - setRenameValue(data.Name); - setRename(data.objectId); - } - }; - - const sanitizeFileName = (pdfName) => { - // Replace spaces with underscore - return pdfName.replace(/ /g, '_'); - } - - const handleEnterPress = (e, data) => { - if (e.key === "Enter") { - handledRenameDoc(data); - } - }; - return listType === "table" ? ( data.Type === "Folder" ? ( handleOnclikFolder(data)}> - +