├── .all-contributorsrc
├── .cz.toml
├── .env.example
├── .env.local_dev
├── .eslintrc.json
├── .github
├── ISSUE_TEMPLATE
│ ├── bug-report.yml
│ └── feature-request.yml
├── dependabot.yml
└── workflows
│ └── Docker.yml
├── .gitignore
├── .husky
└── pre-commit
├── .lintstagedrc.json
├── .prettierignore
├── .prettierrc.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Caddyfile
├── INSTALLATION.md
├── LICENSE
├── Makefile
├── README.md
├── USAGE.md
├── apps
├── OpenSign
│ ├── .babelrc
│ ├── .cz.toml
│ ├── .dockerignore
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── .husky
│ │ └── pre-commit
│ ├── .prettierignore
│ ├── .prettierrc.json
│ ├── Dockerhubfile
│ ├── README.md
│ ├── babel.config.js
│ ├── entrypoint.sh
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── locales
│ │ │ ├── de
│ │ │ │ └── translation.json
│ │ │ ├── en
│ │ │ │ └── translation.json
│ │ │ ├── es
│ │ │ │ └── translation.json
│ │ │ ├── fr
│ │ │ │ └── translation.json
│ │ │ ├── hi
│ │ │ │ └── translation.json
│ │ │ └── it
│ │ │ │ └── translation.json
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ ├── robots.txt
│ │ ├── static
│ │ │ └── js
│ │ │ │ └── assets
│ │ │ │ └── images
│ │ │ │ └── logo.2a7bff0c1189183fafe71d7d5b94e0cd.png
│ │ └── version.txt
│ ├── setuptest.js
│ ├── src
│ │ ├── App.jsx
│ │ ├── assets
│ │ │ └── images
│ │ │ │ ├── dp.png
│ │ │ │ ├── folder.png
│ │ │ │ ├── login_img.svg
│ │ │ │ ├── logo.png
│ │ │ │ ├── pad.svg
│ │ │ │ ├── pdf3.png
│ │ │ │ └── recreatedoc.png
│ │ ├── components
│ │ │ ├── AddSigner.jsx
│ │ │ ├── AddUser.jsx
│ │ │ ├── BulkSendUi.jsx
│ │ │ ├── EditContactForm.jsx
│ │ │ ├── Footer.jsx
│ │ │ ├── FullScreenButton.jsx
│ │ │ ├── Header.jsx
│ │ │ ├── RenderDebugPdf.jsx
│ │ │ ├── RotateAlert.jsx
│ │ │ ├── SocialMedia.jsx
│ │ │ ├── Title.jsx
│ │ │ ├── dashboard
│ │ │ │ ├── DashboardButton.jsx
│ │ │ │ ├── DashboardCard.jsx
│ │ │ │ ├── DashboardReport.jsx
│ │ │ │ └── GetDashboard.jsx
│ │ │ ├── opensigndrive
│ │ │ │ └── DriveBody.jsx
│ │ │ ├── pdf
│ │ │ │ ├── AddRoleModal.jsx
│ │ │ │ ├── AgreementContent.jsx
│ │ │ │ ├── AgreementSign.jsx
│ │ │ │ ├── BorderResize.jsx
│ │ │ │ ├── DefaultSignature.jsx
│ │ │ │ ├── DraftDocument.jsx
│ │ │ │ ├── DragElement.jsx
│ │ │ │ ├── DropdownWidgetOption.jsx
│ │ │ │ ├── EditTemplate.jsx
│ │ │ │ ├── EditorToolbar.jsx
│ │ │ │ ├── EmailBody.jsx
│ │ │ │ ├── EmailComponent.jsx
│ │ │ │ ├── PdfHeader.jsx
│ │ │ │ ├── PdfZoom.jsx
│ │ │ │ ├── Placeholder.jsx
│ │ │ │ ├── PlaceholderCopy.jsx
│ │ │ │ ├── PlaceholderType.jsx
│ │ │ │ ├── PrevNext.jsx
│ │ │ │ ├── RecipientList.jsx
│ │ │ │ ├── RenderAllPdfPage.jsx
│ │ │ │ ├── RenderPdf.jsx
│ │ │ │ ├── SelectLanguage.jsx
│ │ │ │ ├── Signedby.jsx
│ │ │ │ ├── SignerListComponent.jsx
│ │ │ │ ├── SignerListPlace.jsx
│ │ │ │ ├── TextFontSetting.jsx
│ │ │ │ ├── VerifyEmail.jsx
│ │ │ │ ├── WidgetComponent.jsx
│ │ │ │ ├── WidgetList.jsx
│ │ │ │ ├── WidgetNameModal.jsx
│ │ │ │ └── WidgetsValueModal.jsx
│ │ │ ├── shared
│ │ │ │ └── fields
│ │ │ │ │ ├── CreateFolder.jsx
│ │ │ │ │ ├── DateFormatSelector.jsx
│ │ │ │ │ ├── FolderModal.jsx
│ │ │ │ │ ├── SelectFolder.jsx
│ │ │ │ │ ├── SelectSigners.jsx
│ │ │ │ │ ├── SignersInput.jsx
│ │ │ │ │ ├── SuggestionInput.jsx
│ │ │ │ │ └── TimezoneSelector.jsx
│ │ │ └── sidebar
│ │ │ │ ├── Menu.jsx
│ │ │ │ ├── Sidebar.jsx
│ │ │ │ └── SubMenu.jsx
│ │ ├── constant
│ │ │ ├── Utils.jsx
│ │ │ ├── appinfo.js
│ │ │ ├── const.js
│ │ │ ├── getReplacedHashQuery.js
│ │ │ └── saveFileSize.js
│ │ ├── hook
│ │ │ ├── useScript.js
│ │ │ └── useWindowSize.js
│ │ ├── i18n.js
│ │ ├── index.css
│ │ ├── index.jsx
│ │ ├── json
│ │ │ ├── FormJson.js
│ │ │ ├── ReportJson.js
│ │ │ ├── dashboardJson.js
│ │ │ └── menuJson.js
│ │ ├── layout
│ │ │ └── HomeLayout.jsx
│ │ ├── pages
│ │ │ ├── AddAdmin.jsx
│ │ │ ├── ChangePassword.jsx
│ │ │ ├── Dashboard.jsx
│ │ │ ├── DebugPdf.jsx
│ │ │ ├── DocSuccessPage.jsx
│ │ │ ├── ForgetPassword.jsx
│ │ │ ├── Form.jsx
│ │ │ ├── GuestLogin.jsx
│ │ │ ├── Login.jsx
│ │ │ ├── Managesign.jsx
│ │ │ ├── Opensigndrive.jsx
│ │ │ ├── PageNotFound.jsx
│ │ │ ├── PdfRequestFiles.jsx
│ │ │ ├── PlaceHolderSign.jsx
│ │ │ ├── Preferences.jsx
│ │ │ ├── Report.jsx
│ │ │ ├── SignyourselfPdf.jsx
│ │ │ ├── TemplatePlaceholder.jsx
│ │ │ ├── UpdateExistUserAdmin.jsx
│ │ │ ├── UserList.jsx
│ │ │ ├── UserProfile.jsx
│ │ │ └── VerifyDocument.jsx
│ │ ├── polyfills.js
│ │ ├── primitives
│ │ │ ├── AddContact.jsx
│ │ │ ├── Alert.jsx
│ │ │ ├── CheckCircle.jsx
│ │ │ ├── DotLottieReact.jsx
│ │ │ ├── DownloadPdfZip.jsx
│ │ │ ├── GetReportDisplay.jsx
│ │ │ ├── HandleError.jsx
│ │ │ ├── LazyPage.jsx
│ │ │ ├── LinkUserModal.jsx
│ │ │ ├── Loader.jsx
│ │ │ ├── LoaderWithMsg.jsx
│ │ │ ├── Modal.jsx
│ │ │ ├── ModalUi.jsx
│ │ │ ├── PdfDeclineModal.jsx
│ │ │ ├── ShareButton.jsx
│ │ │ ├── Tooltip.jsx
│ │ │ ├── Tour.jsx
│ │ │ ├── TourContentWithBtn.jsx
│ │ │ ├── Validate.jsx
│ │ │ ├── ValidateRoute.jsx
│ │ │ ├── ValidateSession.jsx
│ │ │ └── sanitizeFileName.js
│ │ ├── redux
│ │ │ ├── reducers
│ │ │ │ ├── ShowTenant.js
│ │ │ │ ├── TourStepsReducer.js
│ │ │ │ ├── infoReducer.js
│ │ │ │ ├── showHeader.js
│ │ │ │ └── widgetSlice.js
│ │ │ └── store.js
│ │ └── styles
│ │ │ ├── AddUser.css
│ │ │ ├── managesign.css
│ │ │ ├── opensigndrive.css
│ │ │ ├── quill.css
│ │ │ └── signature.css
│ ├── tailwind.config.js
│ └── vite.config.js
├── OpenSignServer
│ ├── .dockerignore
│ ├── .ebextensions
│ │ └── app.config
│ ├── .eslintrc.json
│ ├── .github
│ │ └── workflows
│ │ │ └── ci.yml
│ ├── .gitignore
│ ├── .nycrc
│ ├── .prettierrc
│ ├── CODE_OF_CONDUCT.md
│ ├── Dockerhubfile
│ ├── Utils.js
│ ├── app.json
│ ├── app.yaml
│ ├── auth
│ │ └── authadapter.js
│ ├── cloud
│ │ ├── customRoute
│ │ │ ├── customApp.js
│ │ │ └── uploadFile.js
│ │ ├── main.js
│ │ └── parsefunction
│ │ │ ├── AddAdmin.js
│ │ │ ├── AuthLoginAsMail.js
│ │ │ ├── CheckAdminExist.js
│ │ │ ├── ContactBookAftersave.js
│ │ │ ├── DocumentAfterFind.js
│ │ │ ├── DocumentAftersave.js
│ │ │ ├── DocumentBeforesave.js
│ │ │ ├── ForwardDoc.js
│ │ │ ├── GetLogoByDomain.js
│ │ │ ├── GetTemplate.js
│ │ │ ├── Newsletter.js
│ │ │ ├── SendMailOTPv1.js
│ │ │ ├── SignatureAfterFind.js
│ │ │ ├── TeamsAftersave.js
│ │ │ ├── TemplateAfterFind.js
│ │ │ ├── TemplateAfterSave.js
│ │ │ ├── TemplateBeforesave.js
│ │ │ ├── TenantAfterFind.js
│ │ │ ├── UpdateExistUserAsAdmin.js
│ │ │ ├── UserAfterFInd.js
│ │ │ ├── VerifyEmail.js
│ │ │ ├── addUser.js
│ │ │ ├── createBatchContact.js
│ │ │ ├── createBatchDocs.js
│ │ │ ├── createDuplicate.js
│ │ │ ├── declinedocument.js
│ │ │ ├── editContact.js
│ │ │ ├── fileUpload.js
│ │ │ ├── filterDocs.js
│ │ │ ├── generateCertificatebydocId.js
│ │ │ ├── getContact.js
│ │ │ ├── getDocument.js
│ │ │ ├── getDrive.js
│ │ │ ├── getReport.js
│ │ │ ├── getSignedUrl.js
│ │ │ ├── getSigners.js
│ │ │ ├── getTeams.js
│ │ │ ├── getTenant.js
│ │ │ ├── getUserDetails.js
│ │ │ ├── getUserId.js
│ │ │ ├── getUserListByOrg.js
│ │ │ ├── isUserInContactBook.js
│ │ │ ├── isextenduser.js
│ │ │ ├── linkContactToDoc.js
│ │ │ ├── loginUser.js
│ │ │ ├── pdf
│ │ │ ├── GenerateCertificate.js
│ │ │ ├── PDF.js
│ │ │ ├── PDFArrayCustom.js
│ │ │ └── Placeholder.js
│ │ │ ├── recreateDocument.js
│ │ │ ├── reportsJson.js
│ │ │ ├── saveAsTemplate.js
│ │ │ ├── saveFile.js
│ │ │ ├── savecontact.js
│ │ │ ├── sendMailGmailProvider.js
│ │ │ ├── sendMailv3.js
│ │ │ ├── updateContactTour.js
│ │ │ ├── updatePreferences.js
│ │ │ ├── updateTenant.js
│ │ │ ├── updateTourStatus.js
│ │ │ ├── updatesignaturetype.js
│ │ │ └── usersignup.js
│ ├── databases
│ │ ├── migrations
│ │ │ ├── 20231110174122-update_setclp.cjs
│ │ │ ├── 20231220171155-create_template_cls.cjs
│ │ │ ├── 20240110100110-update_document_cls_cjs.cjs
│ │ │ ├── 20240306123606-add_fields_contracts_users_cjs.cjs
│ │ │ ├── 20240408133151-update_contracts_document_cls.cjs
│ │ │ ├── 20240521184801-update_contracts_document_cls_cjs.cjs
│ │ │ ├── 20240527194216-update_contracts_template_cls_cjs.cjs
│ │ │ ├── 20240701151539-update_contracts_users_cls_cjs.cjs
│ │ │ ├── 20240708200454-create_multiuser_classes.cjs
│ │ │ ├── 20240710163936-addfield_declinereason_doc_cls.cjs
│ │ │ ├── 20240723162947-update_teams_org_clp.cjs
│ │ │ ├── 20240726114557-update_contracts_template_cjs.cjs
│ │ │ ├── 20240806141611-update_contracts_users_cjs.cjs
│ │ │ ├── 20240822201043-addfield_doccls_cjs.cjs
│ │ │ ├── 20240903170628-update_contracts_document_cls_cjs.cjs
│ │ │ ├── 20240913121404-add_isenableotp_doc.cjs
│ │ │ ├── 20240926163209-add_istourenabled_doc_cjs.cjs
│ │ │ ├── 20241004104551-fileadapterId_doccls.cjs
│ │ │ ├── 20241106180102-add_signaturetype_field.cjs
│ │ │ ├── 20241114175425-add_notifyonsignatures_field.cjs
│ │ │ ├── 20241205115937-add_bcc_field_cjs.cjs
│ │ │ ├── 20241205163817-add_redirecturl_field_cjs.cjs
│ │ │ ├── 20241227112339-update_contracts_document_cls_cjs.cjs
│ │ │ ├── 20241227125916-update_contracts_template_cls_cjs.cjs
│ │ │ ├── 20250411095519-add_templateid_field.cjs
│ │ │ ├── 20250424104819-change_permission.cjs
│ │ │ └── 20250427105912-add_name_field_user_cls.cjs
│ │ └── seeders
│ │ │ └── .gitkeep
│ ├── exports
│ │ └── .gitkeep
│ ├── files
│ │ ├── custom_email.html
│ │ ├── custom_email.txt
│ │ ├── custom_email_subject.txt
│ │ ├── password_reset_email.html
│ │ ├── password_reset_email.txt
│ │ ├── password_reset_email_subject.txt
│ │ ├── verification_email.html
│ │ ├── verification_email.txt
│ │ └── verification_email_subject.txt
│ ├── font
│ │ └── times.ttf
│ ├── index.js
│ ├── jsconfig.json
│ ├── logo.png
│ ├── migrationdb
│ │ └── createContactIndex.js
│ ├── openshift.json
│ ├── package-lock.json
│ ├── package.json
│ ├── pdfFile
│ │ ├── emudhra-test-class2.pfx
│ │ └── sample.pdf
│ ├── public
│ │ ├── assets
│ │ │ ├── css
│ │ │ │ └── style.css
│ │ │ ├── images
│ │ │ │ └── parse-logo.png
│ │ │ └── js
│ │ │ │ └── script.js
│ │ ├── openapi.json
│ │ └── test.html
│ ├── scalingo.json
│ └── spec
│ │ ├── .eslintrc.json
│ │ ├── Tests.spec.js
│ │ ├── helper.js
│ │ ├── support
│ │ └── jasmine.json
│ │ └── utils
│ │ └── test-runner.js
├── localstack
│ └── localstack-script.sh
└── mongo
│ └── Dockerfile
├── cert
├── local-dev_base64_pfx
├── local_dev.crt
├── local_dev.key
└── local_dev.pfx
├── docker-compose.yml
├── package-lock.json
└── package.json
/.cz.toml:
--------------------------------------------------------------------------------
1 | [tool.commitizen]
2 | version = "0.1.0" # This should be your current semver version
3 | version_files = [
4 | "package.json:\"version\":",
5 | "package-lock.json:\"version\":",
6 | ]
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:react/recommended",
9 | "plugin:react-hooks/recommended"
10 | ],
11 | "parserOptions": {
12 | "ecmaFeatures": {
13 | "jsx": true
14 | },
15 | "ecmaVersion": "latest",
16 | "sourceType": "module"
17 | },
18 | "plugins": ["react"],
19 | "rules": {
20 | "react/prop-types": 0,
21 | "no-unused-vars": 0,
22 | "no-empty": 0,
23 | "no-case-declarations": 0,
24 | "react/no-deprecated": 0,
25 | "no-undef": 0
26 | },
27 | "ignorePatterns": ["**/build/**", "**/*.config.js"],
28 | "settings": {
29 | "react": {
30 | "version": "detect"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: "Bug Report"
2 | labels: ["bug","up-for-grabs"]
3 | title: "[Bug]: "
4 | assignees:
5 | - andrew-opensignlabs
6 | description: Create a bug report to help us make OpenSign™ the world's best document e-signature platform
7 | body:
8 | - type: textarea
9 | attributes:
10 | label: Issue Description
11 | description: Please provide a clear & concise description of the problem.
12 | - type: textarea
13 | attributes:
14 | label: Expected Behavior
15 | description: Describe what you expected to happen.
16 | - type: textarea
17 | attributes:
18 | label: Current Behavior
19 | description: Describe what is happening instead.
20 | - type: textarea
21 | attributes:
22 | label: Steps to reproduce
23 | description: Please provide step-by-step instructions to reproduce the issue. Include code snippets, URLs, error messages and any other relevant information.
24 | - type: textarea
25 | attributes:
26 | label: Screenshots of the issue(optional)
27 | description: Add screenshots to better explain the issue.
28 | - type: input
29 | attributes:
30 | label: Operating System [e.g. MacOS Sonoma 14.1, Windows 11]
31 | - type: dropdown
32 | id: browsers
33 | attributes:
34 | label: What browsers are you seeing the problem on?
35 | multiple: true
36 | options:
37 | - Chrome
38 | - Firefox
39 | - Safari
40 | - Microsoft Edge
41 | default: 0
42 | - type: input
43 | attributes:
44 | label: What version of OpenSign™ are you seeing this issue on? [e.g. 1.0.6]
45 | validations:
46 | required: true
47 | - type: dropdown
48 | id: environment
49 | attributes:
50 | label: What environment are you seeing the problem on?
51 | multiple: true
52 | options:
53 | - Production (app.opensignlabs.com)
54 | - Staging (staging-app.opensignlabs.com)
55 | - Hosted (app.yourdomain.com)
56 | - Dev (localhost or vercel)
57 | - type: checkboxes
58 | attributes:
59 | label: Please check the boxes that apply to this issue report.
60 | options:
61 | - label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
62 | validations:
63 | required: true
64 | - type: checkboxes
65 | id: terms
66 | attributes:
67 | label: Code of Conduct
68 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://www.opensignlabs.com)
69 | options:
70 | - label: I agree to follow this project's Code of Conduct
71 | required: true
72 | - label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
73 | required: true
74 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Suggest an idea for OpenSign™
3 | title: "Feature Request: [Short Description]"
4 | labels: [feature request, needs triage]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | ## Thanks for taking the time to fill out this feature request!
10 |
11 | - type: input
12 | id: title
13 | attributes:
14 | label: Feature Title
15 | description: What would you call this feature?
16 | placeholder: e.g., Advanced Signature Verification
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | id: feature-description
22 | attributes:
23 | label: Feature Description
24 | description: |
25 | Please provide a detailed description of the feature you're proposing.
26 | placeholder: |
27 | e.g., I'm proposing an advanced signature verification feature that...
28 | validations:
29 | required: true
30 | - type: dropdown
31 | id: featuretype
32 | attributes:
33 | label: What type of feature are you requesting?
34 | multiple: true
35 | options:
36 | - UI/UX Improvement
37 | - Security / Compliance
38 | - Performance / Optimization
39 | - 3rd party integration
40 | - Other
41 | - type: dropdown
42 | id: importance
43 | attributes:
44 | label: Importance
45 | description: How important is this feature to you?
46 | options:
47 | - Critical
48 | - High
49 | - Medium
50 | - Low
51 | validations:
52 | required: true
53 |
54 | - type: textarea
55 | id: additional-context
56 | attributes:
57 | label: Additional Context
58 | description: Any other context or screenshots about the feature request here.
59 | placeholder: Additional details, examples, or screenshots...
60 |
61 | - type: checkboxes
62 | id: terms
63 | attributes:
64 | label: Code of Conduct
65 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://www.opensignlabs.com)
66 | options:
67 | - label: I agree to follow this project's Code of Conduct
68 | required: true
69 | - label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
70 | required: true
71 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | # maintain dependencies for frontend
9 | - package-ecosystem: "npm" # See documentation for possible values
10 | directory: "/apps/OpenSign" # Location of package manifests
11 | schedule:
12 | interval: "weekly"
13 | # maintain dependencies for server
14 | - package-ecosystem: "npm" # See documentation for possible values
15 | directory: "/apps/OpenSignServer" # Location of package manifests
16 | schedule:
17 | interval: "weekly"
18 | # maintain dependencies for microfrontends
19 | - package-ecosystem: "npm" # See documentation for possible values
20 | directory: "microfrontends/SignDocuments" # Location of package manifests
21 | schedule:
22 | interval: "weekly"
23 |
--------------------------------------------------------------------------------
/.github/workflows/Docker.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | # 👇 add this block
4 | permissions:
5 | contents: read # allow checkout & metadata-action to read repo
6 | id-token: write # needed by docker/metadata-action v4
7 |
8 | on:
9 | push:
10 | branches:
11 | - 'main'
12 | - 'staging'
13 |
14 | jobs:
15 | docker:
16 | runs-on: ubuntu-latest
17 | strategy:
18 | matrix:
19 | include:
20 | - image: opensign/opensign
21 | dockerfile: apps/OpenSign/Dockerhubfile
22 | - image: opensign/opensignserver
23 | dockerfile: apps/OpenSignServer/Dockerhubfile
24 | steps:
25 | -
26 | name: Checkout
27 | uses: actions/checkout@v3
28 | -
29 | name: Login to Docker Hub
30 | uses: docker/login-action@v2
31 | with:
32 | username: ${{ secrets.DOCKERHUB_USERNAME }}
33 | password: ${{ secrets.DOCKERHUB_TOKEN }}
34 | -
35 | name: Extract metadata (tags, labels) for Docker
36 | id: meta
37 | uses: docker/metadata-action@v4
38 | with:
39 | images: ${{ matrix.image }}
40 | -
41 | name: Debug - List files opensign
42 | run: ls -R apps/OpenSign/ # Adjust the path as needed
43 | -
44 | name: Debug - List files opensignserver
45 | run: ls -R apps/OpenSignServer/ # Adjust the path as needed
46 | -
47 | name: Build and push
48 | uses: docker/build-push-action@v4
49 | with:
50 | context: .
51 | file: ${{ matrix.dockerfile }}
52 | push: true
53 | tags: ${{ steps.meta.outputs.tags }}
54 | labels: ${{ steps.meta.outputs.labels }}
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .env
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 | apps/OpenSign/public/mfbuild/*
26 | microfrontends/SignDocuments/build/*
27 | apps/OpenSignServer/files/files/*
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npm run lint-staged-changes
5 |
--------------------------------------------------------------------------------
/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.js": "prettier --write"
3 | }
4 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | public/
3 | build/
4 | package.json
5 | package-lock.json
6 | dist/
7 | docs/
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": true,
3 | "semi": true,
4 | "trailingComma": "none",
5 | "printWidth": 80,
6 | "tabWidth": 2
7 | }
8 |
--------------------------------------------------------------------------------
/Caddyfile:
--------------------------------------------------------------------------------
1 | {$HOST_URL} {
2 | reverse_proxy client:3000
3 | handle_path /api/* {
4 | reverse_proxy server:8080
5 | rewrite * {uri}
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/INSTALLATION.md:
--------------------------------------------------------------------------------
1 |
2 | # INSTALLATON INSTRUCTIONS HAS A NEW HOME
3 |
4 | We've updated our installation instructions and moved them to our dedicated documentation portal to provide you with a better experience and updated guidance. Whether you're looking to self-host OpenSign™ or contribute to its development, you can find detailed instructions tailored to your needs at [docs.opensignlabs.com](https://docs.opensignlabs.com).
5 |
6 | ## Self Hosting
7 |
8 | If you're interested in self-hosting OpenSign™, our new documentation portal provides comprehensive, step-by-step instructions to help you set up OpenSign™ in your own environment. This section is designed for system administrators and those looking to deploy OpenSign™ within their organization or for personal use.
9 |
10 | - **Access Self Hosting Instructions:** [Self Hosting Guide](https://docs.opensignlabs.com/docs/category/docker)
11 |
12 | ## Contributors
13 |
14 | For developers and contributors who are looking to build upon or contribute to OpenSign™, we've prepared a separate section that covers the setup, development environment configuration, and guidelines for contributing to the OpenSign™ project.
15 |
16 | - **Access Contributor Instructions:** [Contributors Guide](https://docs.opensignlabs.com/docs/contribute/INSTALLATION)
17 |
18 | ## Additional Resources
19 |
20 | Should you need further assistance or have any questions, please feel free to reach out to us through our support channels:
21 |
22 | - **Twitter:** [OpenSignHQ on Twitter](https://twitter.com/OpenSignHQ)
23 | - **Facebook:** [OpenSign on Facebook](https://www.facebook.com/profile.php?id=61551030403669)
24 | - **LinkedIn:** [OpenSign™ on LinkedIn](https://www.linkedin.com/company/opensign%E2%84%A2/)
25 | - **Discord:** [Join our Discord Community](https://discord.com/invite/opensign)
26 | - **YouTube:** [OpenSignHQ on YouTube](https://www.youtube.com/@opensignhq)
27 |
28 | We are committed to providing you with the support you need to successfully install and use OpenSign™. Visit our website at [www.opensignlabs.com](https://www.opensignlabs.com) for more information about our project and its features.
29 |
30 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | build:
2 | @echo "Building with HOST_URL=${HOST_URL}"
3 | cp .env.local_dev .env
4 | cd apps/OpenSign && cp ../../.env.local_dev .env && npm install && npm run build
5 | HOST_URL=${HOST_URL} docker compose up --build --force-recreate
6 |
7 | run:
8 | @echo "Building with HOST_URL=${HOST_URL}"
9 | cp .env.local_dev .env
10 | docker compose up -d
11 |
--------------------------------------------------------------------------------
/USAGE.md:
--------------------------------------------------------------------------------
1 | Please visit the official documentation [here](https://docs.opensignlabs.com).
--------------------------------------------------------------------------------
/apps/OpenSign/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env", "@babel/preset-react"]
3 | }
--------------------------------------------------------------------------------
/apps/OpenSign/.cz.toml:
--------------------------------------------------------------------------------
1 | [tool.commitizen]
2 | version = "0.1.0" # This should be your current semver version
3 | version_files = [
4 | "package.json:\"version\":",
5 | "package-lock.json:\"version\":",
6 | ]
--------------------------------------------------------------------------------
/apps/OpenSign/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/apps/OpenSign/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:react/recommended",
9 | "plugin:react-hooks/recommended"
10 | ],
11 | "parserOptions": {
12 | "ecmaFeatures": {
13 | "jsx": true
14 | },
15 | "ecmaVersion": "latest",
16 | "sourceType": "module"
17 | },
18 | "plugins": ["react"],
19 | "rules": {
20 | "react/prop-types": 0,
21 | "no-unused-vars": 1
22 | },
23 | "ignorePatterns": ["**/build/**", "**/*.config.js"],
24 | "settings": {
25 | "react": {
26 | "version": "detect"
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/apps/OpenSign/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 | /mfbuild
14 |
15 | # misc
16 | .env
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
--------------------------------------------------------------------------------
/apps/OpenSign/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx eslint '**/*.{js,jsx}'
5 | npx pretty-quick --staged '**/*.{js,jsx}'
--------------------------------------------------------------------------------
/apps/OpenSign/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | public/
3 | build/
4 | package.json
5 | package-lock.json
6 | dist/
7 | docs/
--------------------------------------------------------------------------------
/apps/OpenSign/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": true,
3 | "semi": true,
4 | "trailingComma": "none",
5 | "printWidth": 80,
6 | "tabWidth": 2
7 | }
8 |
--------------------------------------------------------------------------------
/apps/OpenSign/Dockerhubfile:
--------------------------------------------------------------------------------
1 | # Use an official Node runtime as the base image
2 | FROM node:22.14.0
3 |
4 | # Set the working directory inside the container
5 | WORKDIR /usr/src/app
6 |
7 | # Copy package.json and package-lock.json first to leverage Docker cache
8 | COPY apps/OpenSign/package*.json ./
9 |
10 | # Install application dependencies
11 | RUN npm install
12 |
13 | # Copy the current directory contents into the container
14 | COPY apps/OpenSign/ .
15 | COPY apps/OpenSign/.husky .
16 | COPY apps/OpenSign/entrypoint.sh .
17 |
18 | # make the entrypoint.sh file executable
19 | RUN chmod +x entrypoint.sh
20 |
21 | # Define environment variables if needed
22 | ENV NODE_ENV=production
23 | ENV GENERATE_SOURCEMAP=false
24 | # build
25 | RUN npm run build
26 |
27 | # Inject env.js loader into index.html
28 | RUN sed -i '/
/a\' build/index.html
29 |
30 | # Make port 3000 available to the world outside this container
31 | EXPOSE 3000
32 |
33 | ENTRYPOINT ["./entrypoint.sh"]
34 |
35 | # Run the application
36 | CMD ["npm", "start"]
37 |
--------------------------------------------------------------------------------
/apps/OpenSign/README.md:
--------------------------------------------------------------------------------
1 | # Open Sign
2 |
3 | Open source is true platform to sign pdf with digital signature
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm run build`
18 |
19 | Builds the app for production to the `build` folder.\
20 | It correctly bundles React in production mode and optimizes the build for the best performance.
21 |
22 | The build is minified and the filenames include the hashes.\
23 | Your app is ready to be deployed!
24 |
25 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
26 |
--------------------------------------------------------------------------------
/apps/OpenSign/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@babel/preset-env", "@babel/preset-react"]
3 | };
4 |
--------------------------------------------------------------------------------
/apps/OpenSign/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ENV_FILE=./build/env.js
4 | DOTENV_FILE=./.env.prod # ✅ use .env.prod
5 |
6 | echo "Generating runtime env file at $ENV_FILE..."
7 |
8 | echo "window.RUNTIME_ENV = {" > $ENV_FILE
9 |
10 | # List of keys to include
11 | RUNTIME_KEYS="REACT_APP_SERVERURL"
12 |
13 | for key in $RUNTIME_KEYS; do
14 | # First check docker env (-e), fallback to .env file
15 | value=$(printenv "$key")
16 |
17 | if [ -z "$value" ] && [ -f "$DOTENV_FILE" ]; then
18 | # fallback: read from .env
19 | value=$(grep "^$key=" "$DOTENV_FILE" | cut -d '=' -f2- | tr -d '\r\n' | sed 's/"/\\"/g')
20 | else
21 | value=$(echo "$value" | sed 's/"/\\"/g')
22 | fi
23 |
24 | echo " $key: \"$value\"," >> $ENV_FILE
25 | done
26 |
27 | echo "};" >> $ENV_FILE
28 |
29 | exec "$@"
30 |
--------------------------------------------------------------------------------
/apps/OpenSign/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 | ...Loading
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/apps/OpenSign/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {}
5 | }
6 | };
7 |
--------------------------------------------------------------------------------
/apps/OpenSign/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/public/favicon.ico
--------------------------------------------------------------------------------
/apps/OpenSign/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/public/logo192.png
--------------------------------------------------------------------------------
/apps/OpenSign/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/public/logo512.png
--------------------------------------------------------------------------------
/apps/OpenSign/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Open sign",
3 | "name": "Open sign",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/apps/OpenSign/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/apps/OpenSign/public/static/js/assets/images/logo.2a7bff0c1189183fafe71d7d5b94e0cd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/public/static/js/assets/images/logo.2a7bff0c1189183fafe71d7d5b94e0cd.png
--------------------------------------------------------------------------------
/apps/OpenSign/public/version.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/public/version.txt
--------------------------------------------------------------------------------
/apps/OpenSign/setuptest.js:
--------------------------------------------------------------------------------
1 | import "@testing-library/jest-dom";
2 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/assets/images/dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/src/assets/images/dp.png
--------------------------------------------------------------------------------
/apps/OpenSign/src/assets/images/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/src/assets/images/folder.png
--------------------------------------------------------------------------------
/apps/OpenSign/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/src/assets/images/logo.png
--------------------------------------------------------------------------------
/apps/OpenSign/src/assets/images/pdf3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/src/assets/images/pdf3.png
--------------------------------------------------------------------------------
/apps/OpenSign/src/assets/images/recreatedoc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSign/src/assets/images/recreatedoc.png
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import Package from "../../package.json";
3 | import axios from "axios";
4 | import { openInNewTab } from "../constant/Utils";
5 | import { useTranslation } from "react-i18next";
6 | const Footer = () => {
7 | const appName = "OpenSign™";
8 | const { t } = useTranslation();
9 | const [showButton, setShowButton] = useState(false);
10 | const [version, setVersion] = useState("");
11 | useEffect(() => {
12 | axios
13 | .get("/version.txt")
14 | .then((response) => {
15 | setVersion(response.data); // Set the retrieved data to the state variable
16 | })
17 | .catch((error) => {
18 | console.error("Error reading the file:", error);
19 | });
20 | }, []);
21 |
22 | const handleScroll = () => {
23 | if (window.pageYOffset >= 50) {
24 | setShowButton(true);
25 | } else {
26 | setShowButton(false);
27 | }
28 | };
29 |
30 | const scrollToTop = () => {
31 | window.scrollTo(0, 0);
32 | setShowButton(false);
33 | };
34 |
35 | useEffect(() => {
36 | window.addEventListener("scroll", handleScroll);
37 |
38 | return () => {
39 | window.removeEventListener("scroll", handleScroll);
40 | };
41 | }, []);
42 |
43 | const openUrl = () => {
44 | openInNewTab(
45 | "https://github.com/OpenSignLabs/OpenSign/releases/tag/" + version
46 | );
47 | };
48 | return (
49 | <>
50 |
61 |
69 | >
70 | );
71 | };
72 |
73 | export default Footer;
74 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/FullScreenButton.jsx:
--------------------------------------------------------------------------------
1 | // FullScreenButton.js
2 | import React, { useState, useEffect } from "react";
3 |
4 | const FullScreenButton = () => {
5 | const [isFullScreen, setIsFullScreen] = useState(false);
6 |
7 | useEffect(() => {
8 | document.addEventListener("fullscreenchange", handleFullScreenChange);
9 | document.addEventListener("webkitfullscreenchange", handleFullScreenChange);
10 | document.addEventListener("mozfullscreenchange", handleFullScreenChange);
11 | document.addEventListener("MSFullscreenChange", handleFullScreenChange);
12 |
13 | return () => {
14 | document.removeEventListener("fullscreenchange", handleFullScreenChange);
15 | document.removeEventListener(
16 | "webkitfullscreenchange",
17 | handleFullScreenChange
18 | );
19 | document.removeEventListener(
20 | "mozfullscreenchange",
21 | handleFullScreenChange
22 | );
23 | document.removeEventListener(
24 | "MSFullscreenChange",
25 | handleFullScreenChange
26 | );
27 | };
28 | }, []);
29 |
30 | const handleFullScreenChange = () => {
31 | setIsFullScreen(!!document.fullscreenElement);
32 | };
33 |
34 | const toggleFullScreen = () => {
35 | if (isFullScreen) {
36 | exitFullScreen();
37 | } else {
38 | requestFullScreen();
39 | }
40 | };
41 |
42 | const requestFullScreen = () => {
43 | if (document.documentElement.requestFullscreen) {
44 | document.documentElement.requestFullscreen();
45 | } else if (document.documentElement.mozRequestFullScreen) {
46 | document.documentElement.mozRequestFullScreen();
47 | } else if (document.documentElement.webkitRequestFullscreen) {
48 | document.documentElement.webkitRequestFullscreen();
49 | } else if (document.documentElement.msRequestFullscreen) {
50 | document.documentElement.msRequestFullscreen();
51 | }
52 | };
53 |
54 | const exitFullScreen = () => {
55 | if (document.exitFullscreen) {
56 | document.exitFullscreen();
57 | } else if (document.mozCancelFullScreen) {
58 | document.mozCancelFullScreen();
59 | } else if (document.webkitExitFullscreen) {
60 | document.webkitExitFullscreen();
61 | } else if (document.msExitFullscreen) {
62 | document.msExitFullscreen();
63 | }
64 | };
65 |
66 | return (
67 |
68 |
78 |
79 | );
80 | };
81 |
82 | export default FullScreenButton;
83 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/RotateAlert.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ModalUi from "../primitives/ModalUi";
3 | import { useTranslation } from "react-i18next";
4 |
5 | function RotateAlert(props) {
6 | const { t } = useTranslation();
7 | return (
8 | props.setShowRotateAlert({ status: false, degree: 0 })}
12 | >
13 |
14 |
{t("rotate-alert-mssg")}
15 |
16 |
17 |
24 |
33 |
34 |
35 |
36 | );
37 | }
38 |
39 | export default RotateAlert;
40 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/SocialMedia.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { NavLink } from "react-router";
4 |
5 | const SocialMedia = () => {
6 | const { t } = useTranslation();
7 |
8 | return (
9 |
10 |
15 |
16 |
17 | OpenSign's {t("social-media.github")}
18 |
19 |
20 |
25 |
26 |
27 | OpenSign's {t("social-media.linked-in")}
28 |
29 |
30 |
35 |
36 |
37 | OpenSign's {t("social-media.twitter")}
38 |
39 |
40 |
45 |
46 |
47 | OpenSign's {t("social-media.discord")}
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | export default SocialMedia;
55 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/Title.jsx:
--------------------------------------------------------------------------------
1 | import { Helmet } from "react-helmet";
2 |
3 | function Title({ title, drive }) {
4 | const appName =
5 | "OpenSign™";
6 | return (
7 |
8 | {drive ? title : `${title} - ${appName}`}
9 |
10 |
16 |
17 | );
18 | }
19 |
20 | export default Title;
21 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/dashboard/DashboardButton.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useNavigate } from "react-router";
3 | import { openInNewTab } from "../../constant/Utils";
4 | import { useTranslation } from "react-i18next";
5 |
6 | const DashboardButton = (props) => {
7 | const navigate = useNavigate();
8 | const { t } = useTranslation();
9 |
10 | function openReport() {
11 | if (props.Data && props.Data.Redirect_type) {
12 | const Redirect_type = props.Data.Redirect_type;
13 | const id = props.Data.Redirect_id;
14 | if (Redirect_type === "Form") {
15 | navigate(`/form/${id}`);
16 | } else if (Redirect_type === "Report") {
17 | navigate(`/report/${id}`);
18 | } else if (Redirect_type === "Url") {
19 | openInNewTab(id);
20 | }
21 | }
22 | }
23 | return (
24 | openReport()}
26 | className={`${
27 | props.Data && props.Data.Redirect_type
28 | ? "cursor-pointer"
29 | : "cursor-default"
30 | } w-full shadow-md px-3 py-2 op-card bg-base-100`}
31 | >
32 |
33 |
34 |
35 |
40 |
41 |
42 |
43 | {t(`sidebar.${props.Label}`)}
44 | {props.Label === "Sign yourself" && (
45 |
46 | {t("signyour-self-button")}
47 |
48 | )}
49 | {props.Label === "Request signatures" && (
50 |
51 | {t("requestsign-button")}
52 |
53 | )}
54 |
55 |
56 |
57 | );
58 | };
59 |
60 | export default DashboardButton;
61 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/AddRoleModal.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ModalUi from "../../primitives/ModalUi";
3 | import { useTranslation } from "react-i18next";
4 |
5 | const AddRoleModal = (props) => {
6 | const { t } = useTranslation();
7 | return (
8 |
13 |
43 |
44 | );
45 | };
46 |
47 | export default AddRoleModal;
48 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/BorderResize.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function BorderResize(props) {
4 | const getHeight = () => {
5 | const height = props.posHeight(props.pos, props.isSignYourself);
6 | if (height > 14) {
7 | return "14px";
8 | } else {
9 | return `${height}px`;
10 | }
11 | };
12 |
13 | return (
14 |
23 | );
24 | }
25 |
26 | export default BorderResize;
27 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/DragElement.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { getWidgetType, widgets } from "../../constant/Utils";
3 |
4 | function DragElement(item) {
5 | const getWidgets = widgets;
6 | const filterWidgetPreview = getWidgets.filter(
7 | (data) => data.type === item?.text
8 | );
9 |
10 | return {getWidgetType(filterWidgetPreview[0])}
;
11 | }
12 |
13 | export default DragElement;
14 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/EmailBody.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Tooltip from "../../primitives/Tooltip";
3 | import ReactQuill from "react-quill-new";
4 | import "../../styles/quill.css";
5 | import EditorToolbar, { module1, formats } from "./EditorToolbar";
6 | import { useTranslation } from "react-i18next";
7 |
8 | export function EmailBody(props) {
9 | const { t } = useTranslation();
10 | return (
11 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/PrevNext.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 |
4 | function PrevNext({ pageNumber, allPages, changePage }) {
5 | const { t } = useTranslation();
6 | //for go to previous page
7 | function previousPage() {
8 | changePage(-1);
9 | }
10 | //for go to next page
11 | function nextPage() {
12 | changePage(1);
13 | }
14 |
15 | return (
16 |
17 |
26 |
27 | {pageNumber || (allPages ? 1 : "--")} {t("of")} {allPages || "--"}
28 |
29 |
38 |
39 | );
40 | }
41 |
42 | export default PrevNext;
43 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/SelectLanguage.jsx:
--------------------------------------------------------------------------------
1 | import i18next from "i18next";
2 | import React, { useState } from "react";
3 | import { useTranslation } from "react-i18next";
4 |
5 | function SelectLanguage(props) {
6 | const { i18n } = useTranslation();
7 | const languages = [
8 | { value: "en", text: "English" }, //english
9 | { value: "es", text: "Española" }, //spanish
10 | { value: "fr", text: "Français" }, //french
11 | { value: "it", text: "Italiano" }, //italian
12 | { value: "de", text: "Deutsch" }, //german
13 | { value: "hi", text: "हिन्दी" } //hindi
14 | ];
15 | const defaultLanguage = i18next.language || "en";
16 | const [lang, setLang] = useState(defaultLanguage);
17 | // This function put query that helps to change the language
18 | const handleChangeLang = (e) => {
19 | setLang(e.target.value);
20 | i18n.changeLanguage(e.target.value);
21 | props?.updateExtUser && props.updateExtUser({ language: e.target.value });
22 | };
23 | return (
24 |
29 |
45 |
46 | );
47 | }
48 |
49 | export default SelectLanguage;
50 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/Signedby.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../../styles/signature.css";
3 | import { useTranslation } from "react-i18next";
4 | function Signedby(props) {
5 | const { t } = useTranslation();
6 | const getFirstLetter = (pdfData) => {
7 | const name = props.isSelfSign
8 | ? (pdfData?.Signers && pdfData?.Signers[0]?.Name) || "User"
9 | : pdfData.ExtUserPtr?.Name;
10 | const firstLetter = name.charAt(0);
11 | return firstLetter;
12 | };
13 | return (
14 |
15 |
16 | {props.isSelfSign ? t("user") : t("signed-by")}
17 |
18 |
19 |
20 |
21 |
22 | {getFirstLetter(props.pdfDetails)}
23 |
24 |
25 |
26 |
27 | {props.isSelfSign
28 | ? (props.pdfDetails?.Signers &&
29 | props.pdfDetails?.Signers[0]?.Name) ||
30 | "User"
31 | : props.pdfDetails.ExtUserPtr.Name || "User"}
32 |
33 |
34 | {props.isSelfSign
35 | ? (props.pdfDetails?.Signers &&
36 | props.pdfDetails?.Signers[0]?.Email) ||
37 | ""
38 | : props.pdfDetails.ExtUserPtr.Email || ""}
39 |
40 |
41 |
42 |
43 |
44 | );
45 | }
46 |
47 | export default Signedby;
48 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/SignerListComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { darkenColor, getFirstLetter } from "../../constant/Utils";
3 |
4 | function SignerListComponent(props) {
5 | const checkSignerBackColor = (obj) => {
6 | if (obj) {
7 | let data = "";
8 | if (obj?.Id) {
9 | data = props.signerPos.filter((data) => data.Id === obj.Id);
10 | } else {
11 | data = props.signerPos.filter(
12 | (data) => data.signerObjId === obj.objectId
13 | );
14 | }
15 | return data && data.length > 0 && data[0].blockColor;
16 | }
17 | };
18 | const checkUserNameColor = (obj) => {
19 | const getBackColor = checkSignerBackColor(obj);
20 | if (getBackColor) {
21 | const color = darkenColor(getBackColor, 0.4);
22 | return color;
23 | } else {
24 | return "#abd1d0";
25 | }
26 | };
27 |
28 | return (
29 |
33 |
37 |
38 | {getFirstLetter(
39 | props.obj?.Name || props.obj?.email || props.obj?.Role
40 | )}
41 |
42 |
43 |
44 |
45 | {props.obj?.Name || props?.obj?.Role}
46 |
47 |
48 | {props.obj?.Email || props.obj?.email}
49 |
50 |
51 |
52 | );
53 | }
54 |
55 | export default SignerListComponent;
56 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/SignerListPlace.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import RecipientList from "./RecipientList";
3 | import { Tooltip } from "react-tooltip";
4 | import { useTranslation } from "react-i18next";
5 |
6 | function SignerListPlace(props) {
7 | const { t } = useTranslation();
8 | return (
9 |
10 |
11 |
12 | {props.title ? props.title : "Recipients"}
13 |
14 | {props?.title === "Roles" && (
15 | <>
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
{t("role-help.p1")}
24 |
{t("role-help.p2")}
25 |
{t("role-help.p3")}
26 |
{t("role-help.p4")}
27 |
{t("role-help.p5")}
28 |
{t("role-help.p6")}
29 |
30 |
31 | >
32 | )}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {props.handleAddSigner ? (
41 |
props.handleAddSigner()}
47 | >
48 | {t("add-role")}
49 |
50 | ) : (
51 |
props.setIsAddSigner(true)}
57 | >
58 | {t("add-recipients")}
59 |
60 | )}
61 |
62 |
63 | );
64 | }
65 |
66 | export default SignerListPlace;
67 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/VerifyEmail.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Loader from "../../primitives/Loader";
3 | import { useTranslation } from "react-i18next";
4 |
5 | function VerifyEmail(props) {
6 | const { t } = useTranslation();
7 | return (
8 |
68 | );
69 | }
70 |
71 | export default VerifyEmail;
72 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/pdf/WidgetList.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { getWidgetType, isMobile } from "../../constant/Utils";
3 | import { useTranslation } from "react-i18next";
4 |
5 | function WidgetList(props) {
6 | const { t } = useTranslation();
7 | return props.updateWidgets.map((item, ind) => {
8 | return (
9 |
10 |
{
14 | props.addPositionOfSignature &&
15 | props.addPositionOfSignature("onclick", item);
16 | }}
17 | ref={(element) => !isMobile && item.ref(element)}
18 | onMouseMove={(e) => !isMobile && props?.handleDivClick(e)}
19 | onMouseDown={() => !isMobile && props?.handleMouseLeave()}
20 | onTouchStart={(e) => !isMobile && props?.handleDivClick(e)}
21 | >
22 | {item.ref && getWidgetType(item, t(`widgets-name.${item.type}`))}
23 |
24 |
25 | );
26 | });
27 | }
28 |
29 | export default WidgetList;
30 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/shared/fields/DateFormatSelector.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { formatDateTime } from "../../../constant/Utils";
3 | import { useTranslation } from "react-i18next";
4 |
5 | const DateFormatSelector = (props) => {
6 | const { t } = useTranslation();
7 | const date = new Date();
8 | const [selectedFormat, setSelectedFormat] = useState(props.dateFormat);
9 | const [is12Hour, setIs12Hour] = useState(props?.is12HourTime);
10 |
11 | const dateFormats = [
12 | "MM/DD/YYYY",
13 | "MMMM DD, YYYY",
14 | "DD MMMM, YYYY",
15 | "DD-MM-YYYY",
16 | "DD MMM, YYYY",
17 | "YYYY-MM-DD",
18 | "MM-DD-YYYY",
19 | "MM.DD.YYYY",
20 | "MMM DD, YYYY"
21 | ];
22 |
23 | // Handle format change
24 | const handleFormatChange = (event) => {
25 | setSelectedFormat(event.target.value);
26 | props.setDateFormat && props.setDateFormat(event.target.value);
27 | };
28 | const handleHrInput = () => {
29 | setIs12Hour(!is12Hour);
30 | props.setIs12HourTime && props.setIs12HourTime(!is12Hour);
31 | };
32 | return (
33 |
34 |
37 |
48 |
70 |
71 |
72 | {formatDateTime(date, selectedFormat, props?.timezone, is12Hour)}
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | export default DateFormatSelector;
80 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/shared/fields/TimezoneSelector.jsx:
--------------------------------------------------------------------------------
1 | import { t } from "i18next";
2 | import React, { useState } from "react";
3 | import TimezoneSelect from "react-timezone-select";
4 |
5 | const TimezoneSelector = (props) => {
6 | const [selectedTimezone, setSelectedTimezone] = useState(props?.timezone);
7 | // Intl.DateTimeFormat().resolvedOptions().timeZone // Default to the user's local timezone
8 |
9 | const onChangeTimezone = (timezone) => {
10 | setSelectedTimezone(timezone?.value);
11 | props.setTimezone && props.setTimezone(timezone?.value);
12 | };
13 |
14 | return (
15 | <>
16 |
17 |
18 | {t("select-timezone")}
19 |
20 | onChangeTimezone(timezone)}
23 | unstyled
24 | classNames={{
25 | control: () =>
26 | "op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
27 | valueContainer: () =>
28 | "flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
29 | multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
30 | multiValueLabel: () => "mb-[2px]",
31 | menu: () =>
32 | "mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
33 | menuList: () => "shadow-md rounded-lg overflow-hidden",
34 | option: () =>
35 | "bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
36 | noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
37 | }}
38 | />
39 |
40 | >
41 | );
42 | };
43 |
44 | export default TimezoneSelector;
45 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/components/sidebar/Menu.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { NavLink } from "react-router";
4 |
5 | const Menu = ({ item, isOpen, closeSidebar }) => {
6 | const appName =
7 | "OpenSign™";
8 | const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
9 | const { t } = useTranslation();
10 | return (
11 |
12 |
19 | `${
20 | isActive ? " bg-base-300 text-base-content" : ""
21 | } flex items-center justify-start text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
22 | }
23 | onClick={closeSidebar}
24 | tabIndex={isOpen ? 0 : -1}
25 | role="menuitem"
26 | >
27 |
28 |
29 |
30 |
31 | {t(`sidebar.${item.title}`, { appName: drivename })}
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | export default Menu;
39 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/constant/appinfo.js:
--------------------------------------------------------------------------------
1 | import logo from "../assets/images/logo.png";
2 | import { getEnv } from "./Utils";
3 |
4 | export function serverUrl_fn() {
5 | const env = getEnv();
6 | const serverurl = env?.REACT_APP_SERVERURL
7 | ? env.REACT_APP_SERVERURL // env.REACT_APP_SERVERURL is used for prod
8 | : process.env.REACT_APP_SERVERURL; // process.env.REACT_APP_SERVERURL is used for dev (locally)
9 | let baseUrl = serverurl ? serverurl : window.location.origin + "/api/app";
10 | return baseUrl;
11 | }
12 | export const appInfo = {
13 | applogo: logo,
14 | appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
15 | baseUrl: serverUrl_fn(),
16 | defaultRole: "contracts_User",
17 | fev_Icon:
18 | "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC",
19 | googleClietId: process.env.REACT_APP_GOOGLECLIENTID
20 | ? `${process.env.REACT_APP_GOOGLECLIENTID}`
21 | : "",
22 | metaDescription:
23 | "The fastest way to sign PDFs & request signatures from others.",
24 | settings: [
25 | {
26 | role: "contracts_Admin",
27 | menuId: "VPh91h0ZHk",
28 | pageType: "dashboard",
29 | pageId: "35KBoSgoAK",
30 | extended_class: "contracts_Users"
31 | },
32 | {
33 | role: "contracts_OrgAdmin",
34 | menuId: "VPh91h0ZHk",
35 | pageType: "dashboard",
36 | pageId: "35KBoSgoAK",
37 | extended_class: "contracts_Users"
38 | },
39 | {
40 | role: "contracts_Editor",
41 | menuId: "H9vRfEYKhT",
42 | pageType: "dashboard",
43 | pageId: "35KBoSgoAK",
44 | extended_class: "contracts_Users"
45 | },
46 | {
47 | role: "contracts_User",
48 | menuId: "H9vRfEYKhT",
49 | pageType: "dashboard",
50 | pageId: "35KBoSgoAK",
51 | extended_class: "contracts_Users"
52 | }
53 | ]
54 | };
55 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/constant/const.js:
--------------------------------------------------------------------------------
1 | export const contactCls = "contracts_Contactbook";
2 | export const templateCls = "contracts_Template";
3 | export const documentCls = "contracts_Document";
4 | export const themeColor = "#47a3ad";
5 | export const iconColor = "#686968";
6 | export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
7 | export const maxFileSize = 10; // 10MB
8 | export const maxTitleLength = 250; // 250 characters
9 | export const maxNoteLength = 200; // 200 characters
10 | export const maxDescriptionLength = 500; // 500 characters
11 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/constant/getReplacedHashQuery.js:
--------------------------------------------------------------------------------
1 | import Parse from "parse";
2 | /**
3 | * Function returning the queryString in which multiple hash replaced with actual values
4 | * @param str query string
5 | * @param json localstroage data in json
6 | */
7 |
8 | export default function getReplacedHashQuery(str, json) {
9 | // eslint-disable-next-line
10 | let reg = /(\#.*?\#)/gi;
11 | const currentUser = Parse.User.current();
12 | const multiHash = str.match(reg);
13 |
14 | let values = {};
15 | let key = "";
16 | multiHash.forEach((x) => {
17 | key = x;
18 | key = key.substring(1, key.length - 1);
19 | key = key.split(".");
20 | if (key.length > 1) {
21 | key = x.replace(reg, json[key[0]][key[1]]);
22 | } else if (json[key[0]]) {
23 | key = x.replace(reg, json[key[0]]);
24 | } else if (key[0] === "Date") {
25 | key = x.replace(reg, "Date");
26 | } else if (key[0] === "today") {
27 | key = x.replace(reg, new Date().toISOString());
28 | } else {
29 | key = x.replace(reg, currentUser.id);
30 | }
31 | values = { ...values, [x]: key };
32 | });
33 | const querySplit = str.split(reg);
34 | const replacedHashWithValuesArr = querySplit.map((hash) =>
35 | values[hash] ? values[hash] : hash
36 | );
37 | const HashFreeQuery = replacedHashWithValuesArr.join("");
38 | // console.log("HashFreeQuery ", HashFreeQuery);
39 | return HashFreeQuery;
40 | }
41 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/constant/saveFileSize.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import { serverUrl_fn } from "./appinfo";
3 | const parseAppId = process.env.REACT_APP_APPID
4 | ? process.env.REACT_APP_APPID
5 | : "opensign";
6 | const serverUrl = serverUrl_fn();
7 | export const SaveFileSize = async (size, imageUrl, tenantId) => {
8 | //checking server url and save file's size
9 | const tenantPtr = {
10 | __type: "Pointer",
11 | className: "partners_Tenant",
12 | objectId: tenantId
13 | };
14 | const _tenantPtr = JSON.stringify(tenantPtr);
15 | try {
16 | const res = await axios.get(
17 | `${serverUrl}/classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
18 | {
19 | headers: {
20 | "Content-Type": "application/json",
21 | "X-Parse-Application-Id": parseAppId
22 | }
23 | }
24 | );
25 | const response = res.data.results;
26 | let data;
27 | // console.log("response", response);
28 | if (response && response.length > 0) {
29 | data = {
30 | usedStorage: response[0].usedStorage
31 | ? response[0].usedStorage + size
32 | : size
33 | };
34 | await axios.put(
35 | `${serverUrl}/classes/partners_TenantCredits/${response[0].objectId}`,
36 | data,
37 | {
38 | headers: {
39 | "Content-Type": "application/json",
40 | "X-Parse-Application-Id": parseAppId
41 | }
42 | }
43 | );
44 | } else {
45 | data = { usedStorage: size, PartnersTenant: tenantPtr };
46 | await axios.post(`${serverUrl}/classes/partners_TenantCredits`, data, {
47 | headers: {
48 | "Content-Type": "application/json",
49 | "X-Parse-Application-Id": parseAppId
50 | }
51 | });
52 | }
53 | } catch (err) {
54 | console.log("err in save usage", err);
55 | }
56 | saveDataFile(size, imageUrl, tenantPtr);
57 | };
58 |
59 | //function for save fileUrl and file size in particular client db class partners_DataFiles
60 | const saveDataFile = async (size, imageUrl, tenantPtr) => {
61 | const data = {
62 | FileUrl: imageUrl,
63 | FileSize: size,
64 | TenantPtr: tenantPtr
65 | };
66 |
67 | // console.log("data save",file, data)
68 | try {
69 | await axios.post(`${serverUrl}/classes/partners_DataFiles`, data, {
70 | headers: {
71 | "Content-Type": "application/json",
72 | "X-Parse-Application-Id": parseAppId
73 | }
74 | });
75 | } catch (err) {
76 | console.log("err in save usage ", err);
77 | }
78 | };
79 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/hook/useScript.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | /**`useScript` hook is generated scripte for google sign in button */
4 | export const useScript = (url, onload) => {
5 | useEffect(() => {
6 | const script = document.createElement("script");
7 | //add url parameter to the script src, for load and it will remove after load in return
8 | script.src = url;
9 | script.async = true;
10 | script.defer = true;
11 | script.onload = onload;
12 | document.head.appendChild(script);
13 | return () => {
14 | document.head.removeChild(script);
15 | };
16 | }, [url, onload]);
17 | };
18 |
19 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/hook/useWindowSize.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | export function useWindowSize() {
4 | const [size, setSize] = useState({
5 | width: 0,
6 | height: 0
7 | });
8 |
9 | const onResize = () => {
10 | setSize({
11 | width: window.innerWidth,
12 | height: window.innerHeight
13 | });
14 | };
15 |
16 | useEffect(() => {
17 | onResize();
18 | window.addEventListener("resize", onResize);
19 | return () => {
20 | window.removeEventListener("resize", onResize);
21 | };
22 | }, []);
23 |
24 | return size;
25 | }
26 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/i18n.js:
--------------------------------------------------------------------------------
1 | import i18n from "i18next";
2 | import { initReactI18next } from "react-i18next";
3 | import Backend from "i18next-http-backend";
4 | import LanguageDetector from "i18next-browser-languagedetector";
5 |
6 | i18n
7 | .use(Backend)
8 | .use(LanguageDetector) // Use LanguageDetector directly without creating an instance
9 | .use(initReactI18next)
10 | .init({
11 | backend: {
12 | loadPath: "/locales/{{lng}}/{{ns}}.json"
13 | },
14 | fallbackLng: "en", // Fallback to English if no other language is detected
15 | detection: {
16 | // Specifies the default language to fall back to if the detected language is not available.
17 | order: ["localStorage", "navigator"],
18 | // Defines where the detected language should be cached.
19 | caches: ["localStorage"]
20 | },
21 | ns: ["translation"], // default namespace
22 | defaultNS: "translation", // default namespace
23 | //Enables debug mode, which outputs detailed logs to the console about the translation process.
24 | debug: false,
25 | interpolation: {
26 | escapeValue: false // Not needed for react as it escapes by default
27 | },
28 | whitelist: ["en", "es", "fr", "it", "de", "hi"] // List of allowed languages
29 | });
30 |
31 | export default i18n;
32 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | body {
6 | background-color: white;
7 | }
8 |
9 | /* Custom CSS to hide scrollbar */
10 | .hide-scrollbar::-webkit-scrollbar {
11 | display: none;
12 | }
13 |
14 | .hide-scrollbar {
15 | -ms-overflow-style: none;
16 | /* IE and Edge */
17 | scrollbar-width: none;
18 | /* Firefox */
19 | }
20 | .react-datepicker-popper {
21 | z-index: 9999 !important;
22 | }
23 |
24 | @media screen and (max-width: 766px) {
25 | .reactour__close {
26 | width: 17px !important;
27 | padding-left: 3px !important;
28 | }
29 | }
30 |
31 | /* below css class replace bootstrap background color with daisy */
32 | .op-bg-primary {
33 | @apply bg-primary;
34 | }
35 |
36 | .op-bg-secondary {
37 | @apply bg-secondary;
38 | }
39 |
40 | .op-bg-info {
41 | @apply bg-info;
42 | }
43 |
44 | .op-bg-success {
45 | @apply bg-success;
46 | }
47 |
48 | .op-bg-warning {
49 | @apply bg-warning;
50 | }
51 |
52 | /* below css class replace bootstrap text color with daisy */
53 | .op-text-primary {
54 | @apply text-primary;
55 | }
56 |
57 | .op-text-secondary {
58 | @apply text-secondary;
59 | }
60 |
61 | .op-text-info {
62 | @apply text-info;
63 | }
64 |
65 | .op-text-accent {
66 | @apply text-accent;
67 | }
68 |
69 | .op-text-success {
70 | @apply text-success;
71 | }
72 |
73 | .op-text-warning {
74 | @apply text-warning;
75 | }
76 |
77 | .op-border-primary {
78 | @apply border-primary;
79 | }
80 |
81 | /* CSS for scrollbar customization */
82 | * {
83 | scrollbar-width: thin;
84 | /* For Firefox */
85 | scrollbar-color: gray;
86 | /* For Firefox */
87 | }
88 |
89 | /* For webkit-based browsers like Chrome, Safari */
90 | *::-webkit-scrollbar {
91 | width: 5px;
92 | }
93 |
94 | *::-webkit-scrollbar-track {
95 | background-color: transparent;
96 | }
97 |
98 | *::-webkit-scrollbar-thumb {
99 | background-color: gray;
100 | border-radius: 10px;
101 | }
--------------------------------------------------------------------------------
/apps/OpenSign/src/index.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 | import { Provider } from "react-redux";
6 | import { store } from "./redux/store";
7 | import { HTML5Backend } from "react-dnd-html5-backend";
8 | import { TouchBackend } from "react-dnd-touch-backend";
9 | import {
10 | DndProvider,
11 | TouchTransition,
12 | MouseTransition,
13 | Preview
14 | } from "react-dnd-multi-backend";
15 | import DragElement from "./components/pdf/DragElement.jsx";
16 | import Parse from "parse";
17 | import "./polyfills";
18 | import { serverUrl_fn } from "./constant/appinfo";
19 | import "./i18n";
20 |
21 | const appId =
22 | import.meta.env.VITE_APPID || process.env.REACT_APP_APPID || "opensign";
23 | const serverUrl = serverUrl_fn();
24 | Parse.initialize(appId);
25 | Parse.serverURL = serverUrl;
26 |
27 | const HTML5toTouch = {
28 | backends: [
29 | {
30 | id: "html5",
31 | backend: HTML5Backend,
32 | transition: MouseTransition
33 | },
34 | {
35 | id: "touch",
36 | backend: TouchBackend,
37 | options: { enableMouseEvents: true },
38 | preview: true,
39 | transition: TouchTransition
40 | }
41 | ]
42 | };
43 | const generatePreview = (props) => {
44 | const { item, style } = props;
45 | const newStyle = {
46 | ...style
47 | };
48 |
49 | return (
50 |
51 |
52 |
53 | );
54 | };
55 |
56 |
57 | const root = ReactDOM.createRoot(document.getElementById("root"));
58 | root.render(
59 |
60 |
61 | {generatePreview}
62 |
63 |
64 |
65 | );
66 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/json/FormJson.js:
--------------------------------------------------------------------------------
1 | import { documentCls, templateCls } from "../constant/const";
2 | export const formJson = {
3 | //json form for signYourself
4 | sHAnZphf69: {
5 | title: "Sign Yourself",
6 | redirectRoute: "signaturePdf",
7 | msgVar: "Document",
8 | Cls: documentCls
9 | },
10 |
11 | //json form for request signatures
12 | "8mZzFxbG1z": {
13 | title: "Request Signatures",
14 | msgVar: "Document",
15 | redirectRoute: "placeHolderSign",
16 | Cls: documentCls,
17 | signers: true,
18 | bcc: true
19 | },
20 | //json form for template
21 | template: {
22 | title: "New Template",
23 | redirectRoute: "template",
24 | msgVar: "Template",
25 | Cls: templateCls,
26 | bcc: true
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/pages/Dashboard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import GetDashboard from "../components/dashboard/GetDashboard";
3 | import { useNavigate, useParams } from "react-router";
4 | import Title from "../components/Title";
5 | import { useDispatch } from "react-redux";
6 | import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
7 | import dashboardJson from "../json/dashboardJson";
8 | import Loader from "../primitives/Loader";
9 | import { useTranslation } from "react-i18next";
10 |
11 | const Dashboard = () => {
12 | const { t } = useTranslation();
13 | const navigate = useNavigate();
14 | const dispatch = useDispatch();
15 | const { id } = useParams();
16 | const [dashboard, setdashboard] = useState({});
17 | const [loading, setloading] = useState(true);
18 |
19 | useEffect(() => {
20 | if (localStorage.getItem("accesstoken")) {
21 | if (id !== undefined) {
22 | getDashboard(id);
23 | } else {
24 | getDashboard(localStorage.getItem("PageLanding"));
25 | }
26 | } else {
27 | navigate("/", { replace: true, state: { from: "" } });
28 | }
29 | // eslint-disable-next-line
30 | }, [id]);
31 |
32 | const getDashboard = async (id) => {
33 | try {
34 | const dashboard = dashboardJson.find((x) => x.id === id);
35 | setdashboard(dashboard);
36 | const dashboardTour = dashboard.columns
37 | .filter((col) => {
38 | if (col.widget.data && col.widget.data.tourSection) {
39 | return col;
40 | }
41 | })
42 | .map((col) => {
43 | return {
44 | selector: `[data-tut=${col.widget.data.tourSection}]`,
45 | content: t(`tour-mssg.${col.widget.label}`),
46 | position: "top"
47 | // style: { backgroundColor: "#abd4d2" },
48 | };
49 | });
50 | dispatch(saveTourSteps(dashboardTour));
51 | setloading(false);
52 | } catch (e) {
53 | console.error("Problem", e);
54 | setloading(false);
55 | }
56 | };
57 |
58 | return (
59 |
60 |
61 | {loading ? (
62 |
63 |
64 |
65 | ) : (
66 |
67 | )}
68 |
69 | );
70 | };
71 |
72 | export default Dashboard;
73 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/pages/PageNotFound.jsx:
--------------------------------------------------------------------------------
1 | // NotFound.js
2 | import React from "react";
3 | import Title from "../components/Title";
4 |
5 | const PageNotFound = ({ prefix }) => {
6 | return (
7 |
8 |
9 |
10 |
404
11 |
12 | {prefix ? prefix : "Page"} Not Found
13 |
14 |
15 |
16 | );
17 | };
18 |
19 | export default PageNotFound;
20 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/polyfills.js:
--------------------------------------------------------------------------------
1 | // below code is used to handle undefined Promise.withResolvers for safari
2 | if (typeof Promise.withResolvers === "undefined") {
3 | Promise.withResolvers = function () {
4 | let resolve, reject;
5 | const promise = new Promise((res, rej) => {
6 | resolve = res;
7 | reject = rej;
8 | });
9 | return { promise, resolve, reject };
10 | };
11 | }
12 |
13 | // Usage:
14 | // const { promise, resolve, reject } = Promise.withResolvers()
15 | // console.log(promise, resolve, reject) // Promise { } [Function (anonymous)] [Function (anonymous)]
16 | // ... Do something async and then call resolve or reject!
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/Alert.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Alert = ({ children, type, className }) => {
4 | const textcolor = type ? theme(type) : theme();
5 | function theme(color) {
6 | switch (color) {
7 | case "success":
8 | return "op-alert-success";
9 | case "info":
10 | return "op-alert-info";
11 | case "danger":
12 | return "op-alert-error";
13 | case "warning":
14 | return "op-alert-warning text-black";
15 | default:
16 | return "";
17 | }
18 | }
19 | return (
20 | children && (
21 |
28 |
29 | {children}
30 |
31 |
32 | )
33 | );
34 | };
35 |
36 | export default Alert;
37 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/CheckCircle.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const CheckCircle = ({ size = 56, color = "text-green-500" }) => {
4 | return (
5 |
31 | );
32 | };
33 |
34 | export default CheckCircle;
35 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/DotLottieReact.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { DotLottieReact } from "@lottiefiles/dotlottie-react";
3 | import Loader from "./Loader";
4 | import { useTranslation } from "react-i18next";
5 |
6 | const LottieWithLoader = () => {
7 | const { t } = useTranslation();
8 | const [isLoaded, setIsLoaded] = useState(false);
9 | const [hasError, setHasError] = useState(false);
10 | const [animationSrc, setAnimationSrc] = useState(null);
11 | const src =
12 | "https://lottie.host/00a72a09-f2d4-493a-9b2d-2843bf067638/Ic7jJ44wLJ.json";
13 | useEffect(() => {
14 | fetch(src)
15 | .then((response) => {
16 | if (!response.ok) {
17 | throw new Error("Network response was not ok");
18 | }
19 | return response.blob();
20 | })
21 | .then((blob) => {
22 | const objectURL = URL.createObjectURL(blob);
23 | setAnimationSrc(objectURL);
24 | setIsLoaded(true);
25 | })
26 | .catch((error) => {
27 | console.error("faild to load animation of send request:", error);
28 | setHasError(true);
29 | });
30 | }, [src]);
31 |
32 | return (
33 |
34 | {!isLoaded && !hasError && (
35 |
36 |
37 |
38 | )}
39 | {hasError &&
{t("faild-animation")}
}
40 | {isLoaded && animationSrc && (
41 |
46 | )}
47 |
48 | );
49 | };
50 |
51 | export default LottieWithLoader;
52 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/HandleError.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function HandleError({ handleError }) {
4 | return (
5 |
6 |
7 | {handleError}
8 |
9 |
10 | );
11 | }
12 |
13 | export default HandleError;
14 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/LazyPage.jsx:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from "react";
2 | import Loader from "./Loader";
3 |
4 | const LazyPage = ({ Page }) => {
5 | return (
6 |
9 |
10 |
11 | }
12 | >
13 |
14 |
15 | );
16 | };
17 |
18 | export default LazyPage;
19 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/LinkUserModal.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import SelectSigners from "../components/shared/fields/SelectSigners";
3 | import AddContact from "./AddContact";
4 | import ModalUi from "./ModalUi";
5 | import { useTranslation } from "react-i18next";
6 |
7 | const LinkUserModal = (props) => {
8 | const { t } = useTranslation();
9 | const [isContact, setIsContact] = useState(false);
10 | const [isExistSigner, setIsExistSIgner] = useState(false);
11 |
12 | useEffect(() => {
13 | if (props.uniqueId) {
14 | const isExistSigner = props.signerPos.find(
15 | (x) => x.Id === props.uniqueId && x.signerObjId
16 | );
17 | setIsExistSIgner(isExistSigner);
18 | }
19 | // eslint-disable-next-line react-hooks/exhaustive-deps
20 | }, [props.signerPos]);
21 | return (
22 |
27 |
34 | {isContact && (
35 | <>
36 |
37 | {t("or")}
38 |
39 |
43 | >
44 | )}
45 |
46 | );
47 | };
48 |
49 | export default LinkUserModal;
50 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/Loader.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Loader = () => {
4 | return (
5 |
6 | );
7 | };
8 |
9 | export default Loader;
10 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/LoaderWithMsg.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Loader from "./Loader";
3 |
4 | function LoaderWithMsg({ isLoading }) {
5 | return (
6 |
7 |
8 | {isLoading.message}
9 |
10 | );
11 | }
12 |
13 | export default LoaderWithMsg;
14 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/Modal.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | const Modal = ({ children, Title }) => {
4 | const [isOpen, SetIsOpen] = useState(false);
5 | return (
6 | <>
7 | {children && (
8 |
11 |
12 |
{Title}
13 |
SetIsOpen()}
15 | className="px-2 py-1 bg-gray-400 rounded cursor-pointer"
16 | >
17 |
18 |
19 |
20 |
21 | {isOpen &&
{children}
}
22 |
23 | )}
24 | >
25 | );
26 | };
27 |
28 | export default Modal;
29 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/ModalUi.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../styles/signature.css";
3 |
4 | const ModalUi = ({
5 | children,
6 | title,
7 | isOpen,
8 | handleClose,
9 | showHeader = true,
10 | showClose = true,
11 | reduceWidth,
12 | position
13 | }) => {
14 | const width = reduceWidth;
15 | const isBottom = position === "bottom" ? "items-end pb-2" : "";
16 | return (
17 | <>
18 | {isOpen && (
19 |
48 | )}
49 | >
50 | );
51 | };
52 |
53 | export default ModalUi;
54 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/Tooltip.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Tooltip as ReactTooltip } from "react-tooltip";
3 | import { openInNewTab } from "../constant/Utils";
4 | const Tooltip = ({
5 | id,
6 | message,
7 | url,
8 | iconColor,
9 | maxWidth,
10 | handleOnlickHelp
11 | }) =>
12 | url || handleOnlickHelp ? (
13 |
29 | ) : (
30 | <>
31 |
36 |
37 |
44 |
45 |
46 |
50 | >
51 | );
52 |
53 | export default Tooltip;
54 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/Tour.jsx:
--------------------------------------------------------------------------------
1 | import ReactTour from "reactour";
2 |
3 | export default function Tour({
4 | steps,
5 | isOpen,
6 | rounded,
7 | className,
8 | showNumber,
9 | closeWithMask,
10 | onRequestClose,
11 | showNavigation,
12 | showCloseButton,
13 | showNavigationNumber,
14 | disableKeyboardNavigation
15 | }) {
16 | const radius = rounded || 5;
17 | return (
18 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/TourContentWithBtn.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useTranslation } from "react-i18next";
3 | export default function TourContentWithBtn({ message, isChecked, video }) {
4 | const { t } = useTranslation();
5 | const [isCheck, setIsCheck] = useState(false);
6 |
7 | const handleCheck = () => {
8 | setIsCheck(!isCheck);
9 | if (isChecked) {
10 | isChecked(!isCheck);
11 | }
12 | };
13 | return (
14 |
15 |
{message}
16 | {video && (
17 |
18 |
25 |
26 | )}
27 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/Validate.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Parse from "parse";
3 | import { Outlet, useNavigate, useLocation } from "react-router";
4 | import ModalUi from "./ModalUi";
5 | import { useTranslation } from "react-i18next";
6 | const Validate = () => {
7 | const navigate = useNavigate();
8 | const { t } = useTranslation();
9 | const location = useLocation();
10 | const [isUserValid, setIsUserValid] = useState(true);
11 | useEffect(() => {
12 | (async () => {
13 | if (localStorage.getItem("accesstoken")) {
14 | try {
15 | const userDetails = JSON.parse(
16 | localStorage.getItem(
17 | `Parse/${localStorage.getItem("parseAppId")}/currentUser`
18 | )
19 | );
20 | // Use the session token to validate the user
21 | const userQuery = new Parse.Query(Parse.User);
22 | const user = await userQuery.get(userDetails?.objectId, {
23 | sessionToken: localStorage.getItem("accesstoken")
24 | });
25 | if (user) {
26 | setIsUserValid(true);
27 | } else {
28 | setIsUserValid(false);
29 | }
30 | } catch (error) {
31 | // Session token is invalid or there was an error
32 | setIsUserValid(false);
33 | }
34 | }
35 | })();
36 |
37 | // eslint-disable-next-line react-hooks/exhaustive-deps
38 | }, []);
39 |
40 | const handleLoginBtn = async () => {
41 | try {
42 | await Parse.User.logOut();
43 | } catch (err) {
44 | console.log("err ", err);
45 | } finally {
46 | localStorage.removeItem("accesstoken");
47 | navigate("/", { replace: true, state: { from: location } });
48 | }
49 | };
50 | return isUserValid ? (
51 |
52 |
53 |
54 | ) : (
55 |
56 |
57 |
{t("session-expired")}
58 |
61 |
62 |
63 | );
64 | };
65 |
66 | export default Validate;
67 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/ValidateRoute.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import Parse from "parse";
3 | import { Outlet } from "react-router";
4 | import { saveLanguageInLocal } from "../constant/Utils";
5 | import { useTranslation } from "react-i18next";
6 | const ValidateRoute = () => {
7 | const { i18n } = useTranslation();
8 | useEffect(() => {
9 | (async () => {
10 | if (localStorage.getItem("accesstoken")) {
11 | try {
12 | // Use the session token to validate the user
13 | const userQuery = new Parse.Query(Parse.User);
14 | const user = await userQuery.get(Parse?.User?.current()?.id, {
15 | sessionToken: localStorage.getItem("accesstoken")
16 | });
17 | if (!user) {
18 | handlelogout();
19 | }
20 | } catch (error) {
21 | console.log("err in validate route", error);
22 | handlelogout();
23 | }
24 | }
25 | })();
26 | // eslint-disable-next-line react-hooks/exhaustive-deps
27 | }, []);
28 | const handlelogout = async () => {
29 | let appdata = localStorage.getItem("userSettings");
30 | let applogo = localStorage.getItem("appLogo");
31 | let defaultmenuid = localStorage.getItem("defaultmenuid");
32 | let PageLanding = localStorage.getItem("PageLanding");
33 | let baseUrl = localStorage.getItem("baseUrl");
34 | let appid = localStorage.getItem("parseAppId");
35 |
36 | localStorage.clear();
37 | saveLanguageInLocal(i18n);
38 |
39 | localStorage.setItem("appLogo", applogo);
40 | localStorage.setItem("defaultmenuid", defaultmenuid);
41 | localStorage.setItem("PageLanding", PageLanding);
42 | localStorage.setItem("userSettings", appdata);
43 | localStorage.setItem("baseUrl", baseUrl);
44 | localStorage.setItem("parseAppId", appid);
45 | };
46 | return {}
;
47 | };
48 |
49 | export default ValidateRoute;
50 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/ValidateSession.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import ModalUi from "./ModalUi";
4 | import { useNavigate } from "react-router";
5 | import Parse from "parse";
6 |
7 | const ValidateSession = ({ children }) => {
8 | const { t } = useTranslation();
9 | const navigate = useNavigate();
10 |
11 | const handleLoginBtn = async () => {
12 | try {
13 | await Parse?.User?.logOut();
14 | } catch (err) {
15 | console.log("err ", err);
16 | } finally {
17 | localStorage.removeItem("accesstoken");
18 | navigate("/", { replace: true });
19 | }
20 | };
21 | return localStorage.getItem("accesstoken") ? (
22 | children
23 | ) : (
24 |
25 |
26 |
Your session has expired.
27 |
30 |
31 |
32 | );
33 | };
34 |
35 | export default ValidateSession;
36 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/primitives/sanitizeFileName.js:
--------------------------------------------------------------------------------
1 | function sanitizeFileName(fileName) {
2 | // Remove spaces and invalid characters
3 | const file = fileName?.replace(/[^a-zA-Z0-9._-]/g, "");
4 | const removedot = file?.replace(/\.(?=.*\.)/g, "");
5 | return removedot?.replace(/[^a-zA-Z0-9._-]/g, "");
6 | }
7 | export default sanitizeFileName;
8 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/redux/reducers/ShowTenant.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const showTenantSlice = createSlice({
4 | name: "showTenant",
5 | initialState: "",
6 | reducers: {
7 | showTenant: (state, action) => {
8 | return action.payload;
9 | },
10 | },
11 | });
12 |
13 | export const { showTenant } = showTenantSlice.actions;
14 | export default showTenantSlice.reducer;
--------------------------------------------------------------------------------
/apps/OpenSign/src/redux/reducers/TourStepsReducer.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const tourStepSlice = createSlice({
4 | name: "tourStep",
5 | initialState: [],
6 | reducers: {
7 | saveTourSteps: (state, action) => {
8 | return action.payload;
9 | },
10 | removeTourSteps: () => {
11 | return [];
12 | }
13 | }
14 | });
15 |
16 | export const { saveTourSteps, removeTourSteps } = tourStepSlice.actions;
17 | export default tourStepSlice.reducer;
18 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/redux/reducers/infoReducer.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | import { appInfo } from "../../constant/appinfo";
3 |
4 | const infoSlice = createSlice({
5 | name: "info",
6 | initialState: {},
7 | reducers: {
8 | fetchAppInfo: () => {
9 | localStorage.setItem("baseUrl", `${appInfo.baseUrl}/`);
10 | localStorage.setItem("parseAppId", appInfo.appId);
11 | localStorage.setItem("appLogo", appInfo.applogo);
12 | localStorage.removeItem("userSettings");
13 | localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
14 | localStorage.setItem("fev_Icon", appInfo.fev_Icon);
15 | return appInfo;
16 | }
17 | }
18 | });
19 | export const { fetchAppInfo } = infoSlice.actions;
20 | export default infoSlice.reducer;
21 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/redux/reducers/showHeader.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const showHeaderSlice = createSlice({
4 | name: "showTenant",
5 | initialState: "",
6 | reducers: {
7 | showHeader: (state, action) => {
8 | return action.payload;
9 | }
10 | }
11 | });
12 |
13 | export const { showHeader } = showHeaderSlice.actions;
14 | export default showHeaderSlice.reducer;
15 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/redux/reducers/widgetSlice.js:
--------------------------------------------------------------------------------
1 | // reducers/widgetSlice.js
2 | import { createSlice } from "@reduxjs/toolkit";
3 |
4 | const initialState = {
5 | isShowModal: false,
6 | saveSignCheckbox: {
7 | isVisible: false,
8 | signId: ""
9 | },
10 | signatureTypes: null,
11 | defaultSignImg: null,
12 | myInitial: null,
13 | lastIndex: ""
14 | };
15 |
16 | const widgetSlice = createSlice({
17 | name: "widget",
18 | initialState,
19 | reducers: {
20 | setIsShowModal: (state, action) => {
21 | state.isShowModal = action.payload;
22 | },
23 | setSaveSignCheckbox: (state, action) => {
24 | state.saveSignCheckbox = action.payload;
25 | },
26 | setSignatureTypes: (state, action) => {
27 | state.signatureTypes = action.payload;
28 | },
29 | setDefaultSignImg: (state, action) => {
30 | state.defaultSignImg = action.payload;
31 | },
32 | setMyInitial: (state, action) => {
33 | state.myInitial = action.payload;
34 | },
35 | setLastIndex: (state, action) => {
36 | state.lastIndex = action.payload;
37 | },
38 | resetWidgetState: () => initialState
39 | }
40 | });
41 |
42 | export const {
43 | setIsShowModal,
44 | setSaveSignCheckbox,
45 | setSignatureTypes,
46 | setMyInitial,
47 | resetWidgetState,
48 | setDefaultSignImg,
49 | setLastIndex
50 | } = widgetSlice.actions;
51 |
52 | export default widgetSlice.reducer;
53 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import infoReducer from "./reducers/infoReducer";
3 | import ShowTenant from "./reducers/ShowTenant";
4 | import TourStepsReducer from "./reducers/TourStepsReducer";
5 | import showHeader from "./reducers/showHeader";
6 | import widgetReducer from "./reducers/widgetSlice";
7 |
8 | export const store = configureStore({
9 | reducer: {
10 | appInfo: infoReducer,
11 | TourSteps: TourStepsReducer,
12 | ShowTenant,
13 | showHeader,
14 | widget: widgetReducer
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/apps/OpenSign/src/styles/AddUser.css:
--------------------------------------------------------------------------------
1 | .validationlist {
2 | position: absolute;
3 | left: 0;
4 | z-index: 1;
5 | appearance: none;
6 | -moz-appearance: "none";
7 | -webkit-appearance: "none";
8 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAnUlEQVR4nO2QMQrCQBBFX51NbWMp2uox7Gw8h22uYEguIZNKyB0lMIElTNzdGBvdB8PC8Gces5DJ/Cxn4Aa4QM5pbsgncQF6rQYoZ3IFcPey11jByRsaqzYuctqfZo8xki3QBURuRtDpfBQ74GEsaYHN5It8wYFEhgExlj2NniwRhC7qP70gRSRrCN6JZE2BJZJvCEb2QKVvJvMvvAD2WzaK/35kGAAAAABJRU5ErkJggg==");
9 | background-repeat: no-repeat;
10 | background-position: right 0.7rem top 50%;
11 | background-size: 1rem auto;
12 | }
13 |
14 | @media (max-width: 375px) {
15 | .validationlist {
16 | background-position: right 0.5rem top 50%;
17 | }
18 | }
19 |
20 | @media (min-width:375px) and (max-width: 767px) {
21 | .validationlist {
22 | background-position: right 1rem top 50%;
23 | }
24 | }
25 |
26 | .warning {
27 | position: absolute;
28 | padding: 5px;
29 | border: 1px solid black;
30 | background: white;
31 | width: 250px;
32 | border-radius: 5px;
33 | animation: inAnimation 1s ease-in-out;
34 | z-index: 1;
35 | }
36 |
37 | .defaultvalueWarning {
38 | position: absolute;
39 | left: 20px;
40 | }
41 |
42 | .defaultvalueWarning::before {
43 | content: "";
44 | width: 0px;
45 | height: 0px;
46 | border-style: outset;
47 | border-width: 0px 10px 10px 10px;
48 | border-color: transparent transparent black transparent;
49 | display: inline-block;
50 | position: absolute;
51 | top: -29%;
52 | left: 0;
53 | right: 75%;
54 | margin: 0 auto;
55 | }
56 |
57 | @keyframes inAnimation {
58 | 0% {
59 | opacity: 0;
60 | visibility: hidden;
61 | }
62 |
63 | 25% {
64 | opacity: 1;
65 | visibility: visible;
66 | }
67 |
68 | 50% {
69 | opacity: 1;
70 | visibility: visible;
71 | }
72 |
73 | 75% {
74 | opacity: 1;
75 | visibility: visible;
76 | }
77 |
78 | 100% {
79 | opacity: 1;
80 | visibility: visible;
81 | }
82 | }
--------------------------------------------------------------------------------
/apps/OpenSign/src/styles/managesign.css:
--------------------------------------------------------------------------------
1 | .customwarning {
2 | position: absolute;
3 | padding: 8px;
4 | border: 1px solid black;
5 | background: white;
6 | border-radius: 5px;
7 | z-index: 1;
8 | }
9 |
10 | .signWarning {
11 | bottom: 70px;
12 | left: 50px;
13 | }
14 |
15 | .signWarning::before {
16 | content: "";
17 | width: 0px;
18 | height: 0px;
19 | border-style: outset;
20 | border-width: 0px 10px 10px 10px;
21 | border-color: transparent transparent black transparent;
22 | display: inline-block;
23 | position: absolute;
24 | top: -29%;
25 | left: 0;
26 | right: 75%;
27 | margin: 0 auto;
28 | }
29 |
30 | @keyframes inAnimation {
31 | 0% {
32 | opacity: 0;
33 | visibility: hidden;
34 | }
35 |
36 | 100% {
37 | opacity: 1;
38 | visibility: visible;
39 | }
40 | }
41 |
42 | .signature {
43 | color: white;
44 | cursor: pointer;
45 | padding: 10px 14px 10px;
46 | background: #15b4e9;
47 | font-size: 12px;
48 | font-weight: 600;
49 | border-radius: 2px;
50 | box-shadow:
51 | 0 1px 3px rgba(0, 0, 0, 0.1),
52 | 0 1px 2px rgba(0, 0, 0, 0.18);
53 | }
54 |
55 | .signature:hover {
56 | box-shadow:
57 | 0 2px 4px rgba(0, 0, 0, 0.1),
58 | 0 2px 4px rgba(0, 0, 0, 0.18);
59 | background: #13a8da;
60 | color: white;
61 | }
62 |
--------------------------------------------------------------------------------
/apps/OpenSign/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ["./src/**/*.{js,jsx,ts,tsx}"],
4 | theme: {
5 | extend: {}
6 | },
7 | plugins: [
8 | require("daisyui"),
9 | function ({ addUtilities }) {
10 | addUtilities({
11 | // Prevent iOS long-press popup
12 | ".touch-callout-none": {
13 | "-webkit-touch-callout": "none"
14 | }
15 | });
16 | }
17 | ],
18 | daisyui: {
19 | // themes: true,
20 | themes: [
21 | "dark",
22 | {
23 | opensigncss: {
24 | primary: "#002864",
25 | "primary-content": "#cacccf",
26 | secondary: "#29354a",
27 | "secondary-content": "#c8d1e0",
28 | accent: "#E10032",
29 | "accent-content": "#ffd8d5",
30 | neutral: "#c1ccdb",
31 | "neutral-content": "#111312",
32 | "base-100": "#ffffff",
33 | "base-200": "#dedede",
34 | "base-300": "#bebebe",
35 | "base-content": "#161616",
36 | info: "#00b6ff",
37 | "info-content": "#f5f5f4",
38 | success: "#00a96e",
39 | "success-content": "#f5f5f4",
40 | warning: "#ffbe00",
41 | "warning-content": "#ccd9e8",
42 | error: "#ffa1a7",
43 | "error-content": "#16090a",
44 | "--rounded-btn": "1.9rem",
45 | "--tab-border": "2px",
46 | "--tab-radius": "0.7rem"
47 | }
48 | }
49 | ],
50 | prefix: "op-"
51 | }
52 | };
53 |
--------------------------------------------------------------------------------
/apps/OpenSign/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 | import svgr from "vite-plugin-svgr";
4 | import { resolve } from "path";
5 | import dotenv from "dotenv";
6 |
7 | // Load env file based on mode
8 | dotenv.config();
9 |
10 | // https://vitejs.dev/config/
11 | export default defineConfig(({ command, mode }) => {
12 | return {
13 | plugins: [
14 | react(),
15 | svgr() // Transform SVGs into React components
16 | ],
17 | resolve: {
18 | alias: {
19 | // Add any path aliases here if needed
20 | }
21 | },
22 | define: {
23 | // Replace process.env.REACT_APP_* with import.meta.env.VITE_*
24 | "process.env": {
25 | ...Object.keys(process.env).reduce((env, key) => {
26 | if (key.startsWith("REACT_APP_")) {
27 | env[key] = process.env[key];
28 | }
29 | return env;
30 | }, {})
31 | }
32 | },
33 | build: {
34 | outDir: "build", // Keep the same output directory as CRA for compatibility
35 | rollupOptions: {
36 | // For public template as separate chunk
37 | input: {
38 | main: resolve(__dirname, "index.html")
39 | }
40 | }
41 | },
42 | server: {
43 | port: process.env.PORT || 3000, // Same port as CRA
44 | open: true
45 | },
46 | test: {
47 | environment: "jsdom",
48 | globals: true,
49 | setupFiles: "./setuptest.js" // if you have one
50 | }
51 | };
52 | });
53 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/.ebextensions/app.config:
--------------------------------------------------------------------------------
1 | option_settings:
2 | aws:elasticbeanstalk:application:environment:
3 | PARSE_MOUNT: "/parse"
4 | APP_ID: "ReplaceWithAppID"
5 | MASTER_KEY: "ReplaceWithMasterKey"
6 | DATABASE_URI: "ReplaceWithDatabaseURI"
7 | NODE_ENV: "production"
8 | SERVER_URL: "http://myappname.elasticbeanstalk.com/parse"
9 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "env": {
4 | "node": true,
5 | "es6": true
6 | },
7 | "parserOptions": {
8 | "ecmaVersion": 2021,
9 | "sourceType": "module",
10 | "requireConfigFile": false
11 | },
12 | "parser": "@babel/eslint-parser",
13 | "rules": {
14 | "indent": ["error", 2, { "SwitchCase": 1 }],
15 | "linebreak-style": ["error", "unix"],
16 | "no-trailing-spaces": "error",
17 | "eol-last": "error",
18 | "space-in-parens": ["error", "never"],
19 | "no-multiple-empty-lines": "warn",
20 | "prefer-const": "error",
21 | "space-infix-ops": "error",
22 | "no-useless-escape": "off",
23 | "require-atomic-updates": "off",
24 | "no-var": "warn",
25 | "no-await-in-loop" : "warn"
26 | },
27 | "globals" : {
28 | "Parse" : true
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Node.js
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | branches:
8 | - '**'
9 | workflow_dispatch:
10 | jobs:
11 | test:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | node-version: [16.x]
16 | name: ${{ matrix.name }}
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | - name: Install Dependancies
24 | run: npm install
25 | - name: Check Linting
26 | run: npm run lint
27 | - name: Run Tests
28 | run: npm run test
--------------------------------------------------------------------------------
/apps/OpenSignServer/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 | .nyc_output
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
28 | node_modules
29 |
30 | # Emacs
31 | *~
32 | .eslintcache
33 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/.nycrc:
--------------------------------------------------------------------------------
1 | {
2 | "reporter": [
3 | "lcov",
4 | "text-summary"
5 | ],
6 | "exclude": [
7 | "**/spec/**"
8 | ]
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/.prettierrc:
--------------------------------------------------------------------------------
1 | semi: true
2 | trailingComma: "es5"
3 | singleQuote: true
4 | arrowParens: "avoid"
5 | printWidth: 100
--------------------------------------------------------------------------------
/apps/OpenSignServer/Dockerhubfile:
--------------------------------------------------------------------------------
1 | # Use an official Node runtime as the base image
2 | FROM node:22.14.0
3 |
4 |
5 | # Set the working directory inside the container
6 | WORKDIR /usr/src/app
7 |
8 | # Copy package.json and package-lock.json first to leverage Docker cache
9 | COPY apps/OpenSignServer/package*.json ./
10 |
11 | # Install application dependencies
12 | RUN npm install
13 |
14 | # If you have native dependencies, you'll need extra tools. Uncomment the following line if needed.
15 | # RUN apk add --no-cache make gcc g++ python3
16 |
17 | # Copy the current directory contents into the container
18 | COPY apps/OpenSignServer/ .
19 |
20 | # Make port 8080 available to the world outside this container
21 | EXPOSE 8080
22 |
23 | # Define environment variables if needed
24 | # ENV NODE_ENV production
25 | # ENV DATABASE_URL mongodb://db:27017
26 |
27 | # Run the application
28 | CMD ["npm", "start"]
29 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Parse Server Example",
3 | "description": "An example Parse API server using the parse-server module",
4 | "repository": "https://github.com/ParsePlatform/parse-server-example",
5 | "logo": "https://avatars0.githubusercontent.com/u/1294580?v=3&s=200",
6 | "keywords": ["node", "express", "parse"],
7 | "env": {
8 | "PARSE_MOUNT": {
9 | "description": "Configure Parse API route.",
10 | "value": "/parse"
11 | },
12 | "APP_ID": {
13 | "description": "A unique identifier for your app.",
14 | "value": "myAppId"
15 | },
16 | "MASTER_KEY": {
17 | "description": "A key that overrides all permissions. Keep this secret.",
18 | "value": "myMasterKey"
19 | },
20 | "SERVER_URL": {
21 | "description": "URL to connect to your Heroku instance (update with your app's name + PARSE_MOUNT)",
22 | "value": "http://yourappname.herokuapp.com/parse"
23 | }
24 | },
25 | "image": "heroku/nodejs",
26 | "addons": ["mongolab"]
27 | }
28 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/app.yaml:
--------------------------------------------------------------------------------
1 | runtime: nodejs
2 | env: flex
3 |
4 | env_variables:
5 | # --REQUIRED--
6 | DATABASE_URI: mongodb://localhost:27017/dev
7 | APP_ID:
8 | MASTER_KEY:
9 | SERVER_URL: https://your-project-id.appspot.com/parse
10 | # --OPTIONAL--
11 | # FILE_KEY:
12 | # PARSE_MOUNT: /parse
13 | # CLOUD_CODE_MAIN:
14 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/auth/authadapter.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import dotenv from 'dotenv';
3 | dotenv.config();
4 | const ssoApiUrl = process.env.SSO_API_URL || 'https://sso.opensignlabs.com/api'; //'https://osl-jacksonv2.vercel.app/api';
5 | export const SSOAuth = {
6 | // Returns a promise that fulfills if this user mail is valid.
7 | validateAuthData: async authData => {
8 | try {
9 | const response = await axios.get(ssoApiUrl + '/oauth/userinfo', {
10 | headers: {
11 | Authorization: `Bearer ${authData.access_token}`,
12 | },
13 | });
14 | if (
15 | response.data &&
16 | response.data.id &&
17 | response.data.email?.toLowerCase()?.replace(/\s/g, '') === authData.id
18 | ) {
19 | return;
20 | }
21 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'SSO auth is invalid for this user.');
22 | } catch (error) {
23 | console.log('error in sso adapter', error?.response);
24 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'SSO auth is invalid for this user.');
25 | }
26 | },
27 |
28 | // Returns a promise that fulfills if this app id is valid.
29 | validateAppId: () => {
30 | return Promise.resolve();
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/customRoute/customApp.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import cors from 'cors';
3 | import dotenv from 'dotenv';
4 | import uploadFile from './uploadFile.js';
5 |
6 | export const app = express();
7 |
8 | dotenv.config();
9 | app.use(cors());
10 | app.use(express.json({ limit: '50mb' }));
11 | app.use(express.urlencoded({ limit: '50mb', extended: true }));
12 |
13 | app.post('/file_upload', uploadFile);
14 |
15 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/CheckAdminExist.js:
--------------------------------------------------------------------------------
1 | // `CheckAdminExist` is used to check is admin with org exist or not in db
2 | export default async function CheckAdminExist() {
3 | try {
4 | const extClsQuery = new Parse.Query('contracts_Users');
5 | extClsQuery.equalTo('UserRole', 'contracts_Admin');
6 | extClsQuery.notEqualTo('IsDisabled', true);
7 | const extAdminRes = await extClsQuery.find({ useMasterKey: true });
8 | // must be only one admin
9 | if (extAdminRes && extAdminRes.length === 1 && extAdminRes?.[0]?.get('OrganizationId')) {
10 | return 'exist';
11 | } else {
12 | return 'not_exist';
13 | }
14 | } catch (err) {
15 | console.log('err in isAdminExist', err);
16 | const code = err?.code || 400;
17 | const msg = err?.message || 'something went wrong.';
18 | throw new Parse.Error(code, msg);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/ContactBookAftersave.js:
--------------------------------------------------------------------------------
1 | async function ContactbookAftersave(request) {
2 | /* In beforesave or aftersave if you want to check if an object is being inserted or updated
3 | you can check as follows */
4 | if (!request.original) {
5 | const user = request.user;
6 | const object = request.object;
7 | if (object.get('UserId')) {
8 | // Retrieve the current ACL
9 | const acl = new Parse.ACL();
10 | // Ensure the current user has read access
11 | if (acl && request?.user) {
12 | const object = request.object;
13 | acl.setReadAccess(user, true);
14 | acl.setWriteAccess(user, true);
15 | acl.setReadAccess(object.get('UserId'), true);
16 | acl.setWriteAccess(object.get('UserId'), true);
17 |
18 | object.setACL(acl);
19 | object.set('IsDeleted', false);
20 | // Continue saving the object
21 | return object.save(null, { useMasterKey: true });
22 | }
23 | } else {
24 | const Name = object.get('Name');
25 | const Email = object.get('Email');
26 | const Phone = object.get('Phone');
27 | try {
28 | const _users = Parse.Object.extend('User');
29 | const _user = new _users();
30 | _user.set('name', Name);
31 | _user.set('username', Email);
32 | _user.set('email', Email);
33 | _user.set('password', Email);
34 | if (Email) {
35 | _user.set('phone', Phone);
36 | }
37 | const user = await _user.save();
38 | if (user) {
39 | object.set('UserId', user);
40 | const acl = object.getACL() || new Parse.ACL();
41 | acl.setReadAccess(user.id, true);
42 | acl.setWriteAccess(user.id, true);
43 | object.setACL(acl);
44 | await object.save(null, { useMasterKey: true });
45 | // console.log('res update new user with contac', res);
46 | }
47 | } catch (err) {
48 | // console.log('err ', err);
49 | if (err.code === 202) {
50 | const userQuery = new Parse.Query(Parse.User);
51 | userQuery.equalTo('email', Email);
52 | const userRes = await userQuery.first({ useMasterKey: true });
53 | object.set('UserId', {
54 | __type: 'Pointer',
55 | className: '_User',
56 | objectId: userRes.id,
57 | });
58 | const acl = object.getACL() || new Parse.ACL();
59 | acl.setReadAccess(userRes.id, true);
60 | acl.setWriteAccess(userRes.id, true);
61 | object.setACL(acl);
62 | await object.save(null, { useMasterKey: true });
63 | // console.log('res update existing user with contact', res);
64 | }
65 | }
66 | }
67 | } else {
68 | console.log('Object being update');
69 | }
70 | }
71 | export default ContactbookAftersave;
72 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/DocumentAfterFind.js:
--------------------------------------------------------------------------------
1 | import { useLocal } from '../../Utils.js';
2 | import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
3 |
4 | async function DocumentAfterFind(request) {
5 | if (request.objects.length === 1) {
6 | if (request.objects) {
7 | const obj = request.objects[0];
8 | if (
9 | useLocal !== 'true'
10 | ) {
11 | const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
12 | const Url = obj?.get('URL') && obj?.get('URL');
13 | const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
14 | if (SignedUrl) {
15 | obj.set(
16 | 'SignedUrl',
17 | getPresignedUrl(
18 | SignedUrl,
19 | )
20 | );
21 | }
22 | if (Url) {
23 | obj.set(
24 | 'URL',
25 | getPresignedUrl(
26 | Url,
27 | )
28 | );
29 | }
30 | if (certificateUrl) {
31 | obj.set(
32 | 'CertificateUrl',
33 | getPresignedUrl(
34 | certificateUrl,
35 | )
36 | );
37 | }
38 | return [obj];
39 | } else if (useLocal == 'true') {
40 | const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
41 | const Url = obj?.get('URL') && obj?.get('URL');
42 | const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
43 | if (SignedUrl) {
44 | obj.set('SignedUrl', presignedlocalUrl(SignedUrl));
45 | }
46 | if (Url) {
47 | obj.set('URL', presignedlocalUrl(Url));
48 | }
49 | if (certificateUrl) {
50 | obj.set('CertificateUrl', presignedlocalUrl(certificateUrl));
51 | }
52 | return [obj];
53 | }
54 | }
55 | }
56 | }
57 | export default DocumentAfterFind;
58 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/DocumentBeforesave.js:
--------------------------------------------------------------------------------
1 | import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
2 |
3 | async function DocumentBeforesave(request) {
4 | if (!request.original) {
5 | const validations = [
6 | { field: 'Name', max: MAX_NAME_LENGTH },
7 | { field: 'Note', max: MAX_NOTE_LENGTH },
8 | { field: 'Description', max: MAX_DESCRIPTION_LENGTH },
9 | ];
10 |
11 | for (const { field, max } of validations) {
12 | const value = request?.object?.get(field);
13 | if (value && value.length > max) {
14 | throw new Parse.Error(
15 | Parse.Error.VALIDATION_ERROR,
16 | `The "${field}" field must be at most ${max} characters long.`
17 | );
18 | }
19 | }
20 |
21 | const TimeToCompleteDays = request?.object?.get('TimeToCompleteDays') || 15;
22 | const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
23 | const AutoReminder = request?.object?.get('AutomaticReminders') || false;
24 | const reminderCount = TimeToCompleteDays / RemindOnceInEvery;
25 | if (AutoReminder && reminderCount > 15) {
26 | throw new Parse.Error(Parse.Error.INVALID_QUERY, 'only 15 reminder allowed');
27 | }
28 | }
29 | try {
30 | // below code is used to update document when user sent document or self signed
31 | const document = request.object;
32 | const oldDocument = request.original;
33 |
34 | // Check if SignedUrl field has been added (transition from undefined to defined)
35 | if (oldDocument && !oldDocument?.get('SignedUrl') && document?.get('SignedUrl')) {
36 | // Update count in contracts_Users class
37 | const query = new Parse.Query('contracts_Users');
38 | query.equalTo('objectId', oldDocument.get('ExtUserPtr').id);
39 |
40 | try {
41 | const contractUser = await query.first({ useMasterKey: true });
42 | if (contractUser) {
43 | contractUser.increment('DocumentCount', 1);
44 | await contractUser.save(null, { useMasterKey: true });
45 | } else {
46 | // Create new entry if not found
47 | const ContractsUsers = Parse.Object.extend('contracts_Users');
48 | const newContractUser = new ContractsUsers();
49 | newContractUser.set('DocumentCount', 1);
50 | await newContractUser.save(null, { useMasterKey: true });
51 | }
52 | } catch (error) {
53 | console.log('Error updating document count in contracts_Users: ' + error.message);
54 | }
55 | if (document?.get('Signers') && document.get('Signers').length > 0) {
56 | document.set('DocSentAt', new Date());
57 | }
58 | }
59 | } catch (err) {
60 | console.log('err in document beforesave', err.message);
61 | }
62 | }
63 | export default DocumentBeforesave;
64 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/GetLogoByDomain.js:
--------------------------------------------------------------------------------
1 | import { appName } from '../../Utils.js';
2 |
3 | // `GetLogoByDomain` is used to get logo by domain as well as check any tenant exist or not in db
4 | export default async function GetLogoByDomain(request) {
5 | const domain = request.params.domain;
6 | try {
7 | const tenantCreditsQuery = new Parse.Query('partners_Tenant');
8 | tenantCreditsQuery.equalTo('Domain', domain);
9 | const res = await tenantCreditsQuery.first({ useMasterKey: true });
10 | if (res) {
11 | const updateRes = JSON.parse(JSON.stringify(res));
12 | return {
13 | logo: updateRes?.Logo,
14 | appname: appName,
15 | user: 'exist',
16 | };
17 | } else {
18 | const tenantCreditsQuery = new Parse.Query('partners_Tenant');
19 | const tenantRes = await tenantCreditsQuery.first({ useMasterKey: true });
20 | if (tenantRes) {
21 | return { logo: '', appname: appName, user: 'exist' };
22 | } else {
23 | return { logo: '', appname: appName, user: 'not_exist' };
24 | }
25 | }
26 | } catch (err) {
27 | const code = err.code || 400;
28 | const msg = err.message || 'Something went wrong.';
29 | throw new Parse.Error(code, msg);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/Newsletter.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | export default async function Newsletter(request) {
3 | const name = request.params.name;
4 | const email = request.params?.email?.toLowerCase()?.replace(/\s/g, '');
5 | const domain = request.params.domain;
6 | try {
7 | const envAppId = 'opensign';
8 | const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': envAppId };
9 | const envProdServer = 'https://app.opensignlabs.com/api/app';
10 | const newsletter = await axios.post(
11 | `${envProdServer}/classes/Newsletter`,
12 | { Name: name, Email: email, Domain: domain },
13 | { headers: headers }
14 | );
15 | return 'success';
16 | } catch (err) {
17 | const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
18 | const message =
19 | err?.response?.data?.error || err?.response?.data || err?.message || 'Something went wrong.';
20 | console.log('err in savenewsletter', err);
21 | throw new Parse.Error(code, message);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/SignatureAfterFind.js:
--------------------------------------------------------------------------------
1 | import { useLocal } from '../../Utils.js';
2 | import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
3 |
4 | async function SignatureAfterFind(request) {
5 | if (useLocal !== 'true') {
6 | if (request.objects.length === 1) {
7 | if (request.objects) {
8 | const obj = request.objects[0];
9 | const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
10 | const Initials = obj?.get('Initials') && obj?.get('Initials');
11 | if (ImageURL) {
12 | obj.set('ImageURL', getPresignedUrl(ImageURL));
13 | }
14 | if (Initials) {
15 | obj.set('Initials', getPresignedUrl(Initials));
16 | }
17 | return [obj];
18 | }
19 | }
20 | } else if (useLocal == 'true') {
21 | if (request.objects.length === 1) {
22 | if (request.objects) {
23 | const obj = request.objects[0];
24 | const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
25 | const Initials = obj?.get('Initials') && obj?.get('Initials');
26 | if (ImageURL) {
27 | obj.set('ImageURL', presignedlocalUrl(ImageURL));
28 | }
29 | if (Initials) {
30 | obj.set('Initials', presignedlocalUrl(Initials));
31 | }
32 | return [obj];
33 | }
34 | }
35 | }
36 | }
37 | export default SignatureAfterFind;
38 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/TeamsAftersave.js:
--------------------------------------------------------------------------------
1 | export default async function TeamsAftersave(req) {
2 | if (!req.original) {
3 | try {
4 | const Ancestors = req.object.get('Ancestors');
5 | let updatedAncestors;
6 | if (Ancestors && Ancestors.length > 0) {
7 | updatedAncestors = [
8 | ...Ancestors,
9 | {
10 | __type: 'Pointer',
11 | className: 'contracts_Teams',
12 | objectId: req.object.id,
13 | },
14 | ];
15 | } else {
16 | updatedAncestors = [
17 | {
18 | __type: 'Pointer',
19 | className: 'contracts_Teams',
20 | objectId: req.object.id,
21 | },
22 | ];
23 | }
24 | req.object.set('Ancestors', updatedAncestors);
25 | await req.object.save(null, { useMasterKey: true });
26 | } catch (err) {
27 | console.log('Err in team aftersave', err);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/TemplateAfterFind.js:
--------------------------------------------------------------------------------
1 | import { useLocal } from '../../Utils.js';
2 | import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
3 |
4 | async function TemplateAfterFind(request) {
5 | if (request.objects.length === 1) {
6 | if (request.objects) {
7 | const obj = request.objects[0];
8 | if (
9 | useLocal !== 'true'
10 | ) {
11 | const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
12 | const Url = obj?.get('URL') && obj?.get('URL');
13 | const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
14 | if (SignedUrl) {
15 | obj.set(
16 | 'SignedUrl',
17 | getPresignedUrl(
18 | SignedUrl,
19 | )
20 | );
21 | }
22 | if (Url) {
23 | obj.set(
24 | 'URL',
25 | getPresignedUrl(
26 | Url,
27 | )
28 | );
29 | }
30 | if (certificateUrl) {
31 | obj.set(
32 | 'CertificateUrl',
33 | getPresignedUrl(
34 | certificateUrl,
35 | )
36 | );
37 | }
38 | return [obj];
39 | } else if (useLocal == 'true') {
40 | const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
41 | const Url = obj?.get('URL') && obj?.get('URL');
42 | const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
43 | if (SignedUrl) {
44 | obj.set('SignedUrl', presignedlocalUrl(SignedUrl));
45 | }
46 | if (Url) {
47 | obj.set('URL', presignedlocalUrl(Url));
48 | }
49 | if (certificateUrl) {
50 | obj.set('CertificateUrl', presignedlocalUrl(certificateUrl));
51 | }
52 | return [obj];
53 | }
54 | }
55 | }
56 | }
57 | export default TemplateAfterFind;
58 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/TemplateBeforesave.js:
--------------------------------------------------------------------------------
1 | import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
2 |
3 | async function TemplateBeforeSave(request) {
4 | if (!request.original) {
5 | const validations = [
6 | { field: 'Name', max: MAX_NAME_LENGTH },
7 | { field: 'Note', max: MAX_NOTE_LENGTH },
8 | { field: 'Description', max: MAX_DESCRIPTION_LENGTH },
9 | ];
10 |
11 | for (const { field, max } of validations) {
12 | const value = request.object?.get(field);
13 | if (value && value.length > max) {
14 | throw new Parse.Error(
15 | Parse.Error.VALIDATION_ERROR,
16 | `The "${field}" field must be at most ${max} characters long.`
17 | );
18 | }
19 | }
20 |
21 | const TimeToCompleteDays = request.object.get('TimeToCompleteDays') || 15;
22 | const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
23 | const AutoReminder = request?.object?.get('AutomaticReminders') || false;
24 | const reminderCount = TimeToCompleteDays / RemindOnceInEvery;
25 | if (AutoReminder && reminderCount > 15) {
26 | throw new Parse.Error(Parse.Error.INVALID_QUERY, 'only 15 reminder allowed');
27 | }
28 | }
29 | try {
30 | if (!request.original) {
31 | // below code is used to update template when user sent template or self signed
32 | const template = request.object;
33 |
34 | // Update count in contracts_Users class
35 | const query = new Parse.Query('contracts_Users');
36 | query.equalTo('objectId', template.get('ExtUserPtr').id);
37 |
38 | try {
39 | const contractUser = await query.first({ useMasterKey: true });
40 | if (contractUser) {
41 | contractUser.increment('TemplateCount', 1);
42 | await contractUser.save(null, { useMasterKey: true });
43 | } else {
44 | // Create new entry if not found
45 | const ContractsUsers = Parse.Object.extend('contracts_Users');
46 | const newContractUser = new ContractsUsers();
47 | newContractUser.set('TemplateCount', 1);
48 | await newContractUser.save(null, { useMasterKey: true });
49 | }
50 | } catch (error) {
51 | console.log('Error updating template count in contracts_Users: ' + error.message);
52 | }
53 | }
54 | } catch (err) {
55 | console.log('err in template beforesave', err.message);
56 | }
57 | }
58 | export default TemplateBeforeSave;
59 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/TenantAfterFind.js:
--------------------------------------------------------------------------------
1 | import { useLocal } from '../../Utils.js';
2 | import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
3 |
4 | async function TenantAterFind(request) {
5 | if (useLocal !== 'true') {
6 | if (request.objects.length === 1) {
7 | if (request.objects) {
8 | const obj = request.objects[0];
9 | const Logo = obj?.get('Logo') && obj?.get('Logo');
10 | if (Logo) {
11 | obj.set('Logo', getPresignedUrl(Logo));
12 | }
13 | return [obj];
14 | }
15 | }
16 | } else if (useLocal == 'true') {
17 | if (request.objects.length === 1) {
18 | if (request.objects) {
19 | const obj = request.objects[0];
20 | const Logo = obj?.get('Logo') && obj?.get('Logo');
21 | if (Logo) {
22 | obj.set('Logo', presignedlocalUrl(Logo));
23 | }
24 | return [obj];
25 | }
26 | }
27 | }
28 | }
29 | export default TenantAterFind;
30 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/UserAfterFInd.js:
--------------------------------------------------------------------------------
1 | import { useLocal } from '../../Utils.js';
2 | import getPresignedUrl, { presignedlocalUrl } from './getSignedUrl.js';
3 |
4 | async function UserAfterFind(request) {
5 | if (useLocal !== 'true') {
6 | if (request.objects.length === 1) {
7 | if (request.objects) {
8 | const obj = request.objects[0];
9 | const ProfilePic = obj?.get('ProfilePic') && obj?.get('ProfilePic');
10 | if (ProfilePic) {
11 | obj.set('ProfilePic', getPresignedUrl(ProfilePic));
12 | }
13 | return [obj];
14 | }
15 | }
16 | } else if (useLocal == 'true') {
17 | if (request.objects.length === 1) {
18 | if (request.objects) {
19 | const obj = request.objects[0];
20 | const ProfilePic = obj?.get('ProfilePic') && obj?.get('ProfilePic');
21 | if (ProfilePic) {
22 | obj.set('ProfilePic', presignedlocalUrl(ProfilePic));
23 | }
24 | return [obj];
25 | }
26 | }
27 | }
28 | }
29 | export default UserAfterFind;
30 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/VerifyEmail.js:
--------------------------------------------------------------------------------
1 | export default async function VerifyEmail(request) {
2 | try {
3 | if (!request?.user) {
4 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
5 | } else {
6 | let otpN = request.params.otp;
7 | let otp = parseInt(otpN);
8 | let email = request.params.email;
9 |
10 | //checking otp is correct or not which already save in defaultdata_Otp class
11 | const checkOtp = new Parse.Query('defaultdata_Otp');
12 | checkOtp.equalTo('Email', email);
13 | checkOtp.equalTo('OTP', otp);
14 |
15 | const res = await checkOtp.first({ useMasterKey: true });
16 | if (res) {
17 | // Fetch the user by their objectId
18 | const isEmailVerified = request?.user?.get('emailVerified');
19 | if (isEmailVerified) {
20 | return { message: 'Email is already verified.' };
21 | } else {
22 | const userQuery = new Parse.Query(Parse.User);
23 | const user = await userQuery.get(request?.user.id, {
24 | sessionToken: request?.user.getSessionToken(),
25 | });
26 |
27 | // Update the emailVerified field to true
28 | user.set('emailVerified', true);
29 | // Save the user object
30 | const res = await user.save(null, { useMasterKey: true });
31 | if (res) {
32 | return { message: 'Email is verified.' };
33 | } else {
34 | const error = new Error('Something went wrong, please try again later!');
35 | error.code = 400; // Set the error code (e.g., 400 for bad request)
36 | throw error;
37 | }
38 | }
39 | } else {
40 | const error = new Error('OTP is invalid.');
41 | error.code = 400; // Set the error code (e.g., 400 for bad request)
42 | throw error;
43 | }
44 | }
45 | } catch (err) {
46 | console.log('err ', err.code + ' ' + err.message);
47 | throw err;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/createBatchContact.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { cloudServerUrl } from '../../Utils.js';
3 | const appId = process.env.APP_ID;
4 | const masterkey = process.env.MASTER_KEY;
5 | export default async function createBatchContact(req) {
6 | if (!req?.user) {
7 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
8 | }
9 | if (!req.params?.contacts) {
10 | throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameter.');
11 | }
12 | const contactData = JSON.parse(req.params.contacts);
13 | if (contactData?.length > 0) {
14 | try {
15 | const requests = contactData.map(x => {
16 | return {
17 | method: 'POST',
18 | path: '/app/classes/contracts_Contactbook',
19 | body: {
20 | UserRole: 'contracts_Guest',
21 | TenantId: { __type: 'Pointer', className: 'partners_Tenant', objectId: x.TenantId },
22 | CreatedBy: { __type: 'Pointer', className: '_User', objectId: req.user.id },
23 | Name: x.Name,
24 | Email: x.Email?.toLowerCase()?.replace(/\s/g, ''),
25 | IsDeleted: false,
26 | IsImported: true,
27 | ...(x?.Phone ? { Phone: `${x?.Phone}` } : {}),
28 | ACL: { [req.user.id]: { read: true, write: true } },
29 | },
30 | };
31 | });
32 | const parseConfig = {
33 | baseURL: cloudServerUrl,
34 | headers: {
35 | 'X-Parse-Application-Id': appId,
36 | 'X-Parse-Master-Key': masterkey,
37 | 'Content-Type': 'application/json',
38 | },
39 | };
40 | const response = await axios.post('batch', { requests: requests }, parseConfig);
41 | // Handle the batch query response
42 | // console.info('createbatchcontact ', response.data);
43 | const successCount = response?.data?.filter(item => item.success).length;
44 | const failedCount = requests.length - successCount;
45 | console.log(
46 | `createbatchcontact query response: success: ${successCount}, failed: ${failedCount}`
47 | );
48 | return { success: successCount, failed: failedCount };
49 | } catch (err) {
50 | console.log('err while create batch contact', err);
51 | throw new Parse.Error(400, 'Something went wrong, please try again later');
52 | }
53 | } else {
54 | throw new Parse.Error(Parse.Error.INVALID_CONTENT_LENGTH, 'Please provide parameter');
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/declinedocument.js:
--------------------------------------------------------------------------------
1 | export default async function declinedocument(request) {
2 | const docId = request.params.docId;
3 | const reason = request.params?.reason || '';
4 | const declineBy = {
5 | __type: 'Pointer',
6 | className: '_User',
7 | objectId: request.params?.userId,
8 | };
9 |
10 | if (!docId) {
11 | throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'missing parameter docId.');
12 | }
13 | try {
14 | const docCls = new Parse.Query('contracts_Document');
15 | docCls.include('ExtUserPtr.TenantId');
16 | const updateDoc = await docCls.get(docId, { useMasterKey: true });
17 | if (updateDoc) {
18 | const isEnableOTP = updateDoc?.get('IsEnableOTP') || false;
19 | if (!isEnableOTP) {
20 | updateDoc.set('IsDeclined', true);
21 | updateDoc.set('DeclineReason', reason);
22 | updateDoc.set('DeclineBy', declineBy);
23 | await updateDoc.save(null, { useMasterKey: true });
24 | return 'document declined';
25 | } else {
26 | if (!request?.user) {
27 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
28 | }
29 | updateDoc.set('IsDeclined', true);
30 | updateDoc.set('DeclineReason', reason);
31 | updateDoc.set('DeclineBy', declineBy);
32 | await updateDoc.save(null, { useMasterKey: true });
33 | return 'document declined';
34 | }
35 | } else {
36 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
37 | }
38 | } catch (err) {
39 | console.log('err while decling doc', err);
40 | throw err;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/fileUpload.js:
--------------------------------------------------------------------------------
1 | import { getSignedLocalUrl } from './getSignedUrl.js';
2 |
3 | export default async function fileUpload(request) {
4 | const url = request.params.url;
5 |
6 | try {
7 | const urlwithjwt = getSignedLocalUrl(url, 200);
8 | return { url: urlwithjwt };
9 | } catch (err) {
10 | console.log('Err ', err);
11 | throw err;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getContact.js:
--------------------------------------------------------------------------------
1 | export default async function getContact(request) {
2 | const contactId = request.params.contactId;
3 | try {
4 | const contactCls = new Parse.Query('contracts_Contactbook');
5 | const contactRes = await contactCls.get(contactId, { useMasterKey: true });
6 | return contactRes;
7 | } catch (err) {
8 | console.log('Err in contracts_Contactbook class ', err);
9 | throw err;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getDrive.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { cloudServerUrl } from '../../Utils.js';
3 | export default async function getDrive(request) {
4 | const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
5 | const appId = process.env.APP_ID;
6 | const limit = request.params.limit;
7 | const skip = request.params.skip;
8 | const docId = request.params.docId;
9 | try {
10 | const userRes = await axios.get(serverUrl + '/users/me', {
11 | headers: {
12 | 'X-Parse-Application-Id': appId,
13 | 'X-Parse-Session-Token': request.headers['sessiontoken'],
14 | },
15 | });
16 | const userId = userRes.data && userRes.data.objectId;
17 | if (userId) {
18 | try {
19 | const query = new Parse.Query('contracts_Document');
20 | if (docId) {
21 | query.equalTo('Folder', {
22 | __type: 'Pointer',
23 | className: 'contracts_Document',
24 | objectId: docId,
25 | });
26 | query.include('Folder');
27 | } else {
28 | query.doesNotExist('Folder', true);
29 | }
30 | query.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
31 | query.include('ExtUserPtr');
32 | query.include('ExtUserPtr.TenantId');
33 | query.include('Signers');
34 | query.notEqualTo('IsArchive', true);
35 | query.descending('updatedAt');
36 | query.skip(skip);
37 | query.limit(limit);
38 | query.exclude('AuditTrail');
39 | const res = await query.find({ useMasterKey: true });
40 | return res;
41 | } catch (err) {
42 | console.log('err', err);
43 | return { error: "You don't have access to drive" };
44 | }
45 | } else {
46 | return { error: 'Please provide required parameter!' };
47 | }
48 | } catch (err) {
49 | console.log('err', err);
50 | if (err.code == 209) {
51 | return { error: 'Invalid session token' };
52 | } else {
53 | return { error: "You don't have access!" };
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getSigners.js:
--------------------------------------------------------------------------------
1 | // Function to escape special characters in the search string
2 | function escapeRegExp(string) {
3 | return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escape special characters
4 | }
5 |
6 | async function getContacts(searchObj, isJWT) {
7 | try {
8 | const escapedSearch = escapeRegExp(searchObj.search); // Escape the search input
9 | const searchRegex = new RegExp(escapedSearch, 'i'); // Create regex once to reuse
10 | const contactNameQuery = new Parse.Query('contracts_Contactbook');
11 | contactNameQuery.matches('Name', searchRegex);
12 |
13 | const conatctEmailQuery = new Parse.Query('contracts_Contactbook');
14 | conatctEmailQuery.matches('Email', searchRegex);
15 |
16 | // Combine the two queries with OR
17 | const mainQuery = Parse.Query.or(contactNameQuery, conatctEmailQuery);
18 |
19 | // Add the common condition for 'CreatedBy'
20 | mainQuery.equalTo('CreatedBy', searchObj.CreatedBy);
21 | mainQuery.notEqualTo('IsDeleted', true);
22 | const findOpt = isJWT ? { useMasterKey: true } : { sessionToken: searchObj.sessionToken };
23 | const contactRes = await mainQuery.find(findOpt);
24 | const _contactRes = JSON.parse(JSON.stringify(contactRes));
25 | return _contactRes;
26 | } catch (err) {
27 | console.log('err while fetch contacts', err);
28 | throw err;
29 | }
30 | }
31 | export default async function getSigners(request) {
32 | const searchObj = { search: request.params.search || '', sessionToken: '' };
33 | try {
34 | if (request.user) {
35 | searchObj.CreatedBy = { __type: 'Pointer', className: '_User', objectId: request?.user?.id };
36 | searchObj.sessionToken = request.user.getSessionToken();
37 | return await getContacts(searchObj);
38 | }
39 | else {
40 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
41 | }
42 | } catch (err) {
43 | console.log('err in get signers', err);
44 | throw err;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getTeams.js:
--------------------------------------------------------------------------------
1 | export default async function getTeams(request) {
2 | const activeTeams = request.params.active;
3 | if (!request?.user) {
4 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
5 | }
6 | try {
7 | const extUserQuery = new Parse.Query('contracts_Users');
8 | extUserQuery.equalTo('UserId', {
9 | __type: 'Pointer',
10 | className: '_User',
11 | objectId: request.user.id,
12 | });
13 | extUserQuery.notEqualTo('IsDisabled', true);
14 | const resExt = await extUserQuery.first({ useMasterKey: true });
15 | const extUser = JSON.parse(JSON.stringify(resExt));
16 | const teamCls = new Parse.Query('contracts_Teams');
17 | teamCls.equalTo('OrganizationId', {
18 | __type: 'Pointer',
19 | className: 'contracts_Organizations',
20 | objectId: extUser.OrganizationId.objectId,
21 | });
22 | if (activeTeams) {
23 | teamCls.equalTo('IsActive', true);
24 | }
25 | teamCls.descending('createdAt');
26 | const teamRes = await teamCls.find({ useMasterKey: true });
27 | if (teamRes && teamRes.length > 0) {
28 | return teamRes;
29 | } else {
30 | return [];
31 | }
32 | } catch (err) {
33 | console.log('err in getTeams', err);
34 | const code = err?.code || 400;
35 | const msg = err?.message || 'Something went wrong.';
36 | throw new Parse.Error(code, msg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getTenant.js:
--------------------------------------------------------------------------------
1 |
2 | async function getTenantByUserId(userId, contactId) {
3 | try {
4 | if (contactId) {
5 | const contactquery = new Parse.Query('contracts_Contactbook');
6 | contactquery.equalTo('objectId', contactId);
7 | const contactuser = await contactquery.first({ useMasterKey: true });
8 | if (contactuser) {
9 | const tenantId = contactuser?.get('TenantId')?.id;
10 | if (tenantId) {
11 | const tenantCreditsQuery = new Parse.Query('partners_Tenant');
12 | tenantCreditsQuery.equalTo('objectId', tenantId);
13 | tenantCreditsQuery.exclude('FileAdapters,PfxFile,ContactNumber');
14 | const res = await tenantCreditsQuery.first({ useMasterKey: true });
15 | return res;
16 | } else {
17 | return {};
18 | }
19 | } else {
20 | return {};
21 | }
22 | } else {
23 | const query = new Parse.Query('contracts_Users');
24 | query.equalTo('UserId', {
25 | __type: 'Pointer',
26 | className: '_User',
27 | objectId: userId,
28 | });
29 | const extuser = await query.first({ useMasterKey: true });
30 | if (extuser) {
31 | const user = extuser?.get('CreatedBy')?.id || userId;
32 | const tenantCreditsQuery = new Parse.Query('partners_Tenant');
33 | tenantCreditsQuery.equalTo('UserId', {
34 | __type: 'Pointer',
35 | className: '_User',
36 | objectId: user,
37 | });
38 | tenantCreditsQuery.exclude('FileAdapters,PfxFile');
39 | const res = await tenantCreditsQuery.first({ useMasterKey: true });
40 | return res;
41 | } else {
42 | return {};
43 | }
44 | }
45 | } catch (err) {
46 | console.log('err in getTenant ', err);
47 | return 'user does not exist!';
48 | }
49 | }
50 | export default async function getTenant(request) {
51 | const userId = request.params.userId || '';
52 | const contactId = request.params.contactId || '';
53 |
54 | if (userId || contactId) {
55 | return await getTenantByUserId(userId, contactId);
56 | }
57 | else {
58 | return {};
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getUserDetails.js:
--------------------------------------------------------------------------------
1 | async function getUserDetails(request) {
2 | const reqEmail = request.params.email;
3 | if (reqEmail || request.user) {
4 | try {
5 | const userId = request.params.userId;
6 | const userQuery = new Parse.Query('contracts_Users');
7 | if (reqEmail) {
8 | userQuery.equalTo('Email', reqEmail);
9 | } else {
10 | const email = request.user.get('email');
11 | userQuery.equalTo('Email', email);
12 | }
13 | userQuery.include('TenantId');
14 | userQuery.include('UserId');
15 | userQuery.include('CreatedBy');
16 | userQuery.exclude('CreatedBy.authData');
17 | userQuery.exclude('TenantId.FileAdapters');
18 | userQuery.exclude('google_refresh_token');
19 | userQuery.exclude('TenantId.PfxFile');
20 | if (userId) {
21 | userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
22 | }
23 | const res = await userQuery.first({ useMasterKey: true });
24 | if (res) {
25 | if (reqEmail) {
26 | return { objectId: res.id };
27 | } else {
28 | return res;
29 | }
30 | } else {
31 | return '';
32 | }
33 | } catch (err) {
34 | console.log('Err ', err);
35 | const code = err?.code || 400;
36 | const msg = err?.message || 'Something went wrong.';
37 | throw new Parse.Error(code, msg);
38 | }
39 | }
40 | else {
41 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
42 | }
43 | }
44 | export default getUserDetails;
45 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getUserId.js:
--------------------------------------------------------------------------------
1 | async function getUserId(request) {
2 | try {
3 | const username = request.params.username;
4 | const email = request.params.email;
5 | const query = new Parse.Query(Parse.User);
6 | if (username) {
7 | query.equalTo('username', username);
8 | } else {
9 | query.equalTo('email', email);
10 | }
11 | const user = await query.first({ useMasterKey: true });
12 | return { id: user.id };
13 | } catch (err) {
14 | console.log('err', err);
15 | return err;
16 | }
17 | }
18 | export default getUserId;
19 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/getUserListByOrg.js:
--------------------------------------------------------------------------------
1 | export default async function getUserListByOrg(req) {
2 | const OrganizationId = req.params.organizationId;
3 | const orgPtr = {
4 | __type: 'Pointer',
5 | className: 'contracts_Organizations',
6 | objectId: OrganizationId,
7 | };
8 | if (!req?.user) {
9 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
10 | } else {
11 | try {
12 | const extUser = new Parse.Query('contracts_Users');
13 | extUser.equalTo('OrganizationId', orgPtr);
14 | extUser.include('TeamIds');
15 | extUser.descending('createdAt');
16 | const userRes = await extUser.find({ useMasterKey: true });
17 | if (userRes.length > 0) {
18 | const _userRes = JSON.parse(JSON.stringify(userRes));
19 | return _userRes;
20 | } else {
21 | return [];
22 | }
23 | } catch (err) {
24 | console.log('err in getuserlist', err);
25 | throw err;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/isUserInContactBook.js:
--------------------------------------------------------------------------------
1 |
2 | export default async function isUserInContactBook(request) {
3 | try {
4 | if (request.user) {
5 | const email = request.user.get('email');
6 | const userPtr = { __type: 'Pointer', className: '_User', objectId: request.user?.id };
7 | const query = new Parse.Query('contracts_Contactbook');
8 | query.equalTo('CreatedBy', userPtr);
9 | query.notEqualTo('IsDeleted', true);
10 | query.equalTo('Email', email);
11 | const res = await query.first({ sessionToken: request.user.getSessionToken() });
12 | return res;
13 | }
14 | } catch (err) {
15 | console.log('err', err);
16 | throw err;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/isextenduser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Checks if a user exists in the extended class 'contracts_Users' based on the provided email.
3 | * @param email - The request contains parameters, such as the user's email.
4 | * @returns {Object} - Returns an object indicating whether the user exists.
5 | */
6 | export default async function isextenduser(request) {
7 | try {
8 | // Query the 'contracts_Users' class in the database based on the provided email
9 | const userQuery = new Parse.Query('contracts_Users');
10 | userQuery.equalTo('Email', request.params.email);
11 |
12 | // Execute the query
13 | const res = await userQuery.first({ useMasterKey: true });
14 |
15 | // Check if a user was found
16 | if (res) {
17 | // If user exists, return object with 'isUserExist' set to true
18 | return { isUserExist: true };
19 | } else {
20 | // If user does not exist, return object with 'isUserExist' set to false
21 | return { isUserExist: false };
22 | }
23 | } catch (err) {
24 | // Handle errors
25 | console.log('Error in userexist', err);
26 | const code = err?.code || 400;
27 | const message = err?.message || 'Something went wrong.';
28 | throw new Parse.Error(code, message);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/loginUser.js:
--------------------------------------------------------------------------------
1 | import crypto from 'node:crypto';
2 | export default async function loginUser(request) {
3 | const username = request.params.email;
4 | const password = request.params.password;
5 |
6 | if (username && password) {
7 | try {
8 | // Pass the username and password to logIn function
9 | const user = await Parse.User.logIn(username, password);
10 | // console.log('user ', user);
11 | if (user) {
12 | const _user = user?.toJSON();
13 | return {
14 | ..._user,
15 | };
16 | } else {
17 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'user not found.');
18 | }
19 | } catch (err) {
20 | console.log('err in login user', err);
21 | throw err;
22 | }
23 | } else {
24 | throw new Parse.Error(Parse.Error.PASSWORD_MISSING, 'username/password is missing.');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/pdf/PDFArrayCustom.js:
--------------------------------------------------------------------------------
1 | import { PDFArray, CharCodes } from 'pdf-lib';
2 |
3 | /**
4 | * Extends PDFArray class in order to make ByteRange look like this:
5 | * /ByteRange [0 /********** /********** /**********]
6 | * Not this:
7 | * /ByteRange [ 0 /********** /********** /********** ]
8 | */
9 | export default class PDFArrayCustom extends PDFArray {
10 | static withContext(context) {
11 | return new PDFArrayCustom(context);
12 | }
13 |
14 | clone(context) {
15 | const clone = PDFArrayCustom.withContext(context || this.context);
16 | for (let idx = 0, len = this.size(); idx < len; idx++) {
17 | clone.push(this.array[idx]);
18 | }
19 | return clone;
20 | }
21 |
22 | toString() {
23 | let arrayString = '[';
24 | for (let idx = 0, len = this.size(); idx < len; idx++) {
25 | arrayString += this.get(idx).toString();
26 | if (idx < len - 1) arrayString += ' ';
27 | }
28 | arrayString += ']';
29 | return arrayString;
30 | }
31 |
32 | sizeInBytes() {
33 | let size = 2;
34 | for (let idx = 0, len = this.size(); idx < len; idx++) {
35 | size += this.get(idx).sizeInBytes();
36 | if (idx < len - 1) size += 1;
37 | }
38 | return size;
39 | }
40 |
41 | copyBytesInto(buffer, offset) {
42 | const initialOffset = offset;
43 |
44 | buffer[offset++] = CharCodes.LeftSquareBracket;
45 | for (let idx = 0, len = this.size(); idx < len; idx++) {
46 | offset += this.get(idx).copyBytesInto(buffer, offset);
47 | if (idx < len - 1) buffer[offset++] = CharCodes.Space;
48 | }
49 | buffer[offset++] = CharCodes.RightSquareBracket;
50 |
51 | return offset - initialOffset;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/recreateDocument.js:
--------------------------------------------------------------------------------
1 | export default async function recreateDocument(request) {
2 | const { docId } = request.params;
3 | if (!docId) {
4 | throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Missing docId parameter');
5 | }
6 | if (!request.user) {
7 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User not aunthenticated');
8 | }
9 |
10 | try {
11 | const docQuery = new Parse.Query('contracts_Document');
12 | docQuery.equalTo('objectId', docId);
13 | const doc = await docQuery.first({ useMasterKey: true });
14 | if (!doc) {
15 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found');
16 | }
17 | const _docRes = doc?.toJSON();
18 | const { objectId, SignedUrl, AuditTrail, ACL, DeclineBy, DeclineReason, ...docRes } = _docRes;
19 | const createDoc = new Parse.Object('contracts_Document');
20 | Object.entries(docRes).forEach(([key, value]) => {
21 | if (key === 'IsDeclined') {
22 | createDoc.set(key, false);
23 | } else {
24 | createDoc.set(key, value);
25 | }
26 | // console.log(`${key}: ${value}`);
27 | });
28 | const createDocRes = await createDoc.save(null, { useMasterKey: true });
29 | // console.log('createDocRes', createDocRes);
30 | const newDoc = JSON.parse(JSON.stringify(createDocRes));
31 | return { objectId: newDoc.objectId, createdAt: newDoc.createdAt, updatedAt: newDoc.updatedAt };
32 | } catch (err) {
33 | console.log('err in recreate document', err);
34 | throw err;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/saveFile.js:
--------------------------------------------------------------------------------
1 | import {
2 | flattenPdf,
3 | getSecureUrl,
4 | } from '../../Utils.js';
5 | export default async function saveFile(request) {
6 | if (!request.params.fileBase64) {
7 | throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide file.');
8 | }
9 | const fileBase64 = request.params.fileBase64;
10 | const id = request.params.id;
11 | try {
12 | if (request.user) {
13 | const extCls = new Parse.Query('contracts_Users');
14 | extCls.equalTo('UserId', request.user);
15 | extCls.include('TenantId');
16 | const resExt = await extCls.first({ useMasterKey: true });
17 | if (resExt) {
18 | const _resExt = JSON.parse(JSON.stringify(resExt));
19 | const fileName = request.params.fileName;
20 | const ext = request.params.fileName?.split('.')?.pop();
21 | let mimeType;
22 | let file;
23 | if (ext === 'pdf') {
24 | mimeType = 'application/pdf';
25 | const flatPdf = await flattenPdf(fileBase64);
26 | file = [...flatPdf];
27 | } else if (ext === 'png' || ext === 'jpeg' || ext === 'jpg') {
28 | mimeType = `image/${ext}`;
29 | file = { base64: fileBase64 };
30 | }
31 | const pdfFile = new Parse.File(fileName, file, mimeType);
32 | // Save the Parse File if needed
33 | const pdfData = await pdfFile.save({ useMasterKey: true });
34 | const presignedUrl = pdfData.url();
35 | const fileRes = getSecureUrl(presignedUrl);
36 | return { url: fileRes.url };
37 | } else {
38 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
39 | }
40 | }
41 | else {
42 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
43 | }
44 | } catch (err) {
45 | console.log('err in savetoS3', err);
46 | throw err;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/updateContactTour.js:
--------------------------------------------------------------------------------
1 | export default async function updateContactTour(request) {
2 | const contactId = request.params.contactId;
3 | try {
4 | const contactCls = new Parse.Query('contracts_Contactbook');
5 | const contactRes = await contactCls.get(contactId, { useMasterKey: true });
6 | if (contactRes) {
7 | const _contactRes = JSON.parse(JSON.stringify(contactRes));
8 | const tourStatus = _contactRes?.TourStatus?.length > 0 ? _contactRes.TourStatus : [];
9 | let updatedTourStatus = [];
10 | if (tourStatus.length > 0) {
11 | updatedTourStatus = [...tourStatus];
12 | const requestSignIndex = tourStatus.findIndex(
13 | obj => obj['requestSign'] === false || obj['requestSign'] === true
14 | );
15 | if (requestSignIndex !== -1) {
16 | updatedTourStatus[requestSignIndex] = { requestSign: true };
17 | } else {
18 | updatedTourStatus.push({ requestSign: true });
19 | }
20 | } else {
21 | updatedTourStatus = [{ requestSign: true }];
22 | }
23 | contactRes.set('TourStatus', updatedTourStatus);
24 | const updateRes = await contactRes.save(null, { useMasterKey: true });
25 | return updateRes;
26 | } else {
27 | throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'contact not found.');
28 | }
29 | } catch (err) {
30 | console.log('Err in contracts_Contactbook class ', err);
31 | throw err;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/updateTenant.js:
--------------------------------------------------------------------------------
1 | export default async function updateTenant(request) {
2 | const { tenantId, details } = request.params;
3 |
4 | if (!tenantId || !details) {
5 | throw new Parse.Error(400, 'Missing tenantId or details.');
6 | }
7 |
8 | if (!request.user) {
9 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'unauthorized');
10 | }
11 | try {
12 | const tenant = new Parse.Object('partners_Tenant');
13 | tenant.id = tenantId;
14 | // Update tenant details
15 | Object.keys(details).forEach(key => {
16 | tenant.set(key, details?.[key]);
17 | });
18 |
19 | const tenantRes = await tenant.save(null, { useMasterKey: true });
20 | if (tenantRes) {
21 | const res = JSON.parse(JSON.stringify(tenantRes));
22 | return res;
23 | }
24 | } catch (error) {
25 | throw error;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/updateTourStatus.js:
--------------------------------------------------------------------------------
1 | export default async function updateTourStatus(request) {
2 | const tourstatus = request.params.TourStatus;
3 | const extUserId = request.params.ExtUserId;
4 |
5 | if (request.user) {
6 | try {
7 | const updateUser = new Parse.Object('contracts_Users');
8 | updateUser.id = extUserId;
9 | updateUser.set('TourStatus', tourstatus);
10 | const res = await updateUser.save();
11 | return res;
12 | } catch (err) {
13 | console.log('Err ', err);
14 | const code = err?.code || 400;
15 | const msg = err?.message || 'Something went wrong.';
16 | throw new Parse.Error(code, msg);
17 | }
18 | }
19 | else {
20 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/cloud/parsefunction/updatesignaturetype.js:
--------------------------------------------------------------------------------
1 | export default async function updateSignatureType(request) {
2 | if (!request?.user) {
3 | throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
4 | }
5 | const SignatureType = request.params.SignatureType || [];
6 | if (SignatureType.length > 0) {
7 | const enabledSignTypes = SignatureType?.filter(x => x.enabled);
8 | const isDefaultSignTypeOnly =
9 | enabledSignTypes?.length === 1 && enabledSignTypes[0]?.name === 'default';
10 |
11 | if (enabledSignTypes.length === 0) {
12 | throw new Parse.Error(
13 | Parse.Error.INVALID_QUERY,
14 | 'At least one signature type should be enabled.'
15 | );
16 | } else if (isDefaultSignTypeOnly) {
17 | throw new Parse.Error(
18 | Parse.Error.INVALID_QUERY,
19 | 'At least one signature type other than the default should be enabled.'
20 | );
21 | } else {
22 | try {
23 | const orgQuery = new Parse.Query('contracts_Users');
24 | orgQuery.equalTo('UserId', {
25 | __type: 'Pointer',
26 | className: '_User',
27 | objectId: request.user.id,
28 | });
29 | const resUser = await orgQuery.first({ useMasterKey: true });
30 | if (resUser) {
31 | const newOrg = new Parse.Object('contracts_Users');
32 | newOrg.id = resUser.id;
33 | newOrg.set('SignatureType', SignatureType);
34 | const updateUserRes = await newOrg.save(null, { useMasterKey: true });
35 | if (updateUserRes) {
36 | const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes));
37 | return _updateUserRes;
38 | }
39 | } else {
40 | throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.');
41 | }
42 | } catch (err) {
43 | console.log('err in addorganization', err);
44 | const code = err?.code || 400;
45 | const msg = err?.message || 'Something went wrong.';
46 | throw new Parse.Error(code, msg);
47 | }
48 | }
49 | } else {
50 | throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide signature types.');
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Template';
7 | const schema = new Parse.Schema(className);
8 |
9 | schema.addString('Name');
10 | schema.addString('URL');
11 | schema.addString('Note');
12 | schema.addString('Description');
13 | schema.addArray('Signers');
14 | schema.addBoolean('IsArchive');
15 | schema.addArray('Placeholders');
16 | schema.addPointer('Folder', 'contracts_Template');
17 | schema.addString('Type');
18 | schema.addPointer('CreatedBy', '_User');
19 | schema.addPointer('ExtUserPtr', 'contracts_Users');
20 | schema.addBoolean('EnablePhoneOTP')
21 | schema.addBoolean('EnableEmailOTP')
22 | schema.addBoolean('SendinOrder')
23 | schema.addBoolean('SentToOthers')
24 | schema.addBoolean('AutomaticReminders')
25 |
26 |
27 |
28 | return schema.save();
29 | };
30 |
31 | /**
32 | *
33 | * @param {Parse} Parse
34 | */
35 | exports.down = async Parse => {
36 | const className = 'contracts_Template';
37 | const schema = new Parse.Schema(className);
38 |
39 | return schema.purge().then(() => schema.delete());
40 | };
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240110100110-update_document_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addBoolean('IsArchive');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('IsArchive');
20 | return schema.update();
21 | };
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240306123606-add_fields_contracts_users_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Users';
7 | const schema = new Parse.Schema(className);
8 | schema.addBoolean('HeaderDocId');
9 | schema.addString('Webhook');
10 | return schema.update();
11 | };
12 |
13 | /**
14 | *
15 | * @param {Parse} Parse
16 | */
17 | exports.down = async Parse => {
18 | const className = 'contracts_Users';
19 | const schema = new Parse.Schema(className);
20 | schema.deleteField('HeaderDocId');
21 | schema.deleteField('Webhook');
22 | return schema.update();
23 | };
24 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240408133151-update_contracts_document_cls.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addString('RequestBody');
9 | schema.addString('RequestSubject');
10 | return schema.update();
11 | };
12 |
13 | /**
14 | *
15 | * @param {Parse} Parse
16 | */
17 | exports.down = async Parse => {
18 | const className = 'contracts_Document';
19 | const schema = new Parse.Schema(className);
20 | schema.deleteField('RequestBody');
21 | schema.deleteField('RequestSubject');
22 | return schema.update();
23 | };
24 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240521184801-update_contracts_document_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addBoolean('SendMail');
9 | schema.addBoolean('SendCompletionMail');
10 | return schema.update();
11 | };
12 |
13 | /**
14 | *
15 | * @param {Parse} Parse
16 | */
17 | exports.down = async Parse => {
18 | const className = 'contracts_Document';
19 | const schema = new Parse.Schema(className);
20 | schema.deleteField('SendMail');
21 | schema.deleteField('SendCompletionMail');
22 | return schema.update();
23 | };
24 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240527194216-update_contracts_template_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Template';
7 | const schema = new Parse.Schema(className);
8 | schema.addArray('PublicRole');
9 | schema.addBoolean('IsPublic');
10 | return schema.update();
11 | };
12 |
13 | /**
14 | *
15 | * @param {Parse} Parse
16 | */
17 | exports.down = async Parse => {
18 | const className = 'contracts_Template';
19 | const schema = new Parse.Schema(className);
20 | schema.deleteField('PublicRole');
21 | schema.deleteField('IsPublic');
22 | return schema.update();
23 | };
24 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240701151539-update_contracts_users_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Users';
7 | const schema = new Parse.Schema(className);
8 | schema.addString('UserName');
9 | schema.addString('Tagline');
10 | schema.addBoolean('SearchIndex');
11 | return schema.update();
12 | };
13 |
14 | /**
15 | *
16 | * @param {Parse} Parse
17 | */
18 | exports.down = async Parse => {
19 | const className = 'contracts_Users';
20 | const schema = new Parse.Schema(className);
21 | schema.deleteField('UserName');
22 | schema.deleteField('Tagline');
23 | schema.deleteField('SearchIndex');
24 | return schema.update();
25 | };
26 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240708200454-create_multiuser_classes.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const teamschema = new Parse.Schema('contracts_Teams');
7 | teamschema.addString('Name');
8 | teamschema.addBoolean('IsActive', { defaultValue: true });
9 | teamschema.addPointer('ParentId', 'contracts_Teams');
10 | teamschema.addPointer('OrganizationId', 'contracts_Organizations');
11 | teamschema.addArray('Ancestors');
12 | await teamschema.save();
13 |
14 | const orgSchema = new Parse.Schema('contracts_Organizations');
15 | orgSchema.addString('Name');
16 | orgSchema.addBoolean('IsActive', { defaultValue: true });
17 | orgSchema.addPointer('TenantId', 'partners_Tenant');
18 | orgSchema.addPointer('CreatedBy', '_User');
19 | orgSchema.addPointer('ExtUserId', 'contracts_Users');
20 | await orgSchema.save();
21 |
22 | const schema = new Parse.Schema('contracts_Users');
23 | schema.addBoolean('IsDisabled', { defaultValue: false });
24 | schema.addPointer('OrganizationId', 'contracts_Organizations');
25 | schema.addArray('TeamIds');
26 | await schema.update();
27 |
28 | const templateschema = new Parse.Schema('contracts_Template');
29 | templateschema.addArray('SharedWith');
30 | return templateschema.update();
31 | };
32 |
33 | /**
34 | *
35 | * @param {Parse} Parse
36 | */
37 | exports.down = async Parse => {
38 | const teamschema = new Parse.Schema('contracts_Teams');
39 | await teamschema.purge().then(() => teamschema.delete());
40 |
41 | const orgSchema = new Parse.Schema('contracts_Organizations');
42 | await orgSchema.purge().then(() => orgSchema.delete());
43 |
44 | const schema = new Parse.Schema('contracts_Users');
45 | schema.deleteField('IsDisabled');
46 | schema.deleteField('OrganizationId');
47 | schema.deleteField('TeamIds');
48 | await schema.update();
49 |
50 | const templateschema = new Parse.Schema('contracts_Template');
51 | templateschema.deleteField('SharedWith');
52 | return templateschema.update();
53 | };
54 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240710163936-addfield_declinereason_doc_cls.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addString('DeclineReason');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('DeclineReason');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240723162947-update_teams_org_clp.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const teamSchema = new Parse.Schema('contracts_Teams');
7 | teamSchema.setCLP({
8 | get: {},
9 | find: {},
10 | count: {},
11 | create: {},
12 | update: {},
13 | delete: {},
14 | addField: {},
15 | });
16 | await teamSchema.update();
17 |
18 | const orgSchema = new Parse.Schema('contracts_Organizations');
19 | orgSchema.setCLP({
20 | get: {},
21 | find: {},
22 | count: {},
23 | create: {},
24 | update: {},
25 | delete: {},
26 | addField: {},
27 | });
28 |
29 | return orgSchema.update();
30 | };
31 |
32 | /**
33 | *
34 | * @param {Parse} Parse
35 | */
36 | exports.down = async Parse => {
37 | const teamSchema = new Parse.Schema('contracts_Teams');
38 | teamSchema.setCLP({
39 | get: { '*': true },
40 | find: { '*': true },
41 | count: { '*': true },
42 | create: { '*': true },
43 | update: { '*': true },
44 | delete: { '*': true },
45 | addField: { '*': true },
46 | });
47 | await teamSchema.update();
48 |
49 | const orgSchema = new Parse.Schema('contracts_Organizations');
50 | orgSchema.setCLP({
51 | get: { '*': true },
52 | find: { '*': true },
53 | count: { '*': true },
54 | create: { '*': true },
55 | update: { '*': true },
56 | delete: { '*': true },
57 | addField: { '*': true },
58 | });
59 |
60 | return orgSchema.update();
61 | };
62 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240726114557-update_contracts_template_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Template';
7 | const schema = new Parse.Schema(className);
8 | schema.addString('OriginIp');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Template';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('OriginIp');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240806141611-update_contracts_users_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Users';
7 | const schema = new Parse.Schema(className);
8 | schema.addString('Language');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Users';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('Language');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240822201043-addfield_doccls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addBoolean('IsSignyourself');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('IsSignyourself');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240903170628-update_contracts_document_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addPointer('DeclineBy', '_User');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('DeclineBy');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240913121404-add_isenableotp_doc.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const templateSchema = new Parse.Schema('contracts_Template');
7 | templateSchema.addBoolean('IsEnableOTP');
8 | await templateSchema.update();
9 |
10 | const className = 'contracts_Document';
11 | const schema = new Parse.Schema(className);
12 | schema.addBoolean('IsEnableOTP');
13 | return schema.update();
14 | };
15 |
16 | /**
17 | *
18 | * @param {Parse} Parse
19 | */
20 | exports.down = async Parse => {
21 | const templateSchema = new Parse.Schema('contracts_Template');
22 | templateSchema.deleteField('IsEnableOTP');
23 | await templateSchema.update();
24 |
25 | const className = 'contracts_Document';
26 | const schema = new Parse.Schema(className);
27 | schema.deleteField('IsEnableOTP');
28 | return schema.update();
29 | };
30 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20240926163209-add_istourenabled_doc_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async (Parse) => {
6 | const templateSchema = new Parse.Schema('contracts_Template');
7 | templateSchema.addBoolean('IsTourEnabled');
8 | await templateSchema.update();
9 |
10 | const className = 'contracts_Document';
11 | const schema = new Parse.Schema(className);
12 | schema.addBoolean('IsTourEnabled');
13 | return schema.update();
14 | };
15 |
16 | /**
17 | *
18 | * @param {Parse} Parse
19 | */
20 | exports.down = async (Parse) => {
21 | const templateSchema = new Parse.Schema('contracts_Template');
22 | templateSchema.deleteField('IsTourEnabled');
23 | await templateSchema.update();
24 |
25 | const className = 'contracts_Document';
26 | const schema = new Parse.Schema(className);
27 | schema.deleteField('IsTourEnabled');
28 | return schema.update();
29 | };
30 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241004104551-fileadapterId_doccls.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addString('FileAdapterId');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('FileAdapterId');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241106180102-add_signaturetype_field.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const docSchema = new Parse.Schema('contracts_Document');
7 | docSchema.addArray('SignatureType');
8 | await docSchema.update();
9 |
10 | const templateSchema = new Parse.Schema('contracts_Template');
11 | templateSchema.addArray('SignatureType');
12 | await templateSchema.update();
13 |
14 | const extUserSchema = new Parse.Schema('contracts_Users');
15 | extUserSchema.addArray('SignatureType');
16 | await extUserSchema.update();
17 |
18 | const tenantSchema = new Parse.Schema('partners_Tenant');
19 | tenantSchema.addArray('SignatureType');
20 | return tenantSchema.update();
21 | };
22 |
23 | /**
24 | *
25 | * @param {Parse} Parse
26 | */
27 | exports.down = async Parse => {
28 | const docSchema = new Parse.Schema('contracts_Document');
29 | docSchema.deleteField('SignatureType');
30 | await docSchema.update();
31 |
32 | const templateSchema = new Parse.Schema('contracts_Template');
33 | docSchema.deleteField('SignatureType');
34 | await templateSchema.update();
35 |
36 | const extUserSchema = new Parse.Schema('contracts_Users');
37 | docSchema.deleteField('SignatureType');
38 | await extUserSchema.update();
39 |
40 | const tenantSchema = new Parse.Schema('partners_Tenant');
41 | docSchema.deleteField('SignatureType');
42 | return tenantSchema.update();
43 | };
44 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241114175425-add_notifyonsignatures_field.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const docSchema = new Parse.Schema('contracts_Document');
7 | docSchema.addBoolean('NotifyOnSignatures');
8 | await docSchema.update();
9 |
10 | const templateSchema = new Parse.Schema('contracts_Template');
11 | templateSchema.addBoolean('NotifyOnSignatures');
12 | await templateSchema.update();
13 |
14 | const extUserSchema = new Parse.Schema('contracts_Users');
15 | extUserSchema.addBoolean('NotifyOnSignatures');
16 | return extUserSchema.update();
17 | };
18 |
19 | /**
20 | *
21 | * @param {Parse} Parse
22 | */
23 | exports.down = async Parse => {
24 | const docSchema = new Parse.Schema('contracts_Document');
25 | docSchema.deleteField('NotifyOnSignatures');
26 | await docSchema.update();
27 |
28 | const templateSchema = new Parse.Schema('contracts_Template');
29 | templateSchema.deleteField('NotifyOnSignatures');
30 | await templateSchema.update();
31 |
32 | const extUserSchema = new Parse.Schema('contracts_Users');
33 | docSchema.deleteField('NotifyOnSignatures');
34 | return extUserSchema.update();
35 | };
36 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241205115937-add_bcc_field_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const docSchema = new Parse.Schema('contracts_Document');
7 | docSchema.addArray('Bcc');
8 | await docSchema.update();
9 |
10 | const templateSchema = new Parse.Schema('contracts_Template');
11 | templateSchema.addArray('Bcc');
12 | await templateSchema.update();
13 |
14 | };
15 |
16 | /**
17 | *
18 | * @param {Parse} Parse
19 | */
20 | exports.down = async Parse => {
21 | const docSchema = new Parse.Schema('contracts_Document');
22 | docSchema.deleteField('Bcc');
23 | await docSchema.update();
24 |
25 | const templateSchema = new Parse.Schema('contracts_Template');
26 | templateSchema.deleteField('Bcc');
27 | await templateSchema.update();
28 | };
29 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241205163817-add_redirecturl_field_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const docSchema = new Parse.Schema('contracts_Document');
7 | docSchema.addString('RedirectUrl');
8 | await docSchema.update();
9 |
10 | const templateSchema = new Parse.Schema('contracts_Template');
11 | templateSchema.addString('RedirectUrl');
12 | await templateSchema.update();
13 |
14 | };
15 |
16 | /**
17 | *
18 | * @param {Parse} Parse
19 | */
20 | exports.down = async Parse => {
21 | const docSchema = new Parse.Schema('contracts_Document');
22 | docSchema.deleteField('RedirectUrl');
23 | await docSchema.update();
24 |
25 | const templateSchema = new Parse.Schema('contracts_Template');
26 | templateSchema.deleteField('RedirectUrl');
27 | await templateSchema.update();
28 | };
29 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241227112339-update_contracts_document_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addBoolean('AllowModifications');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('AllowModifications');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20241227125916-update_contracts_template_cls_cjs.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Template';
7 | const schema = new Parse.Schema(className);
8 | schema.addBoolean('AllowModifications');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Template';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('AllowModifications');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20250411095519-add_templateid_field.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const className = 'contracts_Document';
7 | const schema = new Parse.Schema(className);
8 | schema.addPointer('TemplateId', 'contracts_Template');
9 | return schema.update();
10 | };
11 |
12 | /**
13 | *
14 | * @param {Parse} Parse
15 | */
16 | exports.down = async Parse => {
17 | const className = 'contracts_Document';
18 | const schema = new Parse.Schema(className);
19 | schema.deleteField('TemplateId');
20 | return schema.update();
21 | };
22 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/migrations/20250427105912-add_name_field_user_cls.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Parse} Parse
4 | */
5 | exports.up = async Parse => {
6 | const userschema = new Parse.Schema('_User');
7 | userschema.addString('name');
8 | return userschema.update(null, { useMasterKey: true });
9 | };
10 |
11 | /**
12 | *
13 | * @param {Parse} Parse
14 | */
15 | exports.down = async Parse => {
16 | const userschema = new Parse.Schema('_User');
17 | userschema.deleteField('name');
18 | return userschema.update(null, { useMasterKey: true });
19 | };
20 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/databases/seeders/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/databases/seeders/.gitkeep
--------------------------------------------------------------------------------
/apps/OpenSignServer/exports/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/exports/.gitkeep
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/custom_email.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Hello!
9 | This is a notice regarding your account:
10 | {{username}}
11 |
12 | {{appName}}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/custom_email.txt:
--------------------------------------------------------------------------------
1 | Hello!
2 |
3 | This is a notice regarding your account:
4 | {{username}}
5 |
6 | {{appName}}
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/custom_email_subject.txt:
--------------------------------------------------------------------------------
1 | Account Notice - {{appName}}
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/password_reset_email.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Hello!
9 | You requested to reset the password for your account:
10 | {{username}}
11 | Click the button below to reset your password:
12 |
13 | Verify email
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/password_reset_email.txt:
--------------------------------------------------------------------------------
1 | Hello!
2 |
3 | You requested to reset the password for your account:
4 |
5 | {{username}}
6 |
7 | Click the link below to reset your password:
8 |
9 | {{{link}}}
10 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/password_reset_email_subject.txt:
--------------------------------------------------------------------------------
1 | Password Reset
2 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/verification_email.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Welcome!
9 | Click the button below to verify your email address:
10 |
11 | Verify email
12 |
13 | {{appName}}
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/verification_email.txt:
--------------------------------------------------------------------------------
1 | Welcome!
2 |
3 | Click the link below to verify your email address:
4 |
5 | {{{link}}}
6 |
7 | {{appName}}
--------------------------------------------------------------------------------
/apps/OpenSignServer/files/verification_email_subject.txt:
--------------------------------------------------------------------------------
1 | {{appName}} Email Address Verification
--------------------------------------------------------------------------------
/apps/OpenSignServer/font/times.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/font/times.ttf
--------------------------------------------------------------------------------
/apps/OpenSignServer/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES6",
4 | "module": "commonjs"
5 | }
6 | }
--------------------------------------------------------------------------------
/apps/OpenSignServer/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/logo.png
--------------------------------------------------------------------------------
/apps/OpenSignServer/migrationdb/createContactIndex.js:
--------------------------------------------------------------------------------
1 | import dotenv from 'dotenv';
2 | import { MongoClient } from 'mongodb';
3 | import { generateId } from '../Utils.js';
4 | dotenv.config();
5 |
6 | export default async function createContactIndex() {
7 | // Provide the complete MongoDB connection URL with the database name
8 | const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/dev'; // Replace with your MongoDB URI
9 | const client = new MongoClient(uri);
10 | try {
11 | await client.connect();
12 | const database = client.db();
13 |
14 | const migrationCollection = database.collection('Migrationdb');
15 | const migrationName = 'contactIndex_1';
16 |
17 | // Check if the migration has already been executed
18 | const migrationExists = await migrationCollection.findOne({ name: migrationName });
19 |
20 | if (migrationExists) {
21 | console.log(' INFO No migrations were executed, database schema was already up to date.');
22 | console.log(' SUCCESS Successfully ran indexed migrations directly on db.');
23 | return;
24 | }
25 |
26 | const collection = database.collection('contracts_Contactbook');
27 |
28 | // Create the unique index, but only on documents where IsImported is true
29 | const query = {
30 | IsImported: { $eq: true },
31 | $or: [{ IsDeleted: false }, { IsDeleted: { $eq: false } }],
32 | }; // Include documents with IsImported: true and IsDeleted not true
33 | await collection.createIndex(
34 | { _p_CreatedBy: 1, Email: 1, IsImported: 1 },
35 | { unique: true, partialFilterExpression: query }
36 | );
37 |
38 | // Save the migration record in the migrationdb collection
39 | await migrationCollection.insertOne({
40 | _id: generateId(10),
41 | name: migrationName,
42 | _created_at: new Date(),
43 | _updated_at: new Date(),
44 | executedAt: new Date(),
45 | details: 'Created unique index on CreatedBy, IsImported, Email',
46 | });
47 |
48 | const migrationdb = database.collection('_SCHEMA');
49 | // create migrationdb SCHEM migrationdb
50 |
51 | // Document to be inserted
52 | const schemaDocument = {
53 | _id: 'Migrationdb',
54 | objectId: 'string',
55 | name: 'string',
56 | updatedAt: 'date',
57 | createdAt: 'date',
58 | executedAt: 'date',
59 | details: 'string',
60 | };
61 |
62 | // Insert the document
63 | await migrationdb.insertOne(schemaDocument);
64 | console.log(' Unique index created successfully.');
65 | console.log(' SUCCESS Successfully ran indexed migrations directly on db.');
66 | } catch (error) {
67 | console.log(' ERROR running indexed migration:', error);
68 | } finally {
69 | await client.close();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "open_sign_server",
3 | "version": "2.21.1",
4 | "description": "An example Parse API server using the parse-server module",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/ParsePlatform/parse-server-example"
8 | },
9 | "license": "MIT",
10 | "main": "index.js",
11 | "scripts": {
12 | "coverage": "TESTING=true nyc jasmine",
13 | "lint": "eslint --cache ./cloud && eslint --cache index.js && eslint --cache ./spec",
14 | "lint-fix": "eslint --cache --fix ./cloud && eslint --cache --fix index.js && eslint --cache --fix ./spec",
15 | "prettier": "prettier --write '{cloud,spec}/{**/*,*}.js' 'index.js'",
16 | "start": "node index.js",
17 | "test": "mongodb-runner start && TESTING=true jasmine",
18 | "watch": "nodemon index.js"
19 | },
20 | "dependencies": {
21 | "@aws-sdk/client-s3": "^3.824.0",
22 | "@aws-sdk/s3-request-presigner": "^3.824.0",
23 | "@parse/fs-files-adapter": "^3.0.0",
24 | "@parse/s3-files-adapter": "^4.1.1",
25 | "@pdf-lib/fontkit": "^1.1.1",
26 | "@signpdf/placeholder-pdf-lib": "^3.2.6",
27 | "@signpdf/signer-p12": "^3.2.4",
28 | "@signpdf/signpdf": "^3.2.5",
29 | "aws-sdk": "^2.1692.0",
30 | "axios": "^1.9.0",
31 | "cors": "^2.8.5",
32 | "date-fns-tz": "^3.2.0",
33 | "dotenv": "^16.5.0",
34 | "express": "^5.1.0",
35 | "form-data": "^4.0.2",
36 | "generate-api-key": "^1.0.2",
37 | "googleapis": "^149.0.0",
38 | "mailgun.js": "^12.0.2",
39 | "mongodb": "^6.17.0",
40 | "multer": "^2.0.1",
41 | "multer-s3": "^3.0.1",
42 | "node-forge": "^1.3.1",
43 | "nodemailer": "^7.0.3",
44 | "parse": "^6.1.1",
45 | "parse-dbtool": "^1.2.0",
46 | "parse-server": "^8.2.1",
47 | "parse-server-api-mail-adapter": "^4.1.0",
48 | "pdf-lib": "^1.17.1",
49 | "posthog-node": "^4.18.0",
50 | "qrcode": "^1.5.4",
51 | "rate-limiter-flexible": "^7.1.1",
52 | "speakeasy": "^2.0.0",
53 | "ws": "^8.18.2"
54 | },
55 | "type": "module",
56 | "devDependencies": {
57 | "@babel/eslint-parser": "^7.27.5",
58 | "eslint": "^9.28.0",
59 | "jasmine": "^5.7.1",
60 | "mongodb-runner": "^5.8.3",
61 | "nodemon": "^3.1.10",
62 | "nyc": "^17.1.0",
63 | "prettier": "^3.5.3"
64 | },
65 | "overrides": {
66 | "ws": "$ws",
67 | "parse": "$parse"
68 | },
69 | "engines": {
70 | "node": "18 || 20 || 22"
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/pdfFile/emudhra-test-class2.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/pdfFile/emudhra-test-class2.pfx
--------------------------------------------------------------------------------
/apps/OpenSignServer/pdfFile/sample.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/pdfFile/sample.pdf
--------------------------------------------------------------------------------
/apps/OpenSignServer/public/assets/images/parse-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/apps/OpenSignServer/public/assets/images/parse-logo.png
--------------------------------------------------------------------------------
/apps/OpenSignServer/scalingo.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Parse Server Example",
3 | "description": "An example Parse API server using the parse-server module",
4 | "repository": "https://github.com/ParsePlatform/parse-server-example",
5 | "logo": "https://avatars0.githubusercontent.com/u/1294580?v=3&s=200",
6 | "env": {
7 | "PARSE_MOUNT": {
8 | "description": "Configure Parse API route.",
9 | "value": "/parse"
10 | },
11 | "APP_ID": {
12 | "description": "A unique identifier for your app.",
13 | "value": ""
14 | },
15 | "MASTER_KEY": {
16 | "description": "A key that overrides all permissions. Keep this secret.",
17 | "value": ""
18 | },
19 | "DATABASE_URI": {
20 | "description": "Connection string for your database.",
21 | "value": "$SCALINGO_MONGO_URL"
22 | }
23 | },
24 | "addons": ["scalingo-mongodb"]
25 | }
26 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/spec/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "jasmine": true
4 | },
5 | "globals": {
6 | "Parse": true
7 | },
8 | "rules": {
9 | "no-console": [0],
10 | "no-var": "error"
11 | }
12 | }
--------------------------------------------------------------------------------
/apps/OpenSignServer/spec/Tests.spec.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | describe('Parse Server example', () => {
3 | Parse.User.enableUnsafeCurrentUser();
4 | it('call function', async () => {
5 | const result = await Parse.Cloud.run('hello');
6 | expect(result).toBe('Hi');
7 | });
8 | it('call async function', async () => {
9 | const result = await Parse.Cloud.run('asyncFunction');
10 | expect(result).toBe('Hi async');
11 | });
12 | it('failing test', async () => {
13 | const obj = new Parse.Object('Test');
14 | try {
15 | await obj.save();
16 | fail('should not have been able to save test object.');
17 | } catch (e) {
18 | expect(e).toBeDefined();
19 | expect(e.code).toBe(9001);
20 | expect(e.message).toBe('Saving test objects is not available.');
21 | }
22 | });
23 | it('coverage for /', async () => {
24 | const { data, headers } = await axios.get('http://localhost:30001/');
25 | expect(headers['content-type']).toContain('text/html');
26 | expect(data).toBe('I dream of being a website. Please star the parse-server repo on GitHub!');
27 | });
28 | it('coverage for /test', async () => {
29 | const { data, headers } = await axios.get('http://localhost:30001/test');
30 | expect(headers['content-type']).toContain('text/html');
31 | expect(data).toContain('Parse Server Example');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/spec/helper.js:
--------------------------------------------------------------------------------
1 | import { startParseServer, stopParseServer, dropDB } from './utils/test-runner.js';
2 | beforeAll(async () => {
3 | await startParseServer();
4 | }, 100 * 60 * 2);
5 |
6 | afterAll(async () => {
7 | await dropDB();
8 | await stopParseServer();
9 | });
10 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/spec/support/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "**/*[sS]pec.js"
5 | ],
6 | "helpers": ["helper.js"],
7 | "stopSpecOnExpectationFailure": false,
8 | "random": false
9 | }
10 |
--------------------------------------------------------------------------------
/apps/OpenSignServer/spec/utils/test-runner.js:
--------------------------------------------------------------------------------
1 | import http from 'http';
2 | import { ParseServer } from 'parse-server';
3 | import { app, config } from '../../index.js';
4 |
5 | export const dropDB = async () => {
6 | await Parse.User.logOut();
7 | return await Parse.Server.database.deleteEverything(true);
8 | };
9 | let parseServerState = {};
10 |
11 | /**
12 | * Starts the ParseServer instance
13 | * @param {Object} parseServerOptions Used for creating the `ParseServer`
14 | * @return {Promise} Runner state
15 | */
16 | export async function startParseServer() {
17 | delete config.databaseAdapter;
18 | const parseServerOptions = Object.assign(config, {
19 | databaseURI: 'mongodb://localhost:27017/parse-test',
20 | masterKey: 'test',
21 | javascriptKey: 'test',
22 | appId: 'test',
23 | port: 30001,
24 | mountPath: '/test',
25 | serverURL: `http://localhost:30001/test`,
26 | logLevel: 'error',
27 | silent: true,
28 | });
29 | const parseServer = new ParseServer(parseServerOptions);
30 | await parseServer.start();
31 | app.use(parseServerOptions.mountPath, parseServer.app);
32 | const httpServer = http.createServer(app);
33 | await new Promise(resolve => httpServer.listen(parseServerOptions.port, resolve));
34 | Object.assign(parseServerState, {
35 | parseServer,
36 | httpServer,
37 | parseServerOptions,
38 | });
39 | return parseServerOptions;
40 | }
41 |
42 | /**
43 | * Stops the ParseServer instance
44 | * @return {Promise}
45 | */
46 | export async function stopParseServer() {
47 | await new Promise(resolve => parseServerState.httpServer.close(resolve));
48 | parseServerState = {};
49 | }
50 |
--------------------------------------------------------------------------------
/apps/localstack/localstack-script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | awslocal s3api \
4 | create-bucket --bucket my-bucket \
5 | --create-bucket-configuration LocationConstraint=eu-central-1 \
6 | --region eu-central-1
--------------------------------------------------------------------------------
/apps/mongo/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the official MongoDB imagee
2 | FROM mongo:latest
3 |
4 | # Create a directory to host initialization scripts
5 | # RUN mkdir -p /docker-entrypoint-initdb.d
6 |
7 | # Copy default data JSON files to the initialization directory
8 | # COPY ./default-data/*.json /docker-entrypoint-initdb.d/
9 |
10 | # Execute the initialization script during container startup
11 | CMD ["mongod"]
--------------------------------------------------------------------------------
/cert/local_dev.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDxTCCAq2gAwIBAgIUAZQ9QST2eBZz5k9pCa//mHQVm1QwDQYJKoZIhvcNAQEL
3 | BQAwcjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQKDA1P
4 | cGVuU2lnbiBMYWJzMREwDwYDVQQDDAhPcGVuU2lnbjElMCMGCSqGSIb3DQEJARYW
5 | aGVsbG9Ab3BlbnNpZ25sYWJzLmNvbTAeFw0yMzExMTcxOTQ0MzZaFw0yNDExMTYx
6 | OTQ0MzZaMHIxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UE
7 | CgwNT3BlblNpZ24gTGFiczERMA8GA1UEAwwIT3BlblNpZ24xJTAjBgkqhkiG9w0B
8 | CQEWFmhlbGxvQG9wZW5zaWdubGFicy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
9 | DwAwggEKAoIBAQDLRKLjCSrvV1zAY2leWxCvdKTUaThpQO8nWPE/4v5ilMU2aRON
10 | krAnli0LUfQ/tIRWNurxwVjJ7HrW3ICLn05GBLjm2AUCfuMbJCvOEEdmFJqRY04n
11 | 12fBZWz2KtzbZEIBVxLhc4E4g+Rz68hQA2fqwNuFdyGkkIbhVXpZIePEppqRmw+2
12 | uuDvIzJ77rdDaLqwwPoHWenZ2uZTedKXx7PGYs98psg35GvcpssqAJGAIAi9Rzg/
13 | ZV4oSpGXCjn/TJy61zTDbmPFCS/rC1XBWzBQfwDeBPDI18W6gPVX6N4dp0Ao+n8Q
14 | txeI6g4FzMH91KPbdbZXxm8rZqXj87VQs9trAgMBAAGjUzBRMB0GA1UdDgQWBBRN
15 | NtRPagnqovdmbrdhSUON9Rwd3TAfBgNVHSMEGDAWgBRNNtRPagnqovdmbrdhSUON
16 | 9Rwd3TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBrcPyA7GHq
17 | +ol9qjy9HijpoU5MaEiV9v9H8/0v7KoXUND3rMl37yFyjxGN8uda8WxpEhE2eFnk
18 | Xjtm2NgPrv8qeYHor/A3y5RfQhnlCY4kE1bREZGhcuKihR4rOtmComwFjx4Ibwwj
19 | 4nKsflj6rXcWKSfSNHLkXFXHPYwyqRsKdtClrD/8YJn6LeeMlMjIYGGP4qyi2WwS
20 | Z8hExWGEMaMWiA9rxTMX6iu/parGH/pWU/55Os3WlcHPhlvqchBkQFJ+f8b+NYz0
21 | vIHQgwn4K5WMsZVLxoiUcU7cSqE/qhnP+pzBf8lRaYwd+zUznDvzpKKz6nFgeHok
22 | s8BK7JAKkIsl
23 | -----END CERTIFICATE-----
24 |
--------------------------------------------------------------------------------
/cert/local_dev.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | Proc-Type: 4,ENCRYPTED
3 | DEK-Info: DES-EDE3-CBC,5932FA9F02938D1B
4 |
5 | 6gkkZP80WrVnR3dVwkimtfirSeYNXZlrXXBv+Ddjyq7FScqca7svJFd8ObC0xXjg
6 | nbxChDKS8SXcSjsNCTzixG0QReO5vaqovrpQoYbkSQ9GRMIVV8WuWNzlyMnypNJ4
7 | Z6hdpd5nkc1hIP8A6WcY3lA8msyHceU9IidEEb75CE743qsvUMko+XvqntZx/LNe
8 | 0uK8Bs+cXeDzolpNX8ORKBTAOMii+WPlN2l+9ldsWTECEk4GmWa51QfpKouLxz5E
9 | u7fuGuku/nPKGb4Yj7sCgaD91UabRksDLS9UGDBqeNL+mogG3gY/Iu0/q2cUs6XR
10 | x1W6KW1eJHnOf1pAp7+G/zNqzdsxI3pnoR+nsV6/G0glBLar+Xqc99B568lnUWWv
11 | 5NGN3Buz1axx1jPKIknDcT4Skmvt6TcmgrjoCQ9XvmNKVClpExQ+dKPmJI/EVNoU
12 | jjDZyfghcJ6BEMcTgoOBDiUrPM0273sb89u/AzyUA1tTciW2KARz6cOUTPWVRSRn
13 | 4yXpkA4BJDpxRmK68BXorZLNxtvHk+on80c9tu5e+IVa3Gu1K7gc269TPmlIolAM
14 | v//i+jpwJ4Pe2IGVYdojMr15useUv7JC6/Kconnkx4q9rkMriguuXoQt8qW3kvEs
15 | Ur8KuibtDqhz2zGbsKboQFMOd6cdd+63dJCGAUqk4hFrSikTw3LhkXNcg9GZHq1z
16 | WFAfaA3x2jd+kJJ5xg8xMVEHax5IAOXDL2ektyPFpI1UZOuTc2i7FK6Y0NnXPkSN
17 | G/+DsKdLWT943mPfZj01mTRi3MgseDXsHMHGmmPxW9J4jv+WW4OdpHvd474QzJ8b
18 | vQmyiKq4XPHsuQUkzHVPbTrGe1B9z4p97YQKdEfXP2ChGFsUHCYQdpHyXwie2+pq
19 | E2rc7Bai0OuL0anYMSIvDrJ0DE8mVVaFur1b2Uz6ieCDlrOXnzD1BrcleiZem7og
20 | on/3oCUK+qxibCCcd5Hg2HtPusa43U0/UbCrqb2sww9iN36DLdtef/jlozKNiBx9
21 | e8ZztF6GtAKhIdgGW/M9TXMUZOYr7aaXO71MsqhwpVWZ5dNqagOBzhmd7Etokf1H
22 | O0WxJZ5XPDsnlKwYq86ssK+2RCNYAuvZoM3dRCysPvXoBFmsmHDzKdbKcckd8Vxr
23 | 6P1yaCkB/iX55dUqwKfIuqxY3m4MA2Us9DD0BRxZOSUqHhzHHSogsLhqLQEQENA4
24 | U9N/v/za81UaU8nfkAswsGlTdTKjWH6Fzc0NeagbEFtpUaG/WIHPesUzU7ZNvMzR
25 | SQACVWl62Dley2g2eAgcrsIn78MbwNJI2YN5eXIw0K2MiMlGXWOEvkjIIVfjc0/d
26 | QxLFJwqShZBVO+jnAJ8jti7mP6PgskjtfHNAIphRJ4fm9h/Ns1YMpipBRVBDhbwY
27 | AOVT4bRw9Q3O5I0pe10ZdViAhexegQ8yGt3pUlKaUf9GRwIFEknjZ5Pc98V/R/wC
28 | INSIOZzDHj2uyZ3p7ToF1Z6kVVbbyfqDOnxUiV2ykR8ZqQMXNWcEJKH8qRqI+VHf
29 | oszD2BQvXgkWdrJtHuHjJCdDl03Y+daS5yP8IKTDucHvRv4ZSMghZ34SJTw5MaBP
30 | -----END RSA PRIVATE KEY-----
31 |
--------------------------------------------------------------------------------
/cert/local_dev.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenSignLabs/OpenSign/b0e0b38e8f976cebfc23a4954d764179f7a9bcec/cert/local_dev.pfx
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | server:
3 | image: opensign/opensignserver:main
4 | container_name: OpenSignServer-container
5 | volumes:
6 | - opensign-files:/usr/src/app/files
7 | ports:
8 | - "8080:8080"
9 | depends_on:
10 | - mongo
11 | env_file: .env.prod
12 | environment:
13 | - NODE_ENV=production
14 | - SERVER_URL=${HOST_URL:-https://localhost:3001}/api/app
15 | - PUBLIC_URL=${HOST_URL:-https://localhost:3001}
16 | networks:
17 | - app-network
18 | mongo:
19 | image: mongo:latest
20 | container_name: mongo-container
21 | volumes:
22 | - data-volume:/data/db
23 | ports:
24 | - "27018:27017"
25 | networks:
26 | - app-network
27 | client:
28 | image: opensign/opensign:main
29 | container_name: OpenSign-container
30 | depends_on:
31 | - server
32 | env_file: .env.prod
33 | ports:
34 | - "3000:3000"
35 | networks:
36 | - app-network
37 | caddy:
38 | image: caddy:latest
39 | container_name: caddy-container
40 | ports:
41 | - "3001:3001"
42 | - "80:80"
43 | - "443:443"
44 | - "443:443/udp"
45 | volumes:
46 | - ./Caddyfile:/etc/caddy/Caddyfile
47 | - caddy_data:/data
48 | - caddy_config:/config
49 | networks:
50 | - app-network
51 | environment:
52 | - HOST_URL=${HOST_URL:-localhost:3001}
53 | networks:
54 | app-network:
55 | driver: bridge
56 |
57 | volumes:
58 | data-volume:
59 | web-root:
60 | caddy_data:
61 | caddy_config:
62 | opensign-files:
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "opensign",
3 | "version": "1.0.6",
4 | "description": "Free and open source alternative to DocuSign",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "prepare": "husky install",
9 | "lint-staged-changes": "lint-staged"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "github.com/opensignlabs/opensign"
14 | },
15 | "keywords": [
16 | "digital",
17 | "signature",
18 | "e-signature",
19 | "docusign",
20 | "electronic",
21 | "signature"
22 | ],
23 | "author": "OpenSignLabs",
24 | "license": "AGPL-3.0",
25 | "devDependencies": {
26 | "husky": "^8.0.0",
27 | "lint-staged": "^15.1.0",
28 | "prettier": "3.1.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------