Compare commits

..
40 Commits
Author SHA1 Message Date
AndrewandGitHub 096d5962a3 Merge pull request #1221 from OpenSignLabs/validation 2024-09-19 11:30:35 +05:30
prafull-opensignlabs 9ea36f94a7 fix: enableOTP not working properly in template 2024-09-19 11:28:13 +05:30
AndrewandGitHub 2b66df992f Merge pull request #1220 from OpenSignLabs/validation 2024-09-19 10:27:18 +05:30
prafull-opensignlabs ff3c31975e refactor: remove extra space 2024-09-19 10:26:35 +05:30
AndrewandGitHub beaa5eca69 Merge pull request #1219 from OpenSignLabs/validation 2024-09-18 21:17:16 +05:30
prafull-opensignlabs b98040faac fix: document decline event not trigger on revoke 2024-09-18 21:15:31 +05:30
AndrewandGitHub fbbff0df61 Merge pull request #1218 from OpenSignLabs/validation 2024-09-18 19:57:46 +05:30
prafull-opensignlabs 07d5f393c0 fix: document viewed event not trigger 2024-09-18 19:56:47 +05:30
AndrewandGitHub 8220b15a29 Merge pull request #1217 from OpenSignLabs/validation
refactor: add enableOTP in allowedkeys in update doc
2024-09-18 19:27:42 +05:30
prafull-opensignlabs 7cf638b2be refactor: add enableOTP in allowedkeys in update doc 2024-09-18 19:22:41 +05:30
prafull-opensignlabsandGitHub 30fb8f31e3 Merge pull request #1216 from OpenSignLabs/validation
fix: blank page appear when try to add typed signature
2024-09-18 18:10:37 +05:30
prafull-opensignlabs ec4d875547 fix: blank page appear when try to add typed signature 2024-09-18 18:09:18 +05:30
AndrewandGitHub 43eee63df2 Merge pull request #1215 from OpenSignLabs/validation 2024-09-18 14:36:30 +05:30
prafull-opensignlabs 4caf9f598a refactor: change variable from isDisableOTP to isEnableOTP 2024-09-18 14:32:45 +05:30
AndrewandGitHub 107eaca8f0 Merge pull request #1213 from OpenSignLabs/validation
feat: add disable OTP feature to directly sign document without verification
2024-09-17 18:31:15 +05:30
prafull-opensignlabs cc11848346 feat: add disable OTP feature to directly sign document without verification 2024-09-17 18:27:21 +05:30
ZathielandGitHub c8ecd34bd3 Merge pull request #1148 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/lint-staged-15.2.10
build(deps-dev): bump lint-staged from 15.2.9 to 15.2.10 in /apps/OpenSign
2024-09-13 20:00:31 +02:00
ZathielandGitHub d4a4eb3248 Merge pull request #1182 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/mongoose-8.6.1
build(deps): bump mongoose from 8.6.0 to 8.6.1 in /apps/OpenSignServer
2024-09-13 20:00:01 +02:00
ZathielandGitHub f782733397 Merge pull request #1186 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/jasmine-5.3.0
build(deps-dev): bump jasmine from 5.2.0 to 5.3.0 in /apps/OpenSignServer
2024-09-13 19:59:13 +02:00
ZathielandGitHub 7720eddc47 Merge pull request #1183 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/nodemailer-6.9.15
build(deps): bump nodemailer from 6.9.14 to 6.9.15 in /apps/OpenSignServer
2024-09-13 19:58:58 +02:00
AndrewandGitHub 71170a373a Merge pull request #1205 from OpenSignLabs/validation 2024-09-13 12:58:49 +05:30
prafull-opensignlabs 8f080080a7 refactor: changes in text of modal 2024-09-13 12:57:23 +05:30
AndrewandGitHub 71b2958c14 Merge pull request #1204 from OpenSignLabs/validation 2024-09-13 10:56:58 +05:30
prafull-opensignlabs f69aafcbfa refactor: provide userdetails 2024-09-13 10:52:22 +05:30
AndrewandGitHub 5f6a423697 Merge pull request #1203 from OpenSignLabs/validation 2024-09-12 13:29:39 +05:30
prafull-opensignlabs 5d245927c4 fix: user count is not correct 2024-09-12 13:25:11 +05:30
prafull-opensignlabsandGitHub 17c96fb849 Merge pull request #1201 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/npm_and_yarn-d7ff1d4c1a
build(deps): bump the npm_and_yarn group in /apps/OpenSignServer with 2 updates
2024-09-12 12:07:50 +05:30
prafull-opensignlabsandGitHub b7c28cdf36 Merge pull request #1202 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-cf87d80143
build(deps): bump the npm_and_yarn group in /apps/OpenSign with 2 updates
2024-09-12 12:07:17 +05:30
dependabot[bot]andGitHub d05aa0d350 build(deps): bump the npm_and_yarn group
Bumps the npm_and_yarn group in /apps/OpenSign with 2 updates: [send](https://github.com/pillarjs/send) and [express](https://github.com/expressjs/express).


Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.20.0 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: express
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-12 06:34:33 +00:00
prafull-opensignlabsandGitHub 875dc086bf Merge pull request #1195 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-31414ddb3e
build(deps): bump the npm_and_yarn group in /apps/OpenSign with 4 updates
2024-09-12 12:02:55 +05:30
dependabot[bot]andGitHub 4719ebd52a build(deps): bump the npm_and_yarn group
Bumps the npm_and_yarn group in /apps/OpenSignServer with 2 updates: [express](https://github.com/expressjs/express) and [dset](https://github.com/lukeed/dset).


Updates `express` from 4.20.0 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.0)

Updates `dset` from 3.1.3 to 3.1.4
- [Release notes](https://github.com/lukeed/dset/releases)
- [Commits](https://github.com/lukeed/dset/compare/v3.1.3...v3.1.4)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: dset
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-11 23:46:04 +00:00
AndrewandGitHub c8a436a7df Merge pull request #1200 from OpenSignLabs/validation 2024-09-11 20:10:47 +05:30
prafull-opensignlabs 8d6f4dd64e fix: issue user count 2024-09-11 20:10:19 +05:30
AndrewandGitHub 63486927d6 Merge pull request #1199 from OpenSignLabs/validation 2024-09-11 17:54:59 +05:30
prafull-opensignlabs c36a70f8d3 refactor: add user validation 2024-09-11 17:50:39 +05:30
dependabot[bot]andGitHub 6cb30a6597 build(deps): bump the npm_and_yarn group
Bumps the npm_and_yarn group in /apps/OpenSign with 4 updates: [body-parser](https://github.com/expressjs/body-parser), [express](https://github.com/expressjs/express), [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [serve-static](https://github.com/expressjs/serve-static).


Updates `body-parser` from 1.20.2 to 1.20.3
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

Updates `path-to-regexp` from 0.1.7 to 0.1.10
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.10)

Updates `serve-static` from 1.15.0 to 1.16.0
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...1.16.0)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: express
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: express
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: path-to-regexp
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: serve-static
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-11 04:58:46 +00:00
dependabot[bot]andGitHub bc89b33468 build(deps-dev): bump lint-staged in /apps/OpenSign
Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 15.2.9 to 15.2.10.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v15.2.9...v15.2.10)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-11 04:58:17 +00:00
dependabot[bot]andGitHub ff2f7f6586 build(deps-dev): bump jasmine in /apps/OpenSignServer
Bumps [jasmine](https://github.com/jasmine/jasmine-npm) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/jasmine/jasmine-npm/releases)
- [Changelog](https://github.com/jasmine/jasmine-npm/blob/main/RELEASE.md)
- [Commits](https://github.com/jasmine/jasmine-npm/compare/v5.2.0...v5.3.0)

---
updated-dependencies:
- dependency-name: jasmine
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 00:12:15 +00:00
dependabot[bot]andGitHub 93f33d73d9 build(deps): bump nodemailer in /apps/OpenSignServer
Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 6.9.14 to 6.9.15.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v6.9.14...v6.9.15)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 00:11:47 +00:00
dependabot[bot]andGitHub 402c176277 build(deps): bump mongoose from 8.6.0 to 8.6.1 in /apps/OpenSignServer
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.6.0 to 8.6.1.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/8.6.0...8.6.1)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 00:11:41 +00:00
51 changed files with 1663 additions and 1024 deletions
+69 -42
View File
@@ -77,7 +77,7 @@
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.34.3", "eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.8", "lint-staged": "^15.2.10",
"mini-css-extract-plugin": "^2.9.1", "mini-css-extract-plugin": "^2.9.1",
"postcss": "^8.4.45", "postcss": "^8.4.45",
"prettier": "^3.3.3", "prettier": "^3.3.3",
@@ -7592,9 +7592,9 @@
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.2", "version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
"content-type": "~1.0.5", "content-type": "~1.0.5",
@@ -7604,7 +7604,7 @@
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"qs": "6.11.0", "qs": "6.13.0",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "1.0.0" "unpipe": "1.0.0"
@@ -11040,36 +11040,36 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.19.2", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "1.20.2", "body-parser": "1.20.3",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "0.6.0", "cookie": "0.6.0",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"etag": "~1.8.1", "etag": "~1.8.1",
"finalhandler": "1.2.0", "finalhandler": "1.3.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"merge-descriptors": "1.0.1", "merge-descriptors": "1.0.3",
"methods": "~1.1.2", "methods": "~1.1.2",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.7", "path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.11.0", "qs": "6.13.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"send": "0.18.0", "send": "0.19.0",
"serve-static": "1.15.0", "serve-static": "1.16.2",
"setprototypeof": "1.2.0", "setprototypeof": "1.2.0",
"statuses": "2.0.1", "statuses": "2.0.1",
"type-is": "~1.6.18", "type-is": "~1.6.18",
@@ -11099,15 +11099,23 @@
"ms": "2.0.0" "ms": "2.0.0"
} }
}, },
"node_modules/express/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/express/node_modules/ms": { "node_modules/express/node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}, },
"node_modules/express/node_modules/path-to-regexp": { "node_modules/express/node_modules/path-to-regexp": {
"version": "0.1.7", "version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
}, },
"node_modules/express/node_modules/range-parser": { "node_modules/express/node_modules/range-parser": {
"version": "1.2.1", "version": "1.2.1",
@@ -11374,12 +11382,12 @@
} }
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "1.2.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
@@ -11398,6 +11406,14 @@
"ms": "2.0.0" "ms": "2.0.0"
} }
}, },
"node_modules/finalhandler/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/finalhandler/node_modules/ms": { "node_modules/finalhandler/node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -16287,9 +16303,9 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
}, },
"node_modules/lint-staged": { "node_modules/lint-staged": {
"version": "15.2.9", "version": "15.2.10",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz",
"integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chalk": "~5.3.0", "chalk": "~5.3.0",
@@ -16298,7 +16314,7 @@
"execa": "~8.0.1", "execa": "~8.0.1",
"lilconfig": "~3.1.2", "lilconfig": "~3.1.2",
"listr2": "~8.2.4", "listr2": "~8.2.4",
"micromatch": "~4.0.7", "micromatch": "~4.0.8",
"pidtree": "~0.6.0", "pidtree": "~0.6.0",
"string-argv": "~0.3.2", "string-argv": "~0.3.2",
"yaml": "~2.5.0" "yaml": "~2.5.0"
@@ -16908,9 +16924,12 @@
"dev": true "dev": true
}, },
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "1.0.1", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}, },
"node_modules/merge-refs": { "node_modules/merge-refs": {
"version": "1.3.0", "version": "1.3.0",
@@ -19758,11 +19777,11 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.11.0", "version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": { "dependencies": {
"side-channel": "^1.0.4" "side-channel": "^1.0.6"
}, },
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
@@ -22319,9 +22338,9 @@
} }
}, },
"node_modules/send": { "node_modules/send": {
"version": "0.18.0", "version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
@@ -22504,19 +22523,27 @@
} }
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "1.15.0", "version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": { "dependencies": {
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"send": "0.18.0" "send": "0.19.0"
}, },
"engines": { "engines": {
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/serve-static/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/serve/node_modules/ajv": { "node_modules/serve/node_modules/ajv": {
"version": "8.12.0", "version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+1 -1
View File
@@ -109,7 +109,7 @@
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.34.3", "eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.8", "lint-staged": "^15.2.10",
"mini-css-extract-plugin": "^2.9.1", "mini-css-extract-plugin": "^2.9.1",
"postcss": "^8.4.45", "postcss": "^8.4.45",
"prettier": "^3.3.3", "prettier": "^3.3.3",
@@ -635,7 +635,17 @@
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.", "quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
"quota-mail-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.", "quota-mail-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head":"Quota Reached", "quota-mail-head":"Quota Reached",
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminName}}<{{adminEmail}}>.", "unauthorized-modal":"You don't have permission to perform this action, please contact {{adminEmail}}.",
"sent-this-month":"Sent this month" "sent-this-month":"Sent this month",
"available-seats":"Available seats",
"buy-users":"Buy more users",
"isenable-otp": "Enable OTP verification",
"isenable-otp-help": {
"p1": "Would you like to enable the verification process using a one-time password (OTP)?",
"p2": "Selecting this option will enable OTP verification. Users will receive a verification code via email, which they must enter to sign the document.",
"p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.",
"p4": "Please choose the option that best suits your document signing requirements."
},
"advanced-options":"Advanced options",
"hide-advanced-options":"Hide Advanced options"
} }
@@ -634,7 +634,18 @@
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.", "quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
"quota-mail-tip-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.", "quota-mail-tip-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
"quota-mail-head":"Quota atteint", "quota-mail-head":"Quota atteint",
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminName}}<{{adminEmail}}>.", "unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
"sent-this-month":"envoyé ce mois-ci" "sent-this-month":"envoyé ce mois-ci",
"available-seats":"Disponible sièges",
"buy-users":"Acheter plus d'utilisateurs",
"isenable-otp": "Activer la vérification OTP",
"isenable-otp-help": {
"p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?",
"p2": "La sélection de cette option activera la vérification OTP. Les utilisateurs recevront un code de vérification par e-mail, qu'ils devront saisir pour signer le document.",
"p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.",
"p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents."
},
"advanced-options":"Options avancées",
"hide-advanced-options": "Masquer les options avancées"
} }
+4 -2
View File
@@ -301,6 +301,9 @@ const AddUser = (props) => {
setAllowedUser(amount.quantity); setAllowedUser(amount.quantity);
setPlanInfo((obj) => ({ ...obj, totalAllowedUser: _resAddon.addon })); setPlanInfo((obj) => ({ ...obj, totalAllowedUser: _resAddon.addon }));
} }
if (props.handleBuyUsers) {
props.handleBuyUsers(amount.quantity, _resAddon.addon);
}
} }
} catch (err) { } catch (err) {
console.log("Err in buy addon", err); console.log("Err in buy addon", err);
@@ -495,8 +498,7 @@ const AddUser = (props) => {
{planInfo.adminId !== extUser?.objectId ? ( {planInfo.adminId !== extUser?.objectId ? (
<div className="mb-3 mt-1 flex justify-center text-center items-center font-medium break-all"> <div className="mb-3 mt-1 flex justify-center text-center items-center font-medium break-all">
{t("unauthorized-modal", { {t("unauthorized-modal", {
adminName: extUser?.CreatedBy?.name, adminEmail: extUser?.TenantId?.EmailAddress
adminEmail: extUser?.CreatedBy?.email
})} })}
</div> </div>
) : ( ) : (
+2 -7
View File
@@ -31,7 +31,6 @@ const BulkSendUi = (props) => {
const [isFreePlan, setIsFreePlan] = useState(false); const [isFreePlan, setIsFreePlan] = useState(false);
const [admin, setAdmin] = useState({ const [admin, setAdmin] = useState({
objectId: "", objectId: "",
name: "",
email: "", email: "",
isAdmin: true isAdmin: true
}); });
@@ -63,8 +62,7 @@ const BulkSendUi = (props) => {
setAdmin((obj) => ({ setAdmin((obj) => ({
...obj, ...obj,
isAdmin: false, isAdmin: false,
name: extUser?.CreatedBy?.name, email: extUser?.TenantId?.EmailAddress
email: extUser?.CreatedBy?.email
})); }));
} }
setAdmin((obj) => ({ ...obj, objectId: subscription?.adminId })); setAdmin((obj) => ({ ...obj, objectId: subscription?.adminId }));
@@ -491,10 +489,7 @@ const BulkSendUi = (props) => {
</form> </form>
) : ( ) : (
<div className="mx-8 mt-4 mb-8 flex justify-center text-center items-center font-medium break-all"> <div className="mx-8 mt-4 mb-8 flex justify-center text-center items-center font-medium break-all">
{t("unauthorized-modal", { {t("unauthorized-modal", { adminEmail: admin?.email })}
adminName: admin?.name,
adminEmail: admin?.email
})}
</div> </div>
)} )}
</> </>
@@ -3,6 +3,8 @@ import { checkIsSubscribed, getFileName } from "../../constant/Utils";
import Upgrade from "../../primitives/Upgrade"; import Upgrade from "../../primitives/Upgrade";
import { isEnableSubscription } from "../../constant/const"; import { isEnableSubscription } from "../../constant/const";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Tooltip } from "react-tooltip";
// import SelectFolder from "../../premitives/SelectFolder"; // import SelectFolder from "../../premitives/SelectFolder";
const EditTemplate = ({ template, onSuccess }) => { const EditTemplate = ({ template, onSuccess }) => {
@@ -14,7 +16,8 @@ const EditTemplate = ({ template, onSuccess }) => {
Description: template?.Description || "", Description: template?.Description || "",
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false", SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
AutomaticReminders: template?.AutomaticReminders || false, AutomaticReminders: template?.AutomaticReminders || false,
RemindOnceInEvery: template?.RemindOnceInEvery || 5 RemindOnceInEvery: template?.RemindOnceInEvery || 5,
IsEnableOTP: template?.IsEnableOTP ? `${template?.IsEnableOTP}` : "false"
}); });
const [isSubscribe, setIsSubscribe] = useState(false); const [isSubscribe, setIsSubscribe] = useState(false);
useEffect(() => { useEffect(() => {
@@ -41,7 +44,7 @@ const EditTemplate = ({ template, onSuccess }) => {
e.stopPropagation(); e.stopPropagation();
const isChecked = formData.SendinOrder === "true" ? true : false; const isChecked = formData.SendinOrder === "true" ? true : false;
const AutoReminder = formData?.AutomaticReminders || false; const AutoReminder = formData?.AutomaticReminders || false;
const IsEnableOTP = formData.IsEnableOTP === "true" ? true : false;
let reminderDate = {}; let reminderDate = {};
if (AutoReminder) { if (AutoReminder) {
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery); const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
@@ -49,7 +52,12 @@ const EditTemplate = ({ template, onSuccess }) => {
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery); ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
reminderDate = { NextReminderDate: ReminderDate }; reminderDate = { NextReminderDate: ReminderDate };
} }
const data = { ...formData, SendinOrder: isChecked, ...reminderDate }; const data = {
...formData,
SendinOrder: isChecked,
IsEnableOTP: IsEnableOTP,
...reminderDate
};
onSuccess(data); onSuccess(data);
}; };
const handleAutoReminder = () => { const handleAutoReminder = () => {
@@ -184,6 +192,70 @@ const EditTemplate = ({ template, onSuccess }) => {
/> />
</div> </div>
)} )}
{isEnableSubscription && (
<div className="text-xs mt-2">
<label className="block">
<span className={isSubscribe ? "" : " text-gray-300"}>
{t("isenable-otp")}{" "}
<a data-tooltip-id="isenableotp-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<Tooltip id="isenableotp-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("isenable-otp")}</p>
<p>{t("isenable-otp-help.p1")}</p>
<p className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">{t("yes")}: </span>
<span>{t("isenable-otp-help.p2")}</span>
</li>
<li>
<span className="font-bold">{t("no")}: </span>
<span>{t("isenable-otp-help.p3")}</span>
</li>
</ol>
</p>
<p>{t("isenable-otp-help.p4")}</p>
</div>
</Tooltip>
</label>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="IsEnableOTP"
checked={formData.IsEnableOTP === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"false"}
name="IsEnableOTP"
className="op-radio op-radio-xs"
checked={formData.IsEnableOTP === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
)}
<div className="mt-[1rem] flex justify-start"> <div className="mt-[1rem] flex justify-start">
<button type="submit" className="op-btn op-btn-primary"> <button type="submit" className="op-btn op-btn-primary">
{t("submit")} {t("submit")}
@@ -154,7 +154,9 @@ function EmailComponent({
<div className="flex flex-row"> <div className="flex flex-row">
{!isAndroid && ( {!isAndroid && (
<button <button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)} onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
}
className="op-btn op-btn-neutral op-btn-sm text-[15px]" className="op-btn op-btn-neutral op-btn-sm text-[15px]"
> >
<i className="fa-light fa-print" aria-hidden="true"></i> <i className="fa-light fa-print" aria-hidden="true"></i>
@@ -142,7 +142,7 @@ function Header({
<DropdownMenu.Item <DropdownMenu.Item
className="DropdownMenuItem" className="DropdownMenuItem"
onClick={(e) => onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading) handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
} }
> >
<div className="flex flex-row"> <div className="flex flex-row">
@@ -342,7 +342,9 @@ function Header({
alreadySign ? ( alreadySign ? (
<div className="flex flex-row"> <div className="flex flex-row">
<button <button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)} onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
}
type="button" type="button"
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow" className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
> >
@@ -459,7 +461,9 @@ function Header({
</button> </button>
)} )}
<button <button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)} onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
}
type="button" type="button"
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow" className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
> >
+10 -8
View File
@@ -31,8 +31,8 @@ function SignPad({
const [isTab, setIsTab] = useState("draw"); const [isTab, setIsTab] = useState("draw");
const [isSignImg, setIsSignImg] = useState(""); const [isSignImg, setIsSignImg] = useState("");
const [signValue, setSignValue] = useState(""); const [signValue, setSignValue] = useState("");
const [textWidth, setTextWidth] = useState(null); const [textWidth, setTextWidth] = useState(0);
const [textHeight, setTextHeight] = useState(null); const [textHeight, setTextHeight] = useState(0);
const [signatureType, setSignatureType] = useState("draw"); const [signatureType, setSignatureType] = useState("draw");
const fontOptions = [ const fontOptions = [
{ value: "Fasthand" }, { value: "Fasthand" },
@@ -51,7 +51,7 @@ function SignPad({
`Parse/${localStorage.getItem("parseAppId")}/currentUser` `Parse/${localStorage.getItem("parseAppId")}/currentUser`
); );
const jsonSender = JSON.parse(senderUser); const jsonSender = JSON.parse(senderUser);
const currentUserName = jsonSender && jsonSender.name; const currentUserName = jsonSender && jsonSender?.name;
//function for clear signature image //function for clear signature image
const handleClear = () => { const handleClear = () => {
@@ -137,7 +137,7 @@ function SignPad({
(isTab === "draw" && isSignImg) || (isTab === "draw" && isSignImg) ||
(isTab === "image" && image) || (isTab === "image" && image) ||
(isTab === "mysignature" && isDefaultSign) || (isTab === "mysignature" && isDefaultSign) ||
(isTab === "type" && textWidth) (isTab === "type" && signValue)
? false ? false
: image : image
? false ? false
@@ -169,10 +169,10 @@ function SignPad({
} }
} }
const trimmedName = currentUserName && currentUserName.trim(); const trimmedName = currentUserName && currentUserName?.trim();
const firstCharacter = trimmedName?.charAt(0); const firstCharacter = trimmedName?.charAt(0);
const userName = isInitial ? firstCharacter : currentUserName; const userName = isInitial ? firstCharacter : currentUserName;
setSignValue(userName); setSignValue(userName || "");
setFontSelect("Fasthand"); setFontSelect("Fasthand");
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -200,8 +200,10 @@ function SignPad({
canvasRef.current.fromDataURL(isSignImg); canvasRef.current.fromDataURL(isSignImg);
} }
if (isTab === "type") { if (isTab === "type") {
const trimmedName = signValue ? signValue.trim() : currentUserName.trim(); const trimmedName = signValue
const firstCharacter = trimmedName.charAt(0); ? signValue?.trim()
: currentUserName?.trim();
const firstCharacter = trimmedName?.charAt(0);
const userName = isInitial ? firstCharacter : signValue; const userName = isInitial ? firstCharacter : signValue;
setSignValue(userName); setSignValue(userName);
convertToImg(fontSelect, userName); convertToImg(fontSelect, userName);
+13 -7
View File
@@ -708,7 +708,8 @@ export const createDocument = async (
Signers: signers, Signers: signers,
SendinOrder: Doc?.SendinOrder || false, SendinOrder: Doc?.SendinOrder || false,
AutomaticReminders: Doc?.AutomaticReminders || false, AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5) RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5),
IsEnableOTP: Doc?.IsEnableOTP || false
}; };
try { try {
@@ -1741,9 +1742,7 @@ export const contactBook = async (objectId) => {
//function for getting document details from contract_Documents class //function for getting document details from contract_Documents class
export const contractDocument = async (documentId) => { export const contractDocument = async (documentId) => {
const data = { const data = { docId: documentId };
docId: documentId
};
const documentDeatils = await axios const documentDeatils = await axios
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, { .post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
headers: { headers: {
@@ -2047,11 +2046,12 @@ export const handleDownloadPdf = async (
) => { ) => {
const pdfName = pdfDetails[0] && pdfDetails[0].Name; const pdfName = pdfDetails[0] && pdfDetails[0].Name;
setIsDownloading("pdf"); setIsDownloading("pdf");
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
try { try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl }); // const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
const axiosRes = await axios.post( const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`, `${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl }, { url: pdfUrl, docId: docId },
{ {
headers: { headers: {
"content-type": "Application/json", "content-type": "Application/json",
@@ -2075,16 +2075,22 @@ export const sanitizeFileName = (pdfName) => {
return pdfName.replace(/ /g, "_"); return pdfName.replace(/ /g, "_");
}; };
//function for print digital sign pdf //function for print digital sign pdf
export const handleToPrint = async (event, pdfUrl, setIsDownloading) => { export const handleToPrint = async (
event,
pdfUrl,
setIsDownloading,
pdfDetails
) => {
event.preventDefault(); event.preventDefault();
setIsDownloading("pdf"); setIsDownloading("pdf");
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
try { try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl }); // const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign //`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url //if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
const axiosRes = await axios.post( const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`, `${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl }, { url: pdfUrl, docId: docId },
{ {
headers: { headers: {
"content-type": "Application/json", "content-type": "Application/json",
+2 -2
View File
@@ -252,9 +252,9 @@ const HomeLayout = () => {
} }
}; };
const handleLoginBtn = () => { const handleLoginBtn = async () => {
try { try {
Parse?.User?.logOut(); await Parse?.User?.logOut();
} catch (err) { } catch (err) {
console.log("err ", err); console.log("err ", err);
} finally { } finally {
+209 -108
View File
@@ -61,7 +61,8 @@ const Forms = (props) => {
password: "", password: "",
file: "", file: "",
remindOnceInEvery: 5, remindOnceInEvery: 5,
autoreminder: false autoreminder: false,
IsEnableOTP: "false"
}); });
const [fileupload, setFileUpload] = useState(""); const [fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false); const [fileload, setfileload] = useState(false);
@@ -74,6 +75,7 @@ const Forms = (props) => {
const [isDecrypting, setIsDecrypting] = useState(false); const [isDecrypting, setIsDecrypting] = useState(false);
const [isCorrectPass, setIsCorrectPass] = useState(true); const [isCorrectPass, setIsCorrectPass] = useState(true);
const [isSubscribe, setIsSubscribe] = useState(false); const [isSubscribe, setIsSubscribe] = useState(false);
const [isAdvanceOpt, setIsAdvanceOpt] = useState(false);
const handleStrInput = (e) => { const handleStrInput = (e) => {
setIsCorrectPass(true); setIsCorrectPass(true);
setFormData({ ...formData, [e.target.name]: e.target.value }); setFormData({ ...formData, [e.target.name]: e.target.value });
@@ -137,7 +139,6 @@ const Forms = (props) => {
} catch (err) { } catch (err) {
console.log("err in sending posthog encryptedpdf", err); console.log("err in sending posthog encryptedpdf", err);
} }
// console.log("err ", err);
try { try {
setIsDecrypting(true); setIsDecrypting(true);
const size = files?.[0].size; const size = files?.[0].size;
@@ -402,6 +403,13 @@ const Forms = (props) => {
object.set("SendinOrder", isChecked); object.set("SendinOrder", isChecked);
object.set("AutomaticReminders", formData.autoreminder); object.set("AutomaticReminders", formData.autoreminder);
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery)); object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
if (isEnableSubscription) {
const IsEnableOTP =
formData?.IsEnableOTP === "false" ? false : true;
object.set("IsEnableOTP", IsEnableOTP);
} else {
object.set("IsEnableOTP", false);
}
} }
object.set("URL", fileupload); object.set("URL", fileupload);
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
@@ -428,7 +436,17 @@ const Forms = (props) => {
setFormData({ setFormData({
Name: "", Name: "",
Description: "", Description: "",
Note: "" Note:
props.title === "Sign Yourself"
? "Note to myself"
: "Please review and sign this document",
TimeToCompleteDays: 15,
SendinOrder: "true",
password: "",
file: "",
remindOnceInEvery: 5,
autoreminder: false,
IsEnableOTP: "false"
}); });
setFileUpload(""); setFileUpload("");
setpercentage(0); setpercentage(0);
@@ -477,7 +495,8 @@ const Forms = (props) => {
password: "", password: "",
file: "", file: "",
remindOnceInEvery: 5, remindOnceInEvery: 5,
autoreminder: false autoreminder: false,
IsEnableOTP: "false"
}); });
setFileUpload(""); setFileUpload("");
setpercentage(0); setpercentage(0);
@@ -641,7 +660,7 @@ const Forms = (props) => {
)} )}
<div className="text-xs"> <div className="text-xs">
<label className="block"> <label className="block">
{`${t("report-heading.File")} (${t("file-type")} ${ {`${t("report-heading.File")} (${t("file-type")}${
isEnableSubscription ? ", docx)" : ")" isEnableSubscription ? ", docx)" : ")"
}`} }`}
<span className="text-red-500 text-[13px]">*</span> <span className="text-red-500 text-[13px]">*</span>
@@ -754,120 +773,73 @@ const Forms = (props) => {
isReset={isReset} isReset={isReset}
/> />
)} )}
{props.title === "Request Signatures" && ( {props.title !== "Sign Yourself" && (
<div className="text-xs mt-2"> <div className="text-xs mt-2">
<label className="block"> <label className="block">
{t("time-to-complete")} {t("send-in-order")}
<span className="text-red-500 text-[13px]">*</span> <a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
<Tooltip id="sendInOrder-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("send-in-order")}</p>
<p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">{t("yes")}: </span>
<span>{t("send-in-order-help.p2")}</span>
</li>
<li>
<span className="font-bold">{t("no")}: </span>
<span>{t("send-in-order-help.p3")}</span>
</li>
</ol>
</p>
<p>{t("send-in-order-help.p4")}</p>
</div>
</Tooltip>
</label> </label>
<input <div className="flex items-center gap-2 ml-2 mb-1">
type="number" <input
name="TimeToCompleteDays" type="radio"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" value={"true"}
value={formData.TimeToCompleteDays} className="op-radio op-radio-xs"
onChange={(e) => handleStrInput(e)} name="SendinOrder"
onInvalid={(e) => checked={formData.SendinOrder === "true"}
e.target.setCustomValidity(t("input-required")) onChange={handleStrInput}
} />
onInput={(e) => e.target.setCustomValidity("")} <div className="text-center">{t("yes")}</div>
required </div>
/> <div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"false"}
name="SendinOrder"
className="op-radio op-radio-xs"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
</div> </div>
)} )}
{props.title !== "Sign Yourself" && ( {isAdvanceOpt && (
<> <div className={` overflow-y-auto z-[500] transition-all`}>
<div className="text-xs mt-2"> {props.title === "Request Signatures" && (
<label className="block">
{t("send-in-order")}
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
<Tooltip id="sendInOrder-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("send-in-order")}</p>
<p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">{t("yes")}:</span>
<span>{t("send-in-order-help.p2")}</span>
</li>
<li>
<span className="font-bold">{t("no")}: </span>
<span>{t("send-in-order-help.p3")}</span>
</li>
</ol>
</p>
<p>{t("send-in-order-help.p4")}</p>
</div>
</Tooltip>
</label>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="SendinOrder"
checked={formData.SendinOrder === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"false"}
name="SendinOrder"
className="op-radio op-radio-xs"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
{isEnableSubscription && (
<div className="text-xs mt-2">
<span
className={
isSubscribe
? "font-semibold"
: "font-semibold text-gray-300"
}
>
{t("auto-reminder")}
{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe
? "cursor-pointer "
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
checked={formData.autoreminder}
onChange={handleAutoReminder}
/>
</label>
</div>
)}
{formData?.autoreminder === true && (
<div className="text-xs mt-2"> <div className="text-xs mt-2">
<label className="block"> <label className="block">
{t("remind-once")} {t("time-to-complete")}
<span className="text-red-500 text-[13px]">*</span> <span className="text-red-500 text-[13px]">*</span>
</label> </label>
<input <input
type="number" type="number"
value={formData.remindOnceInEvery} name="TimeToCompleteDays"
name="remindOnceInEvery"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
onChange={handleStrInput} value={formData.TimeToCompleteDays}
onChange={(e) => handleStrInput(e)}
onInvalid={(e) => onInvalid={(e) =>
e.target.setCustomValidity(t("input-required")) e.target.setCustomValidity(t("input-required"))
} }
@@ -876,7 +848,136 @@ const Forms = (props) => {
/> />
</div> </div>
)} )}
</> {props.title !== "Sign Yourself" && (
<>
{isEnableSubscription && (
<div className="text-xs mt-2">
<span className={isSubscribe ? "" : " text-gray-300"}>
{t("auto-reminder")}{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe
? "cursor-pointer "
: "pointer-events-none opacity-50"
} relative block items-center mb-0 mt-1.5`}
>
<input
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
checked={formData.autoreminder}
onChange={handleAutoReminder}
/>
</label>
</div>
)}
{formData?.autoreminder === true && (
<div className="text-xs mt-2">
<label className="block">
{t("remind-once")}
<span className="text-red-500 text-[13px]">*</span>
</label>
<input
type="number"
value={formData.remindOnceInEvery}
name="remindOnceInEvery"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
onChange={handleStrInput}
onInvalid={(e) =>
e.target.setCustomValidity(t("input-required"))
}
onInput={(e) => e.target.setCustomValidity("")}
required
/>
</div>
)}
{isEnableSubscription && (
<div className="text-xs mt-2">
<label className="block">
<span className={isSubscribe ? "" : " text-gray-300"}>
{t("isenable-otp")}{" "}
<a
data-tooltip-id="isenableotp-tooltip"
className="ml-1"
>
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>{" "}
{!isSubscribe && isEnableSubscription && (
<Upgrade />
)}
</span>
<Tooltip id="isenableotp-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("isenable-otp")}</p>
<p>{t("isenable-otp-help.p1")}</p>
<p className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">
{t("yes")}:{" "}
</span>
<span>{t("isenable-otp-help.p2")}</span>
</li>
<li>
<span className="font-bold">
{t("no")}:{" "}
</span>
<span>{t("isenable-otp-help.p3")}</span>
</li>
</ol>
</p>
<p>{t("isenable-otp-help.p4")}</p>
</div>
</Tooltip>
</label>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="IsEnableOTP"
checked={formData.IsEnableOTP === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"false"}
name="IsEnableOTP"
className="op-radio op-radio-xs"
checked={formData.IsEnableOTP === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
)}
</>
)}
</div>
)}
{props.title !== "Sign Yourself" && (
<div
onClick={() => setIsAdvanceOpt(!isAdvanceOpt)}
className={`mt-2.5 op-link op-link-primary text-sm`}
>
{isAdvanceOpt
? t("hide-advanced-options")
: t("advanced-options")}
</div>
)} )}
<div className="flex items-center mt-3 gap-2"> <div className="flex items-center mt-3 gap-2">
<button <button
+1 -4
View File
@@ -28,7 +28,6 @@ function GenerateToken() {
plan: "", plan: "",
isValid: false, isValid: false,
adminId: "", adminId: "",
adminName: "",
adminEmail: "" adminEmail: ""
}); });
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
@@ -154,8 +153,7 @@ function GenerateToken() {
} else { } else {
setIsSubscribe((obj) => ({ setIsSubscribe((obj) => ({
...obj, ...obj,
adminName: extUser?.CreatedBy?.name, adminEmail: extUser?.TenantId?.EmailAddress
adminEmail: extUser?.CreatedBy?.email
})); }));
setIsModal((obj) => ({ ...obj, unauthorized: !obj.unauthorized })); setIsModal((obj) => ({ ...obj, unauthorized: !obj.unauthorized }));
} }
@@ -447,7 +445,6 @@ function GenerateToken() {
> >
<div className="m-8 flex justify-center text-center items-center font-medium break-all"> <div className="m-8 flex justify-center text-center items-center font-medium break-all">
{t("unauthorized-modal", { {t("unauthorized-modal", {
adminName: isSubscribe?.adminName,
adminEmail: isSubscribe?.adminEmail adminEmail: isSubscribe?.adminEmail
})} })}
</div> </div>
+36 -12
View File
@@ -28,6 +28,28 @@ function GuestLogin() {
const [contactId, setContactId] = useState(contactBookId); const [contactId, setContactId] = useState(contactBookId);
const [sendmail, setSendmail] = useState(); const [sendmail, setSendmail] = useState();
const [contact, setContact] = useState({ name: "", phone: "", email: "" }); const [contact, setContact] = useState({ name: "", phone: "", email: "" });
const navigateToDoc = async (docId, contactId) => {
try {
const docDetails = await Parse.Cloud.run("getDocument", {
docId: docId
});
if (!docDetails.error) {
if (sendmail === "false") {
navigate(
`/load/recipientSignPdf/${docId}/${contactId}?sendmail=${sendmail}`
);
} else {
navigate(`/load/recipientSignPdf/${docId}/${contactId}`);
}
return true;
} else {
return false;
}
} catch (err) {
console.log("err while getting doc", err);
return false;
}
};
useEffect(() => { useEffect(() => {
handleServerUrl(); handleServerUrl();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -70,13 +92,14 @@ function GuestLogin() {
"linkcontacttodoc", "linkcontacttodoc",
params params
); );
// console.log("linkContactRes ", linkContactRes);
setContactId(linkContactRes?.contactId); setContactId(linkContactRes?.contactId);
await navigateToDoc(checkSplit[0], linkContactRes?.contactId);
} catch (err) { } catch (err) {
console.log("Err in link ext contact", err); console.log("Err in link ext contact", err);
} }
} else { } else {
setContactId(checkSplit[2]); setContactId(checkSplit[2]);
await navigateToDoc(checkSplit[0], checkSplit[2]);
} }
} }
@@ -114,15 +137,12 @@ function GuestLogin() {
if (OTP) { if (OTP) {
setLoading(true); setLoading(true);
try { try {
let url = `${serverUrl}functions/AuthLoginAsMail/`; let url = `${serverUrl}functions/AuthLoginAsMail`;
const headers = { const headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Parse-Application-Id": parseId "X-Parse-Application-Id": parseId
}; };
let body = { let body = { email: email, otp: OTP };
email: email,
otp: OTP
};
let user = await axios.post(url, body, { headers: headers }); let user = await axios.post(url, body, { headers: headers });
if (user.data.result === "Invalid Otp") { if (user.data.result === "Invalid Otp") {
alert(t("invalid-otp")); alert(t("invalid-otp"));
@@ -140,7 +160,6 @@ function GuestLogin() {
`Parse/${parseId}/currentUser`, `Parse/${parseId}/currentUser`,
JSON.stringify(_user) JSON.stringify(_user)
); );
// console.log("contractUserDetails ", contractUserDetails);
if (contractUserDetails && contractUserDetails.length > 0) { if (contractUserDetails && contractUserDetails.length > 0) {
localStorage.setItem( localStorage.setItem(
"Extand_Class", "Extand_Class",
@@ -174,10 +193,15 @@ function GuestLogin() {
try { try {
setLoading(true); setLoading(true);
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params); const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
// console.log("linkContactRes ", linkContactRes);
setContactId(linkContactRes.contactId); setContactId(linkContactRes.contactId);
setEnterOtp(true); const IsEnableOTP = await navigateToDoc(
await SendOtp(); documentId,
linkContactRes.contactId
);
if (!IsEnableOTP) {
setEnterOtp(true);
await SendOtp();
}
} catch (err) { } catch (err) {
setLoading(false); setLoading(false);
alert(t("something-went-wrong-mssg")); alert(t("something-went-wrong-mssg"));
@@ -208,7 +232,7 @@ function GuestLogin() {
<div className="w-full md:w-[50%] text-base-content"> <div className="w-full md:w-[50%] text-base-content">
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1> <h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
<legend className="text-[12px] text-[#878787] mt-2 mb-1"> <legend className="text-[12px] text-[#878787] mt-2 mb-1">
{t("guest-email-alert")} {t("get-otp-alert")}
</legend> </legend>
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md"> <div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
<input <input
@@ -236,7 +260,7 @@ function GuestLogin() {
> >
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1> <h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
<legend className="text-[12px] text-[#878787] mt-2"> <legend className="text-[12px] text-[#878787] mt-2">
{t("get-verification-code-2")} {t("guest-email-alert")}
</legend> </legend>
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md"> <div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
<p className="text-sm">{t("enter-verification-code")}</p> <p className="text-sm">{t("enter-verification-code")}</p>
+196 -175
View File
@@ -142,23 +142,23 @@ function PdfRequestFiles(props) {
let isGuestSignFlow = false; let isGuestSignFlow = false;
let sendmail; let sendmail;
let getDocId = ""; let getDocId = "";
const route = !props.templateId && window.location.pathname; //'/load/recipientSignPdf/TOAVuhXbfw/fPAKdK1qgX' let contactBookId = "";
//window.location.search = ?sendmail=false const route = !props.templateId && window.location.pathname;
const getQuery = const getQuery = !props.templateId && window.location?.search?.split("?"); //['','sendmail=false']
!props.templateId &&
window.location?.search &&
window.location?.search?.split("?"); //['','sendmail=false']
//'sendmail=false'
if (getQuery) { if (getQuery) {
sendmail = getQuery[1].split("=")[1]; //false sendmail = getQuery?.[1]?.split("=")[1]; //false
} }
const checkSplit = route && route?.split("/"); // ['', 'load', 'recipientSignPdf', 'TOAVuhXbfw', 'fPAKdK1qgX']
if (checkSplit && checkSplit.length > 4) { const routeId = route && route?.split("/"); // ['', 'load', 'recipientSignPdf', ':docId', ':contactBookId']
if (routeId && routeId.length > 4) {
// this condition will be occur only in guest flow in which load routeId will be include
isGuestSignFlow = true; isGuestSignFlow = true;
getDocId = checkSplit[3]; getDocId = routeId[3];
contactBookId = routeId[4];
} else { } else {
getDocId = checkSplit[2]; // this condition will be occur only in if user is logged in and load routeId will be exclude
getDocId = routeId[2];
contactBookId = routeId?.[3] || "";
} }
let getDocumentId = getDocId || documentId; let getDocumentId = getDocId || documentId;
useEffect(() => { useEffect(() => {
@@ -372,9 +372,10 @@ function PdfRequestFiles(props) {
`Parse/${localStorage.getItem("parseAppId")}/currentUser` `Parse/${localStorage.getItem("parseAppId")}/currentUser`
); );
const jsonSender = JSON.parse(senderUser); const jsonSender = JSON.parse(senderUser);
// `currUserId` will be contactId or extUserId
let currUserId; let currUserId;
//getting document details //getting document details
const documentData = await contractDocument(documentId || docId); const documentData = await contractDocument(docId);
if (documentData && documentData.length > 0) { if (documentData && documentData.length > 0) {
const url = const url =
documentData[0] && documentData[0] &&
@@ -399,13 +400,13 @@ function PdfRequestFiles(props) {
const expireUpdateDate = new Date(expireDate).getTime(); const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime(); const currDate = new Date().getTime();
const getSigners = documentData[0].Signers; const getSigners = documentData[0].Signers;
const getCurrentSigner = const getCurrentSigner = getSigners?.find(
getSigners && (data) => data.UserId.objectId === jsonSender?.objectId
getSigners.filter( );
(data) => data.UserId.objectId === jsonSender?.objectId
);
currUserId = getCurrentSigner[0] ? getCurrentSigner[0].objectId : ""; currUserId = getCurrentSigner?.objectId
? getCurrentSigner.objectId
: contactBookId || "";
if (isEnableSubscription) { if (isEnableSubscription) {
await checkIsSubscribed( await checkIsSubscribed(
documentData[0]?.ExtUserPtr?.objectId, documentData[0]?.ExtUserPtr?.objectId,
@@ -428,10 +429,7 @@ function PdfRequestFiles(props) {
setIsCelebration(true); setIsCelebration(true);
setTimeout(() => setIsCelebration(false), 5000); setTimeout(() => setIsCelebration(false), 5000);
} else if (declined) { } else if (declined) {
const currentDecline = { const currentDecline = { currnt: "another", isDeclined: true };
currnt: "another",
isDeclined: true
};
setIsDecline(currentDecline); setIsDecline(currentDecline);
} else if (currDate > expireUpdateDate) { } else if (currDate > expireUpdateDate) {
const expireDateFormat = moment(new Date(expireDate)).format( const expireDateFormat = moment(new Date(expireDate)).format(
@@ -457,36 +455,24 @@ function PdfRequestFiles(props) {
} }
} }
} }
const audittrailData = const audittrailData = documentData?.[0]?.AuditTrail?.filter(
documentData[0].AuditTrail && (data) => data.Activity === "Signed"
documentData[0].AuditTrail.length > 0 && );
documentData[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
const checkAlreadySign = const checkAlreadySign =
documentData[0].AuditTrail && documentData?.[0]?.AuditTrail?.some(
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
(data) => (data) =>
data.UserPtr?.objectId === currUserId && data?.UserPtr?.objectId === currUserId &&
data.Activity === "Signed" data.Activity === "Signed"
); ) || false;
if ( if (checkAlreadySign) {
checkAlreadySign &&
checkAlreadySign[0] &&
checkAlreadySign.length > 0
) {
setAlreadySign(true); setAlreadySign(true);
} else { } else {
const obj = documentData?.[0]; const obj = documentData?.[0];
setSendInOrder(obj?.SendinOrder || false); setSendInOrder(obj?.SendinOrder || false);
if ( if (
obj && obj &&
obj.Signers && obj?.Signers?.length > 0 &&
obj.Signers.length > 0 && obj?.Placeholders?.length > 0
obj.Placeholders &&
obj.Placeholders.length > 0
) { ) {
const params = { const params = {
event: "viewed", event: "viewed",
@@ -502,7 +488,10 @@ function PdfRequestFiles(props) {
email: x?.Email, email: x?.Email,
phone: x?.Phone phone: x?.Phone
})), })),
viewedBy: jsonSender.email, viewedBy:
documentData?.[0].Signers?.find(
(x) => x.objectId === currUserId
)?.Email || jsonSender?.email,
viewedAt: new Date(), viewedAt: new Date(),
createdAt: documentData?.[0].createdAt createdAt: documentData?.[0].createdAt
} }
@@ -583,40 +572,51 @@ function PdfRequestFiles(props) {
//checking if condition current user already sign or owner does not exist as a signer or document has been declined by someone or document has been expired //checking if condition current user already sign or owner does not exist as a signer or document has been declined by someone or document has been expired
//then stop to display tour message //then stop to display tour message
if ( if (
(checkAlreadySign && checkAlreadySign ||
checkAlreadySign[0] &&
checkAlreadySign.length > 0) ||
!currUserId || !currUserId ||
declined || declined ||
currDate > expireUpdateDate currDate > expireUpdateDate
) { ) {
setRequestSignTour(true); setRequestSignTour(true);
} else { } else {
//else condition to check current user exist in contracts_Users class and check tour message status const isEnableOTP = documentData?.[0]?.IsEnableOTP || false;
//if not then check user exist in contracts_Contactbook class and check tour message statu if (!isEnableOTP) {
const res = await contractUsers(); try {
if (res === "Error: Something went wrong!") { const resContact = await axios.post(
setHandleError(t("something-went-wrong-mssg")); `${localStorage.getItem("baseUrl")}functions/getcontact`,
} else if (res[0] && res?.length) { {
setContractName("_Users"); contactId: currUserId
currUserId = res[0].objectId; },
setSignerUserId(currUserId); {
const tourData = res[0].TourStatus && res[0].TourStatus; headers: {
if (tourData && tourData.length > 0) { "Content-Type": "application/json",
const checkTourRequest = tourData.filter( "X-Parse-Application-Id": localStorage.getItem("parseAppId")
(data) => data?.requestSign }
}
); );
setTourStatus(tourData); const contact = resContact?.data?.result;
setRequestSignTour(checkTourRequest[0]?.requestSign || false); setContractName("_Contactbook");
setSignerUserId(contact?.objectId);
const tourData = contact?.TourStatus && contact?.TourStatus;
if (tourData && tourData.length > 0) {
const checkTourRequest =
tourData?.some((data) => data?.requestSign) || false;
setTourStatus(tourData);
setRequestSignTour(checkTourRequest);
}
} catch (err) {
console.log("err while getting tourstatus", err);
} }
} else if (res?.length === 0) { } else {
const res = await contactBook(currUserId); //else condition to check current user exist in contracts_Users class and check tour message status
//if not then check user exist in contracts_Contactbook class and check tour message status
const res = await contractUsers();
if (res === "Error: Something went wrong!") { if (res === "Error: Something went wrong!") {
setHandleError(t("something-went-wrong-mssg")); setHandleError(t("something-went-wrong-mssg"));
} else if (res[0] && res.length) { } else if (res[0] && res?.length) {
setContractName("_Contactbook"); setContractName("_Users");
const objectId = res[0].objectId; currUserId = res[0].objectId;
setSignerUserId(objectId); setSignerUserId(currUserId);
const tourData = res[0].TourStatus && res[0].TourStatus; const tourData = res[0].TourStatus && res[0].TourStatus;
if (tourData && tourData.length > 0) { if (tourData && tourData.length > 0) {
const checkTourRequest = tourData.filter( const checkTourRequest = tourData.filter(
@@ -625,8 +625,25 @@ function PdfRequestFiles(props) {
setTourStatus(tourData); setTourStatus(tourData);
setRequestSignTour(checkTourRequest[0]?.requestSign || false); setRequestSignTour(checkTourRequest[0]?.requestSign || false);
} }
} else if (res.length === 0) { } else if (res?.length === 0) {
setHandleError(t("user-not-exist")); const res = await contactBook(currUserId);
if (res === "Error: Something went wrong!") {
setHandleError(t("something-went-wrong-mssg"));
} else if (res[0] && res.length) {
setContractName("_Contactbook");
const objectId = res[0].objectId;
setSignerUserId(objectId);
const tourData = res[0].TourStatus && res[0].TourStatus;
if (tourData && tourData.length > 0) {
const checkTourRequest = tourData.filter(
(data) => data?.requestSign
);
setTourStatus(tourData);
setRequestSignTour(checkTourRequest[0]?.requestSign || false);
}
} else if (res.length === 0) {
setHandleError(t("user-not-exist"));
}
} }
} }
} }
@@ -643,12 +660,12 @@ function PdfRequestFiles(props) {
setIsUiLoading({ isLoad: false }); setIsUiLoading({ isLoad: false });
} }
//function to get default signatur eof current user from `contracts_Signature` class //function to get default signatur eof current user from `contracts_Signature` class
const defaultSignRes = await getDefaultSignature(jsonSender.objectId); const defaultSignRes = await getDefaultSignature(jsonSender?.objectId);
if (defaultSignRes?.status === "success") { if (defaultSignRes?.status === "success") {
setDefaultSignImg(defaultSignRes?.res?.defaultSignature); const sign = defaultSignRes?.res?.defaultSignature || "";
setMyInitial(defaultSignRes?.res?.defaultInitial); const initials = defaultSignRes?.res?.defaultInitial || "";
} else if (defaultSignRes?.status === "error") { setDefaultSignImg(sign);
setHandleError("Error: Something went wrong!"); setMyInitial(initials);
} }
setIsLoading({ isLoad: false }); setIsLoading({ isLoad: false });
} catch (err) { } catch (err) {
@@ -664,20 +681,30 @@ function PdfRequestFiles(props) {
`Parse/${localStorage.getItem("parseAppId")}/currentUser` `Parse/${localStorage.getItem("parseAppId")}/currentUser`
); );
let currentUser = JSON.parse(localuser); let currentUser = JSON.parse(localuser);
let isEmailVerified = currentUser?.emailVerified;
const isEnableOTP = pdfDetails?.[0]?.IsEnableOTP || false;
//if emailVerified data is not present in local user details then fetch again in _User class //if emailVerified data is not present in local user details then fetch again in _User class
if (!currentUser?.emailVerified) { if (isEnableOTP) {
const userQuery = new Parse.Query(Parse.User); try {
const getUser = await userQuery.get(currentUser?.objectId, { if (!currentUser?.emailVerified) {
sessionToken: currentUser?.sessionToken const userQuery = new Parse.Query(Parse.User);
}); const getUser = await userQuery.get(currentUser?.objectId, {
if (getUser) { sessionToken:
currentUser = JSON.parse(JSON.stringify(getUser)); currentUser?.sessionToken || localStorage.getItem("accesstoken")
});
if (getUser) {
currentUser = JSON.parse(JSON.stringify(getUser));
}
}
isEmailVerified = currentUser?.emailVerified;
setIsEmailVerified(isEmailVerified);
} catch (err) {
console.log("err in get email verification ", err);
setHandleError(t("something-went-wrong-mssg"));
} }
} }
let isEmailVerified = currentUser?.emailVerified;
//check if isEmailVerified then go on next step //check if isEmailVerified then go on next step
if (isEmailVerified) { if (!isEnableOTP || isEmailVerified) {
setIsEmailVerified(isEmailVerified);
try { try {
const checkUser = signerPos.filter( const checkUser = signerPos.filter(
(data) => data.signerObjId === signerObjectId (data) => data.signerObjId === signerObjectId
@@ -858,17 +885,9 @@ function PdfRequestFiles(props) {
// console.log("pdfte", pdfBytes); // console.log("pdfte", pdfBytes);
//get ExistUserPtr object id of user class to get tenantDetails //get ExistUserPtr object id of user class to get tenantDetails
const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId; const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId;
//get ExistUserPtr email to get userDetails let activeMailAdapter =
const res = await contractUsers(); pdfDetails?.[0]?.ExtUserPtr?.active_mail_adapter;
let activeMailAdapter = "";
if (res === "Error: Something went wrong!") {
setHandleError(t("something-went-wrong-mssg"));
setIsLoading({ isLoad: false });
} else if (!res || res?.length === 0) {
activeMailAdapter = "";
} else if (res[0] && res.length) {
activeMailAdapter = res[0]?.active_mail_adapter;
}
//function for call to embed signature in pdf and get digital signature pdf //function for call to embed signature in pdf and get digital signature pdf
const resSign = await signPdfFun( const resSign = await signPdfFun(
pdfBytes, pdfBytes,
@@ -880,13 +899,13 @@ function PdfRequestFiles(props) {
widgets widgets
); );
if (resSign && resSign.status === "success") { if (resSign && resSign.status === "success") {
setPdfUrl(res.data); setPdfUrl(resSign.data);
setIsSigned(true); setIsSigned(true);
setSignedSigners([]); setSignedSigners([]);
setUnSignedSigners([]); setUnSignedSigners([]);
getDocumentDetails(true); getDocumentDetails(documentId, true);
const index = pdfDetails?.[0].Signers.findIndex( const index = pdfDetails?.[0]?.Signers.findIndex(
(x) => x.Email === currentUser?.email (x) => x.objectId === signerObjectId
); );
const newIndex = index + 1; const newIndex = index + 1;
const usermail = { const usermail = {
@@ -1054,21 +1073,6 @@ function PdfRequestFiles(props) {
alertMessage: t("something-went-wrong-mssg") alertMessage: t("something-went-wrong-mssg")
}); });
} }
} else {
//else verify users email
try {
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(currentUser?.objectId, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
isEmailVerified = user?.get("emailVerified");
setIsEmailVerified(isEmailVerified);
}
} catch (e) {
console.log("error in save user's emailVerified in user class");
setHandleError(t("something-went-wrong-mssg"));
}
} }
} }
@@ -1216,31 +1220,26 @@ function PdfRequestFiles(props) {
); );
const jsonSender = JSON.parse(senderUser); const jsonSender = JSON.parse(senderUser);
setIsDecline({ isDeclined: false }); setIsDecline({ isDeclined: false });
const data = {
IsDeclined: true,
DeclineReason: reason,
DeclineBy: {
__type: "Pointer",
className: "_User",
objectId: jsonSender?.objectId
}
};
setIsUiLoading(true); setIsUiLoading(true);
const email =
pdfDetails?.[0].Signers?.find((x) => x.objectId === signerObjectId)
?.Email || jsonSender?.email;
const userId =
pdfDetails?.[0].Signers?.find((x) => x.objectId === signerObjectId)
?.UserId?.objectId || jsonSender?.objectId;
const params = {
docId: pdfDetails?.[0].objectId,
reason: reason,
userId: userId
};
await axios await axios
.put( .post(`${localStorage.getItem("baseUrl")}functions/declinedoc`, params, {
`${localStorage.getItem( headers: {
"baseUrl" "Content-Type": "application/json",
)}classes/contracts_Document/${documentId}`, "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
data, "X-Parse-Session-Token": localStorage.getItem("accesstoken")
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
} }
) })
.then(async (result) => { .then(async (result) => {
const res = result.data; const res = result.data;
if (res) { if (res) {
@@ -1260,7 +1259,8 @@ function PdfRequestFiles(props) {
email: x?.Email, email: x?.Email,
phone: x?.Phone phone: x?.Phone
})), })),
declinedBy: jsonSender.email, declinedBy: email,
declinedReason: reason,
declinedAt: new Date(), declinedAt: new Date(),
createdAt: pdfDetails?.[0].createdAt createdAt: pdfDetails?.[0].createdAt
} }
@@ -1314,38 +1314,58 @@ function PdfRequestFiles(props) {
const closeRequestSignTour = async () => { const closeRequestSignTour = async () => {
setRequestSignTour(true); setRequestSignTour(true);
if (isDontShow) { if (isDontShow) {
let updatedTourStatus = []; const isEnableOTP = pdfDetails?.[0]?.IsEnableOTP || false;
if (tourStatus.length > 0) { if (!isEnableOTP) {
updatedTourStatus = [...tourStatus]; try {
const requestSignIndex = tourStatus.findIndex( await axios.post(
(obj) => obj["requestSign"] === false || obj["requestSign"] === true `${localStorage.getItem("baseUrl")}functions/updatecontacttour`,
); {
if (requestSignIndex !== -1) { contactId: signerObjectId
updatedTourStatus[requestSignIndex] = { requestSign: true }; },
} else { {
updatedTourStatus.push({ requestSign: true }); headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
}
}
);
} catch (e) {
console.log("update tour messages error", e);
} }
} else { } else {
updatedTourStatus = [{ requestSign: true }]; let updatedTourStatus = [];
} if (tourStatus.length > 0) {
try { updatedTourStatus = [...tourStatus];
await axios.put( const requestSignIndex = tourStatus.findIndex(
`${localStorage.getItem( (obj) => obj["requestSign"] === false || obj["requestSign"] === true
"baseUrl" );
)}classes/contracts${contractName}/${signerUserId}`, if (requestSignIndex !== -1) {
{ updatedTourStatus[requestSignIndex] = { requestSign: true };
TourStatus: updatedTourStatus } else {
}, updatedTourStatus.push({ requestSign: true });
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
} }
); } else {
} catch (e) { updatedTourStatus = [{ requestSign: true }];
console.log("update tour messages error", e); }
try {
await axios.put(
`${localStorage.getItem(
"baseUrl"
)}classes/contracts${contractName}/${signerUserId}`,
{
TourStatus: updatedTourStatus
},
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
} catch (e) {
console.log("update tour messages error", e);
}
} }
} }
}; };
@@ -1691,11 +1711,7 @@ function PdfRequestFiles(props) {
{/* this modal is used to show decline alert */} {/* this modal is used to show decline alert */}
<PdfDeclineModal <PdfDeclineModal
show={isDecline.isDeclined} show={isDecline.isDeclined}
headMsg={ headMsg={t("document-declined")}
pdfDetails[0]?.IsDeclined
? t("document-declined")
: t("document-decline")
}
bodyMssg={ bodyMssg={
isDecline.currnt === "Sure" isDecline.currnt === "Sure"
? t("decline-alert-1") ? t("decline-alert-1")
@@ -1938,7 +1954,12 @@ function PdfRequestFiles(props) {
<div className="flex mt-4 gap-1 px-[15px]"> <div className="flex mt-4 gap-1 px-[15px]">
<button <button
onClick={(e) => onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading) handleToPrint(
e,
pdfUrl,
setIsDownloading,
pdfDetails
)
} }
type="button" type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral" className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral"
+2 -2
View File
@@ -121,9 +121,9 @@ const PlanSubscriptions = () => {
}; };
const handleLogout = async () => { const handleLogout = async () => {
try { try {
Parse?.User?.logOut(); await Parse?.User?.logOut();
} catch (err) { } catch (err) {
console.log("Err", err); console.log("Err while logging out", err);
} }
let appdata = localStorage.getItem("userSettings"); let appdata = localStorage.getItem("userSettings");
let applogo = localStorage.getItem("appLogo"); let applogo = localStorage.getItem("appLogo");
@@ -779,6 +779,7 @@ const TemplatePlaceholder = () => {
AutomaticReminders: pdfDetails[0]?.AutomaticReminders, AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery), RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
NextReminderDate: pdfDetails[0]?.NextReminderDate, NextReminderDate: pdfDetails[0]?.NextReminderDate,
IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
URL: pdfUrl URL: pdfUrl
}; };
const updateTemplate = new Parse.Object("contracts_Template"); const updateTemplate = new Parse.Object("contracts_Template");
+219 -55
View File
@@ -9,7 +9,7 @@ import Tooltip from "../primitives/Tooltip";
import AddUser from "../components/AddUser"; import AddUser from "../components/AddUser";
import SubscribeCard from "../primitives/SubscribeCard"; import SubscribeCard from "../primitives/SubscribeCard";
import { isEnableSubscription } from "../constant/const"; import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribed } from "../constant/Utils"; import { fetchSubscriptionInfo } from "../constant/Utils";
import Title from "../components/Title"; import Title from "../components/Title";
import { validplan } from "../json/plansArr"; import { validplan } from "../json/plansArr";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -19,7 +19,11 @@ const UserList = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const [userList, setUserList] = useState([]); const [userList, setUserList] = useState([]);
const [isLoader, setIsLoader] = useState(false); const [isLoader, setIsLoader] = useState(false);
const [isModal, setIsModal] = useState(false); const [isModal, setIsModal] = useState({
form: false,
addseats: false,
options: false
});
const location = useLocation(); const location = useLocation();
const isDashboard = const isDashboard =
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false; location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
@@ -27,9 +31,16 @@ const UserList = () => {
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" }); const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isActiveModal, setIsActiveModal] = useState({}); const [isActiveModal, setIsActiveModal] = useState({});
const [isActLoader, setIsActLoader] = useState({}); const [isActLoader, setIsActLoader] = useState({});
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false }); const [isSubscribe, setIsSubscribe] = useState({
plan: "",
isValid: false,
priceperUser: 0
});
const [isAdmin, setIsAdmin] = useState(false); const [isAdmin, setIsAdmin] = useState(false);
const [formHeader, setFormHeader] = useState(t("add-user")); const [formHeader, setFormHeader] = useState(t("add-user"));
const [usersCount, setUserCounts] = useState({ allowed: 0, totalAllowed: 0 });
const [amount, setAmount] = useState({ quantity: 1, price: 0 });
const [isBuyLoader, setIsBuyLoader] = useState(false);
const recordperPage = 10; const recordperPage = 10;
const startIndex = (currentPage - 1) * recordperPage; // user per page const startIndex = (currentPage - 1) * recordperPage; // user per page
@@ -81,7 +92,6 @@ const UserList = () => {
pages.push(lastPageIndex); pages.push(lastPageIndex);
} }
} }
return pages; return pages;
}; };
const pageNumbers = getPaginationRange(); const pageNumbers = getPaginationRange();
@@ -96,13 +106,43 @@ const UserList = () => {
async function fetchUserList() { async function fetchUserList() {
try { try {
setIsLoader(true); setIsLoader(true);
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (isEnableSubscription) { if (isEnableSubscription) {
const subscribe = await checkIsSubscribed(); const subscribe = await fetchSubscriptionInfo();
setIsSubscribe(subscribe); if (subscribe?.plan_code?.includes("team")) {
const isSupAdmin =
subscribe?.adminId && extUser?.objectId === subscribe?.adminId;
setIsSubscribe({
plan: subscribe.plan_code,
isValid: true,
adminId: subscribe.adminId,
priceperUser: subscribe.price,
isSuperAdmin: isSupAdmin
});
setAmount((prev) => ({ ...prev, price: subscribe.price }));
try {
const res = await Parse.Cloud.run("allowedusers");
setUserCounts((obj) => ({
...obj,
allowed: parseInt(res),
totalAllowed: parseInt(subscribe?.totalAllowedUser) || 0
}));
} catch (err) {
console.log("err while get users", err);
}
} else {
setIsSubscribe({
plan: subscribe.plan_code,
isValid: false,
adminId: subscribe.adminId
});
}
} else { } else {
setIsSubscribe({ plan: "teams-yearly", isValid: true }); setIsSubscribe({ plan: "teams-yearly", isValid: true });
} }
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (extUser) { if (extUser) {
const admin = const admin =
extUser?.UserRole && extUser?.UserRole &&
@@ -121,14 +161,12 @@ const UserList = () => {
console.log("Err in fetch userlist", err); console.log("Err in fetch userlist", err);
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") }); setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
} finally { } finally {
setTimeout(() => { setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
setIsAlert({ type: "success", msg: "" });
}, 1500);
setIsLoader(false); setIsLoader(false);
} }
} }
const handleFormModal = () => { const handleModal = (modalName) => {
setIsModal(!isModal); setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
}; };
// Change page // Change page
@@ -146,7 +184,13 @@ const UserList = () => {
}; };
const handleUserData = (userData) => { const handleUserData = (userData) => {
setUserList((prev) => [userData, ...prev]); if (userData) {
setUserCounts((obj) => ({
...obj,
allowed: obj?.allowed > 0 ? obj.allowed - 1 : 1
}));
setUserList((prev) => [userData, ...prev]);
}
}; };
// `formatRow` is used to show data in poper manner like // `formatRow` is used to show data in poper manner like
// if data is of array type then it will join array items with "," // if data is of array type then it will join array items with ","
@@ -162,9 +206,8 @@ const UserList = () => {
return "-"; return "-";
} }
}; };
const handleClose = () => { const handleClose = () => setIsActiveModal({});
setIsActiveModal({});
};
const handleToggleSubmit = async (user) => { const handleToggleSubmit = async (user) => {
const index = userList.findIndex((obj) => obj.objectId === user.objectId); const index = userList.findIndex((obj) => obj.objectId === user.objectId);
if (index !== -1) { if (index !== -1) {
@@ -196,6 +239,49 @@ const UserList = () => {
const handleToggleBtn = (user) => { const handleToggleBtn = (user) => {
setIsActiveModal({ [user.objectId]: true }); setIsActiveModal({ [user.objectId]: true });
}; };
const handleAddOnSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsBuyLoader(true);
try {
const resAddon = await Parse.Cloud.run("buyaddonusers", {
users: parseInt(amount.quantity)
});
if (resAddon) {
const _resAddon = JSON.parse(JSON.stringify(resAddon));
if (_resAddon.status === "success") {
setUserCounts((obj) => ({
...obj,
allowed: parseInt(obj.allowed) + parseInt(amount.quantity),
totalAllowed: parseInt(_resAddon.addon)
}));
setAmount((obj) => ({ ...obj, quantity: 1 }));
}
}
} catch (err) {
console.log("Err in buy addon", err);
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
} finally {
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000);
setIsBuyLoader(false);
handleModal("addseats");
}
};
const handlePricePerUser = (e) => {
const quantity = e.target.value;
const price = e.target?.value > 0 ? isSubscribe.priceperUser * quantity : 0;
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
};
const handleBuyUsers = (allowed, totalAllowed) => {
if (allowed && totalAllowed) {
setUserCounts((obj) => ({
...obj,
allowed: parseInt(obj.allowed) + parseInt(allowed),
totalAllowed: parseInt(totalAllowed)
}));
}
};
return ( return (
<div className="relative"> <div className="relative">
<Title title={isAdmin ? "Users" : "Page not found"} /> <Title title={isAdmin ? "Users" : "Page not found"} />
@@ -205,7 +291,7 @@ const UserList = () => {
</div> </div>
)} )}
{Object.keys(isActLoader)?.length > 0 && ( {Object.keys(isActLoader)?.length > 0 && (
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box"> <div className="absolute w-full h-full flex justify-center items-center bg-black/30 z-30 rounded-box">
<Loader /> <Loader />
</div> </div>
)} )}
@@ -216,19 +302,46 @@ const UserList = () => {
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>} {isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]"> <div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light"> <div className="font-light">
{t("report-name.Users")} {t("report-name.Users")}{" "}
<span className="text-xs md:text-[13px] font-normal"> <span className="text-xs md:text-[13px] font-normal">
<Tooltip message={t("users-from-teams")} /> <Tooltip message={t("users-from-teams")} />
</span> </span>
</div> </div>
<div <div className="flex flex-row gap-2 items-center">
className="cursor-pointer" {isEnableSubscription && isSubscribe?.isSuperAdmin && (
onClick={() => handleFormModal()} <div
> className="hidden md:flex op-btn op-btn-sm h-[35px] op-btn-primary op-btn-outline text-xs mb-0.5"
<i className="fa-light fa-square-plus text-accent text-[40px]"></i> onClick={() => handleModal("addseats")}
>
{t("buy-users")}
</div>
)}
<div
className="cursor-pointer"
onClick={() => handleModal("form")}
>
<i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i>
</div>
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
<div
className="cursor-pointer relative md:hidden mb-0.5"
onClick={() => handleModal("options")}
>
<i className="fa-light fa-ellipsis-vertical fa-xl"></i>
{isModal?.options && (
<ul className="absolute -right-3 top-auto z-[70] w-max op-menu op-menu-xs shadow bg-base-100 text-base-content rounded-box border">
<li onClick={() => handleModal("addseats")}>
<span className="text-[13px] capitalize font-medium">
{t("buy-users")}
</span>
</li>
</ul>
)}
</div>
)}
</div> </div>
</div> </div>
<div className={` overflow-x-auto w-full`}> <div className="overflow-x-auto w-full">
<table className="op-table border-collapse w-full"> <table className="op-table border-collapse w-full">
<thead className="text-[14px]"> <thead className="text-[14px]">
<tr className="border-y-[1px]"> <tr className="border-y-[1px]">
@@ -313,34 +426,42 @@ const UserList = () => {
</tbody> </tbody>
</table> </table>
</div> </div>
<div className="op-join flex flex-wrap items-center p-2"> <div className="flex flex-row justify-between items-center text-xs font-medium">
{userList.length > recordperPage && ( <div className="op-join flex flex-wrap items-center p-2">
<button {userList.length > recordperPage && (
onClick={() => paginateBack()} <button
className="op-join-item op-btn op-btn-sm" onClick={() => paginateBack()}
> className="op-join-item op-btn op-btn-sm"
{t("prev")} >
</button> {t("prev")}
)} </button>
{pageNumbers.map((x, i) => ( )}
<button {pageNumbers.map((x, i) => (
key={i} <button
onClick={() => setCurrentPage(x)} key={i}
disabled={x === "..."} onClick={() => setCurrentPage(x)}
className={`${ disabled={x === "..."}
x === currentPage ? "op-btn-active" : "" className={`${
} op-join-item op-btn op-btn-sm`} x === currentPage ? "op-btn-active" : ""
> } op-join-item op-btn op-btn-sm`}
{x} >
</button> {x}
))} </button>
{userList.length > recordperPage && ( ))}
<button {userList.length > recordperPage && (
onClick={() => paginateFront()} <button
className="op-join-item op-btn op-btn-sm" onClick={() => paginateFront()}
> className="op-join-item op-btn op-btn-sm"
{t("next")} >
</button> {t("next")}
</button>
)}
</div>
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
<div>
{t("available-seats")}: {usersCount.allowed}/
{usersCount.totalAllowed}
</div>
)} )}
</div> </div>
{userList?.length <= 0 && ( {userList?.length <= 0 && (
@@ -362,17 +483,60 @@ const UserList = () => {
</div> </div>
)} )}
<ModalUi <ModalUi
isOpen={isModal} isOpen={isModal.form}
title={formHeader} title={formHeader}
handleClose={handleFormModal} handleClose={() => handleModal("form")}
> >
<AddUser <AddUser
setIsAlert={setIsAlert} setIsAlert={setIsAlert}
handleUserData={handleUserData} handleUserData={handleUserData}
closePopup={handleFormModal} handleBuyUsers={handleBuyUsers}
closePopup={() => handleModal("form")}
setFormHeader={setFormHeader} setFormHeader={setFormHeader}
/> />
</ModalUi> </ModalUi>
<ModalUi
isOpen={isModal.addseats}
title="Add Seats"
handleClose={() => handleModal("addseats")}
>
{isBuyLoader && (
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
<Loader />
</div>
)}
<form onSubmit={handleAddOnSubmit} className=" px-3 pb-6 pt-6">
<div className="mb-3 flex justify-between">
<label
htmlFor="quantity"
className="block text-xs text-gray-700 font-semibold"
>
{t("Quantity-of-users")}
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="number"
name="quantity"
value={amount.quantity}
onChange={(e) => handlePricePerUser(e)}
className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
required
/>
</div>
<div className="mb-3 flex justify-between">
<label className="block text-xs text-gray-700 font-semibold">
{t("Price")} (1 * {isSubscribe.priceperUser})
</label>
<div className="w-1/4 flex justify-center items-center text-sm">
USD {amount.price}
</div>
</div>
<hr className="text-base-content mb-3" />
<button className="op-btn op-btn-primary w-full">
{t("Proceed")}
</button>
</form>
</ModalUi>
</div> </div>
) : ( ) : (
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box"> <div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
@@ -266,7 +266,8 @@ const ReportTable = (props) => {
Signers: signers, Signers: signers,
SendinOrder: Doc?.SendinOrder || false, SendinOrder: Doc?.SendinOrder || false,
AutomaticReminders: Doc?.AutomaticReminders || false, AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5 RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
IsEnableOTP: Doc?.IsEnableOTP || false
}; };
try { try {
const res = await axios.post( const res = await axios.post(
@@ -515,7 +516,6 @@ const ReportTable = (props) => {
.then(async (result) => { .then(async (result) => {
const res = result.data; const res = result.data;
if (res) { if (res) {
setReason("");
setActLoader({}); setActLoader({});
setIsAlert(true); setIsAlert(true);
setAlertMsg({ setAlertMsg({
@@ -527,7 +527,43 @@ const ReportTable = (props) => {
(x) => x.objectId !== item.objectId (x) => x.objectId !== item.objectId
); );
props.setList(upldatedList); props.setList(upldatedList);
const params = {
event: "declined",
body: {
objectId: item.objectId,
file: item?.SignedUrl || item?.URL,
name: item?.Name,
note: item?.Note || "",
description: item?.Description || "",
signers: item?.Signers?.map((x) => ({
name: x?.Name,
email: x?.Email,
phone: x?.Phone
})),
declinedBy: jsonSender?.email,
declinedReason: reason,
declinedAt: new Date(),
createdAt: item?.createdAt
}
};
try {
await axios.post(
`${localStorage.getItem("baseUrl")}functions/callwebhook`,
params,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessiontoken: localStorage.getItem("accesstoken")
}
}
);
} catch (err) {
console.log("Err ", err);
}
} }
setReason("");
}) })
.catch((err) => { .catch((err) => {
console.log("err", err); console.log("err", err);
@@ -41,8 +41,8 @@ function CustomModal(props) {
className="op-btn op-btn-primary mr-2 px-6" className="op-btn op-btn-primary mr-2 px-6"
type="button" type="button"
onClick={() => { onClick={() => {
setReason("");
props.declineDoc(reason); props.declineDoc(reason);
setReason("");
}} }}
> >
{t("yes")} {t("yes")}
@@ -41,7 +41,7 @@
"upgrade-now": "Upgrade now", "upgrade-now": "Upgrade now",
"upgrade-to": "Upgrade to", "upgrade-to": "Upgrade to",
"plan": "Plan", "plan": "Plan",
"subscribe-card-teamplan":"Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!", "subscribe-card-teamplan": "Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!",
"subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.", "subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.",
"user-name-limit-char": "To have a username less than 8 character please subscribe", "user-name-limit-char": "To have a username less than 8 character please subscribe",
"tour-content": "Don't show this again", "tour-content": "Don't show this again",
@@ -614,25 +614,35 @@
"select-date-format": "Select a date format", "select-date-format": "Select a date format",
"quantity-of-credits": "Quantity of premium credits", "quantity-of-credits": "Quantity of premium credits",
"remaining-credits": "Premium credits available:", "remaining-credits": "Premium credits available:",
"remaining-credits-help":"Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.", "remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.",
"additional-credits": "Please purchase premium credits", "additional-credits": "Please purchase premium credits",
"quota-err-quicksend": "Quota Reached, You don't have enough credits.", "quota-err-quicksend": "Quota Reached, You don't have enough credits.",
"buy-credits": "Buy Premium Credits", "buy-credits": "Buy Premium Credits",
"rotate-right":"Rotate right", "rotate-right": "Rotate right",
"rotate-left":"Rotate left", "rotate-left": "Rotate left",
"rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?", "rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?",
"templateid":"Template-Id", "templateid": "Template-Id",
"bulk-send-subcription-alert":"Please upgrade to Professional or Team plan to use bulk send.", "bulk-send-subcription-alert": "Please upgrade to Professional or Team plan to use bulk send.",
"generate-test-token":"Generate Test Token", "generate-test-token": "Generate Test Token",
"regenerate-test-token":"Regenerate Test Token", "regenerate-test-token": "Regenerate Test Token",
"help-test-token":"This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once youve completed your testing, you can upgrade to one of our paid plans to generate a production token.", "help-test-token": "This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once youve completed your testing, you can upgrade to one of our paid plans to generate a production token.",
"help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.", "help-api-token": "This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.",
"quota-mail-info-head":"Monthly request signatures email limit", "quota-mail-info-head": "Monthly request signatures email limit",
"quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.", "quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.",
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.", "quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
"quota-mail-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.", "quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head":"Quota Reached", "quota-mail-head": "Quota Reached",
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminName}}<{{adminEmail}}>.", "unauthorized-modal": "You don't have permission to perform this action, please contact {{adminEmail}}.",
"sent-this-month":"Sent this month" "sent-this-month": "Sent this month",
"available-seats": "Available seats",
"buy-users": "Buy more users",
"isenable-otp": "Enable OTP verification",
"isenable-otp-help": {
"p1": "Would you like to enable the verification process using a one-time password (OTP)?",
"p2": "Selecting this option will enable OTP verification. Users will receive a verification code via email, which they must enter to sign the document.",
"p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.",
"p4": "Please choose the option that best suits your document signing requirements."
},
"advanced-options": "Advanced options",
"hide-advanced-options": "Hide Advanced options"
} }
@@ -42,7 +42,7 @@
"upgrade-to": "Mettre à niveau vers", "upgrade-to": "Mettre à niveau vers",
"pro": "PRO", "pro": "PRO",
"plan": "Offre", "plan": "Offre",
"subscribe-card-teamplan":"Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !", "subscribe-card-teamplan": "Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !",
"subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.", "subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.",
"user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner", "user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner",
"tour-content": "Ne plus afficher", "tour-content": "Ne plus afficher",
@@ -611,28 +611,37 @@
"Add-seats": "Ajouter des sièges", "Add-seats": "Ajouter des sièges",
"format": "format", "format": "format",
"select-date-format": "Sélectionnez un format de date", "select-date-format": "Sélectionnez un format de date",
"quantity-of-credits":"Quantité de crédits de prime", "quantity-of-credits": "Quantité de crédits de prime",
"remaining-credits":"Crédits premium disponibles :", "remaining-credits": "Crédits premium disponibles :",
"additional-credits":"Veuillez acheter des crédits premium", "additional-credits": "Veuillez acheter des crédits premium",
"remaining-credits-help":"Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.", "remaining-credits-help": "Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.",
"quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.", "quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.",
"buy-credits": "Acheter des crédits premium", "buy-credits": "Acheter des crédits premium",
"rotate-right" :"Faire pivoter à droite", "rotate-right": "Faire pivoter à droite",
"rotate-left" :"Faire pivoter à gauche", "rotate-left": "Faire pivoter à gauche",
"rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?", "rotate-alert-mssg": "Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?",
"templateid":"ID de modèle", "templateid": "ID de modèle",
"bulk-send-subcription-alert":"Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.", "bulk-send-subcription-alert": "Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.",
"generate-test-token": "Générer jeton de test", "generate-test-token": "Générer jeton de test",
"regenerate-test-token":"Régénérer le jeton de test", "regenerate-test-token": "Régénérer le jeton de test",
"help-test-token":"Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à lun de nos forfaits payants pour générer un jeton de production.", "help-test-token": "Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à lun de nos forfaits payants pour générer un jeton de production.",
"help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.", "help-api-token": "Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.",
"quota-mail-info-head":"Limite mensuelle d'e-mails de signatures de demandes", "quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes",
"quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.", "quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.",
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.", "quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
"quota-mail-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.", "quota-mail-tip": "Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
"quota-mail-head":"Quota atteint", "quota-mail-head": "Quota atteint",
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminName}}<{{adminEmail}}>.", "unauthorized-modal": "Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
"sent-this-month":"envoyé ce mois-ci" "sent-this-month": "envoyé ce mois-ci",
"available-seats": "Disponible sièges",
"buy-users": "Acheter plus d'utilisateurs",
"isenable-otp": "Activer la vérification OTP",
"isenable-otp-help": {
"p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?",
"p2": "La sélection de cette option activera la vérification OTP. Les utilisateurs recevront un code de vérification par e-mail, qu'ils devront saisir pour signer le document.",
"p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.",
"p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents."
},
"advanced-options": "Options avancées",
"hide-advanced-options": "Masquer les options avancées"
} }
+30 -28
View File
@@ -42,36 +42,38 @@ export function replaceMailVaribles(subject, body, variables) {
export const saveFileUsage = async (size, fileUrl, userId) => { export const saveFileUsage = async (size, fileUrl, userId) => {
//checking server url and save file's size //checking server url and save file's size
try { try {
const tenantQuery = new Parse.Query('partners_Tenant'); if (userId) {
tenantQuery.equalTo('UserId', { const tenantQuery = new Parse.Query('partners_Tenant');
__type: 'Pointer', tenantQuery.equalTo('UserId', {
className: '_User', __type: 'Pointer',
objectId: userId, className: '_User',
}); objectId: userId,
const tenant = await tenantQuery.first(); });
if (tenant) { const tenant = await tenantQuery.first();
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id }; if (tenant) {
try { const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
const tenantCredits = new Parse.Query('partners_TenantCredits'); try {
tenantCredits.equalTo('PartnersTenant', tenantPtr); const tenantCredits = new Parse.Query('partners_TenantCredits');
const res = await tenantCredits.first({ useMasterKey: true }); tenantCredits.equalTo('PartnersTenant', tenantPtr);
if (res) { const res = await tenantCredits.first({ useMasterKey: true });
const response = JSON.parse(JSON.stringify(res)); if (res) {
const usedStorage = response?.usedStorage ? response.usedStorage + size : size; const response = JSON.parse(JSON.stringify(res));
const updateCredit = new Parse.Object('partners_TenantCredits'); const usedStorage = response?.usedStorage ? response.usedStorage + size : size;
updateCredit.id = res.id; const updateCredit = new Parse.Object('partners_TenantCredits');
updateCredit.set('usedStorage', usedStorage); updateCredit.id = res.id;
await updateCredit.save(null, { useMasterKey: true }); updateCredit.set('usedStorage', usedStorage);
} else { await updateCredit.save(null, { useMasterKey: true });
const newCredit = new Parse.Object('partners_TenantCredits'); } else {
newCredit.set('usedStorage', size); const newCredit = new Parse.Object('partners_TenantCredits');
newCredit.set('PartnersTenant', tenantPtr); newCredit.set('usedStorage', size);
await newCredit.save(null, { useMasterKey: true }); newCredit.set('PartnersTenant', tenantPtr);
await newCredit.save(null, { useMasterKey: true });
}
} catch (err) {
console.log('err in save usage', err);
} }
} catch (err) { saveDataFile(size, fileUrl, tenantPtr);
console.log('err in save usage', err);
} }
saveDataFile(size, fileUrl, tenantPtr);
} }
} catch (err) { } catch (err) {
console.log('err in fetch tenant Id', err); console.log('err in fetch tenant Id', err);
@@ -196,6 +196,9 @@ export default async function createDocumentWithTemplate(request, response) {
if (TimeToCompleteDays) { if (TimeToCompleteDays) {
object.set('TimeToCompleteDays', TimeToCompleteDays); object.set('TimeToCompleteDays', TimeToCompleteDays);
} }
const enableOTP = request.body?.enableOTP === true ? true : false;
const IsEnableOTP = enableOTP || template?.IsEnableOTP || false;
object.set('IsEnableOTP', IsEnableOTP);
object.set('CreatedBy', template.CreatedBy); object.set('CreatedBy', template.CreatedBy);
object.set('ExtUserPtr', { object.set('ExtUserPtr', {
__type: 'Pointer', __type: 'Pointer',
@@ -63,6 +63,7 @@ export default async function createDocumentwithCoordinate(request, response) {
const email_body = request.body.email_body; const email_body = request.body.email_body;
const sendInOrder = request.body.sendInOrder || false; const sendInOrder = request.body.sendInOrder || false;
const TimeToCompleteDays = request.body.timeToCompleteDays || 15; const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
const IsEnableOTP = request.body?.enableOTP === true ? true : false;
// console.log('fileData ', fileData); // console.log('fileData ', fileData);
const protocol = customAPIurl(); const protocol = customAPIurl();
const baseUrl = new URL(process.env.PUBLIC_URL); const baseUrl = new URL(process.env.PUBLIC_URL);
@@ -162,6 +163,7 @@ export default async function createDocumentwithCoordinate(request, response) {
if (TimeToCompleteDays) { if (TimeToCompleteDays) {
object.set('TimeToCompleteDays', TimeToCompleteDays); object.set('TimeToCompleteDays', TimeToCompleteDays);
} }
object.set('IsEnableOTP', IsEnableOTP);
object.set('IsSendMail', send_email); object.set('IsSendMail', send_email);
let contact = []; let contact = [];
if (signers && signers.length > 0) { if (signers && signers.length > 0) {
@@ -9,6 +9,7 @@ export default async function createTemplate(request, response) {
const SendinOrder = request.body.sendInOrder || false; const SendinOrder = request.body.sendInOrder || false;
const fileData = request.files?.[0] ? request.files[0].buffer : null; const fileData = request.files?.[0] ? request.files[0].buffer : null;
const baseUrl = new URL(process.env.PUBLIC_URL); const baseUrl = new URL(process.env.PUBLIC_URL);
const isEnableOTP = request.body?.enableOTP === true ? true : false;
try { try {
const reqToken = request.headers['x-api-token']; const reqToken = request.headers['x-api-token'];
@@ -65,6 +66,7 @@ export default async function createTemplate(request, response) {
object.set('URL', fileUrl); object.set('URL', fileUrl);
object.set('CreatedBy', userPtr); object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr); object.set('ExtUserPtr', extUserPtr);
object.set('IsEnableOTP', isEnableOTP);
if (SendinOrder) { if (SendinOrder) {
object.set('SendinOrder', SendinOrder); object.set('SendinOrder', SendinOrder);
} }
@@ -17,6 +17,8 @@ export default async function createTemplatewithCoordinate(request, response) {
const base64File = request.body.file; const base64File = request.body.file;
const fileData = request.files?.[0] ? request.files[0].buffer : null; const fileData = request.files?.[0] ? request.files[0].buffer : null;
const SendinOrder = request.body.sendInOrder || false; const SendinOrder = request.body.sendInOrder || false;
const isEnableOTP = request.body?.enableOTP === true ? true : false;
// console.log('fileData ', fileData); // console.log('fileData ', fileData);
const protocol = customAPIurl(); const protocol = customAPIurl();
@@ -80,6 +82,7 @@ export default async function createTemplatewithCoordinate(request, response) {
object.set('URL', fileUrl); object.set('URL', fileUrl);
object.set('CreatedBy', userPtr); object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr); object.set('ExtUserPtr', extUserPtr);
object.set('IsEnableOTP', isEnableOTP);
let contact = []; let contact = [];
if (signers && signers.length > 0) { if (signers && signers.length > 0) {
let parseSigners; let parseSigners;
@@ -12,6 +12,8 @@ export default async function draftDocument(request, response) {
const send_email = request.body.send_email || true; const send_email = request.body.send_email || true;
const fileData = request.files?.[0] ? request.files[0].buffer : null; const fileData = request.files?.[0] ? request.files[0].buffer : null;
const SendinOrder = request.body.sendInOrder || false; const SendinOrder = request.body.sendInOrder || false;
const isEnableOTP = request.body?.enableOTP === true ? true : false;
// console.log('fileData ', fileData); // console.log('fileData ', fileData);
const protocol = customAPIurl(); const protocol = customAPIurl();
const baseUrl = new URL(process.env.PUBLIC_URL); const baseUrl = new URL(process.env.PUBLIC_URL);
@@ -83,6 +85,7 @@ export default async function draftDocument(request, response) {
object.set('CreatedBy', userPtr); object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr); object.set('ExtUserPtr', extUserPtr);
object.set('IsSendMail', send_email); object.set('IsSendMail', send_email);
object.set('IsEnableOTP', isEnableOTP);
if (signers && signers.length > 0) { if (signers && signers.length > 0) {
let parseSigners; let parseSigners;
if (base64File) { if (base64File) {
@@ -62,6 +62,7 @@ export default async function getDocument(request, response) {
document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
[], [],
sendInOrder: document?.SendinOrder || false, sendInOrder: document?.SendinOrder || false,
enableOTP: document?.IsEnableOTP || false,
createdAt: document.createdAt, createdAt: document.createdAt,
updatedAt: document.updatedAt, updatedAt: document.updatedAt,
}); });
@@ -100,6 +100,7 @@ export default async function getDocumentList(request, response) {
x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) || x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
[], [],
sendInOrder: x?.SendinOrder || false, sendInOrder: x?.SendinOrder || false,
enableOTP: x?.IsEnableOTP || false,
createdAt: x.createdAt, createdAt: x.createdAt,
updatedAt: x.updatedAt, updatedAt: x.updatedAt,
})); }));
@@ -61,6 +61,7 @@ export default async function getTemplate(request, response) {
), ),
})) || [], })) || [],
sendInOrder: template?.SendinOrder || false, sendInOrder: template?.SendinOrder || false,
enableOTP: template?.IsEnableOTP || false,
createdAt: template.createdAt, createdAt: template.createdAt,
updatedAt: template.updatedAt, updatedAt: template.updatedAt,
}); });
@@ -88,6 +88,7 @@ export default async function getTemplatetList(request, response) {
), ),
})) || [], })) || [],
sendInOrder: template?.SendinOrder || false, sendInOrder: template?.SendinOrder || false,
enableOTP: template?.IsEnableOTP || false,
createdAt: template.createdAt, createdAt: template.createdAt,
updatedAt: template.updatedAt, updatedAt: template.updatedAt,
})); }));
@@ -10,7 +10,7 @@ export default async function updateDocument(request, response) {
const token = await tokenQuery.first({ useMasterKey: true }); const token = await tokenQuery.first({ useMasterKey: true });
if (token !== undefined) { if (token !== undefined) {
// Valid Token then proceed request // Valid Token then proceed request
const allowedKeys = ['name', 'note', 'description', 'folderId']; const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP'];
const objectKeys = Object.keys(request.body); const objectKeys = Object.keys(request.body);
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
const parseUser = JSON.parse(JSON.stringify(token)); const parseUser = JSON.parse(JSON.stringify(token));
@@ -48,6 +48,10 @@ export default async function updateDocument(request, response) {
objectId: request?.body?.folderId, objectId: request?.body?.folderId,
}); });
} }
if (request.body?.enableOTP) {
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
}
const updatedRes = await updateQuery.save(null, { useMasterKey: true }); const updatedRes = await updateQuery.save(null, { useMasterKey: true });
if (updatedRes) { if (updatedRes) {
if (request.posthog) { if (request.posthog) {
@@ -10,7 +10,7 @@ export default async function updateTemplate(request, response) {
const token = await tokenQuery.first({ useMasterKey: true }); const token = await tokenQuery.first({ useMasterKey: true });
if (token !== undefined) { if (token !== undefined) {
// Valid Token then proceed request // Valid Token then proceed request
const allowedKeys = ['name', 'note', 'description', 'folderId']; const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP'];
const objectKeys = Object.keys(request.body); const objectKeys = Object.keys(request.body);
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
const parseUser = JSON.parse(JSON.stringify(token)); const parseUser = JSON.parse(JSON.stringify(token));
@@ -48,6 +48,9 @@ export default async function updateTemplate(request, response) {
objectId: request?.body?.folderId, objectId: request?.body?.folderId,
}); });
} }
if (request.body?.enableOTP) {
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
}
const updatedRes = await updateQuery.save(null, { useMasterKey: true }); const updatedRes = await updateQuery.save(null, { useMasterKey: true });
if (updatedRes) { if (updatedRes) {
if (request.posthog) { if (request.posthog) {
+6
View File
@@ -65,6 +65,9 @@ import ExtUserAftersave from './parsefunction/ExtUserAftersave.js';
import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js'; import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js';
import AllowedCredits from './parsefunction/AllowedCredits.js'; import AllowedCredits from './parsefunction/AllowedCredits.js';
import BuyCredits from './parsefunction/BuyCredits.js'; import BuyCredits from './parsefunction/BuyCredits.js';
import getContact from './parsefunction/getContact.js';
import updateContactTour from './parsefunction/updateContactTour.js';
import declinedocument from './parsefunction/declinedocument.js';
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic. // This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
@@ -142,3 +145,6 @@ Parse.Cloud.define('allowedusers', AllowedUsers);
Parse.Cloud.define('buyaddonusers', BuyAddonUsers); Parse.Cloud.define('buyaddonusers', BuyAddonUsers);
Parse.Cloud.define('allowedcredits', AllowedCredits); Parse.Cloud.define('allowedcredits', AllowedCredits);
Parse.Cloud.define('buycredits', BuyCredits); Parse.Cloud.define('buycredits', BuyCredits);
Parse.Cloud.define('getcontact', getContact);
Parse.Cloud.define('updatecontacttour', updateContactTour);
Parse.Cloud.define('declinedoc', declinedocument);
@@ -62,6 +62,7 @@ const createDocumentFromTemplate = async (template, existContact, index) => {
object.set('CreatedBy', template?.CreatedBy); object.set('CreatedBy', template?.CreatedBy);
object.set('ExtUserPtr', template?.ExtUserPtr); object.set('ExtUserPtr', template?.ExtUserPtr);
object.set('OriginIp', template?.OriginIp || ''); object.set('OriginIp', template?.OriginIp || '');
object.set('IsEnableOTP', template?.IsEnableOTP || false);
let signers = template?.Signers || []; let signers = template?.Signers || [];
const signerobj = { const signerobj = {
__type: 'Pointer', __type: 'Pointer',
@@ -7,99 +7,101 @@ export default async function callWebhook(request) {
const contactId = request.params.contactId; const contactId = request.params.contactId;
const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = process.env.APP_ID; const appId = process.env.APP_ID;
const userRes = await axios.get(serverUrl + '/users/me', { try {
headers: { const docQuery = new Parse.Query('contracts_Document');
'X-Parse-Application-Id': appId, const docRes = await docQuery.get(docId, { useMasterKey: true });
'X-Parse-Session-Token': request.headers['sessiontoken'], const isEnableOTP = docRes?.get('IsEnableOTP') || false;
}, let userId;
}); if (isEnableOTP) {
const userRes = await axios.get(serverUrl + '/users/me', {
const userId = userRes.data && userRes.data.objectId; headers: {
if (userId) { 'X-Parse-Application-Id': appId,
if (event === 'viewed' && contactId) { 'X-Parse-Session-Token': request.headers['sessiontoken'],
const docQuery = new Parse.Query('contracts_Document'); },
const res = await docQuery.get(docId, { useMasterKey: true }); });
if (res) { userId = userRes.data && userRes.data.objectId;
const _res = res.toJSON(); }
const userPtr = { if (!isEnableOTP || userId) {
__type: 'Pointer', if (event === 'viewed' && contactId) {
className: 'contracts_Contactbook', if (docRes) {
objectId: contactId, const _docRes = docRes.toJSON();
}; const userPtr = {
const date = new Date().toISOString(); __type: 'Pointer',
const obj = { className: 'contracts_Contactbook',
UserPtr: userPtr, objectId: contactId,
SignedUrl: _res.SignedUrl, };
Activity: 'Viewed', const date = new Date().toISOString();
ipAddress: request.headers['x-real-ip'], const obj = {
ViewedOn: date, UserPtr: userPtr,
}; SignedUrl: _docRes.SignedUrl,
const isUserExist = _res?.AuditTrail?.some( Activity: 'Viewed',
x => x.UserPtr.objectId === contactId && x?.ViewedOn ipAddress: request.headers['x-real-ip'],
); ViewedOn: date,
if (!isUserExist) { };
const updateDoc = new Parse.Object('contracts_Document'); const isUserExist = _docRes?.AuditTrail?.some(
updateDoc.id = res.id; x => x.UserPtr.objectId === contactId && x?.ViewedOn
if (_res?.AuditTrail && _res?.AuditTrail?.length > 0) { );
updateDoc.set('AuditTrail', [..._res?.AuditTrail, obj]); if (!isUserExist) {
} else { const updateDoc = new Parse.Object('contracts_Document');
updateDoc.set('AuditTrail', [obj]); updateDoc.id = docRes.id;
if (_docRes?.AuditTrail && _docRes?.AuditTrail?.length > 0) {
updateDoc.set('AuditTrail', [..._docRes?.AuditTrail, obj]);
} else {
updateDoc.set('AuditTrail', [obj]);
}
await updateDoc.save(null, { useMasterKey: true });
} }
await updateDoc.save(null, { useMasterKey: true });
} }
} }
} const extendcls = new Parse.Query('contracts_Users');
const docQuery = new Parse.Query('contracts_Document'); extendcls.equalTo('objectId', docRes.get('ExtUserPtr')?.id);
const resDoc = await docQuery.get(docId, { useMasterKey: true }); // extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
const extendcls = new Parse.Query('contracts_Users'); const resExt = await extendcls.first({ useMasterKey: true });
extendcls.equalTo('objectId', resDoc.get('ExtUserPtr')?.id); if (resExt) {
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); const extUser = JSON.parse(JSON.stringify(resExt));
const res = await extendcls.first({ useMasterKey: true }); if (extUser?.Webhook) {
if (res) { const params = { event: event, ...body };
const extUser = JSON.parse(JSON.stringify(res)); await axios
if (extUser?.Webhook) { .post(extUser?.Webhook, params, {
const params = { headers: { 'Content-Type': 'application/json' },
event: event, })
...body, .then(res => {
}; try {
await axios const webhook = new Parse.Object('contracts_Webhook');
.post(extUser?.Webhook, params, { webhook.set('Log', res?.status);
headers: { 'Content-Type': 'application/json' }, webhook.set('UserId', {
}) __type: 'Pointer',
.then(res => { className: '_User',
try { objectId: userId,
// console.log('res ', res); });
const webhook = new Parse.Object('contracts_Webhook'); webhook.save(null, { useMasterKey: true });
webhook.set('Log', res?.status); } catch (err) {
webhook.set('UserId', { console.log('err save in contracts_Webhook', err.message);
__type: 'Pointer', }
className: '_User', })
objectId: userId, .catch(err => {
}); console.log('Err send data to webhook', err.message);
webhook.save(null, { useMasterKey: true }); try {
} catch (err) { const webhook = new Parse.Object('contracts_Webhook');
console.log('err save in contracts_Webhook', err.message); webhook.set('Log', err?.status);
} webhook.set('UserId', {
}) __type: 'Pointer',
.catch(err => { className: '_User',
console.log('Err send data to webhook', err.message); objectId: userId,
try { });
const webhook = new Parse.Object('contracts_Webhook'); webhook.save(null, { useMasterKey: true });
webhook.set('Log', err?.status); } catch (err) {
webhook.set('UserId', { console.log('err save in contracts_Webhook', err.message);
__type: 'Pointer', }
className: '_User', });
objectId: userId, }
}); return { message: 'webhook called!' };
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err.message);
}
});
} }
return { message: 'webhook called!' }; } else {
return { message: 'User not found!' };
} }
} else { } catch (err) {
return { message: 'User not found!' }; console.log('Err in callwebhook', err);
return { message: 'Something went wrong!' };
} }
} }
@@ -199,6 +199,7 @@ export default async function createBatchDocs(request) {
TimeToCompleteDays: x.TimeToCompleteDays || 15, TimeToCompleteDays: x.TimeToCompleteDays || 15,
OriginIp: Ip, OriginIp: Ip,
DocSentAt: { __type: 'Date', iso: isoDate }, DocSentAt: { __type: 'Date', iso: isoDate },
IsEnableOTP: x?.IsEnableOTP || false,
}, },
}; };
}); });
@@ -0,0 +1,38 @@
export default async function declinedocument(request) {
const docId = request.params.docId;
const reason = request.params?.reason || '';
const declineBy = {
__type: 'Pointer',
className: '_User',
objectId: request.params?.userId,
};
try {
const docCls = new Parse.Query('contracts_Document');
const updateDoc = await docCls.get(docId, { useMasterKey: true });
if (updateDoc) {
const isEnableOTP = updateDoc?.get('IsEnableOTP') || false;
if (!isEnableOTP) {
updateDoc.set('IsDeclined', true);
updateDoc.set('DeclineReason', reason);
updateDoc.set('DeclineBy', declineBy);
await updateDoc.save(null, { useMasterKey: true });
return 'document declined';
} else {
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
updateDoc.set('IsDeclined', true);
updateDoc.set('DeclineReason', reason);
updateDoc.set('DeclineBy', declineBy);
await updateDoc.save(null, { useMasterKey: true });
return 'document declined';
}
} else {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
}
} catch (err) {
console.log('err while decling doc', err);
throw err;
}
}
@@ -0,0 +1,11 @@
export default async function getContact(request) {
const contactId = request.params.contactId;
try {
const contactCls = new Parse.Query('contracts_Contactbook');
const contactRes = await contactCls.get(contactId, { useMasterKey: true });
return contactRes;
} catch (err) {
console.log('Err in contracts_Contactbook class ', err);
throw err;
}
}
@@ -6,14 +6,7 @@ export default async function getDocument(request) {
const docId = request.params.docId; const docId = request.params.docId;
try { try {
const userRes = await axios.get(serverUrl + '/users/me', { if (docId) {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (docId && userId) {
try { try {
const query = new Parse.Query('contracts_Document'); const query = new Parse.Query('contracts_Document');
query.equalTo('objectId', docId); query.equalTo('objectId', docId);
@@ -26,11 +19,32 @@ export default async function getDocument(request) {
query.notEqualTo('IsArchive', true); query.notEqualTo('IsArchive', true);
const res = await query.first({ useMasterKey: true }); const res = await query.first({ useMasterKey: true });
if (res) { if (res) {
const acl = res.getACL(); const IsEnableOTP = res?.get('IsEnableOTP') || false;
if (acl && acl.getReadAccess(userId)) { if (!IsEnableOTP) {
return res; return res;
} else { } else {
return { error: "You don't have access of this document!" }; if (request?.headers?.['sessiontoken']) {
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data?.objectId;
const acl = res.getACL();
if (userId && acl && acl.getReadAccess(userId)) {
return res;
} else {
return { error: "You don't have access of this document!" };
}
} catch (err) {
console.log('err user in not authenticated', err);
return { error: "You don't have access of this document!" };
}
} else {
return { error: "You don't have access of this document!" };
}
} }
} else { } else {
return { error: "You don't have access of this document!" }; return { error: "You don't have access of this document!" };
@@ -28,15 +28,42 @@ export default function getPresignedUrl(url) {
export async function getSignedUrl(request) { export async function getSignedUrl(request) {
try { try {
const docId = request.params.docId || '';
const url = request.params.url; const url = request.params.url;
if (!request?.user) { if (docId) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); try {
const query = new Parse.Query('contracts_Document');
query.equalTo('objectId', docId);
query.notEqualTo('IsEnableOTP', true);
query.include('CreatedBy');
query.include('Signers');
query.include('AuditTrail.UserPtr');
query.include('Placeholders');
query.include('DeclineBy');
query.notEqualTo('IsArchive', true);
const res = await query.first({ useMasterKey: true });
if (res) {
if (useLocal !== 'true') {
const presignedUrl = getPresignedUrl(url);
return presignedUrl;
} else {
return url;
}
}
} catch (err) {
console.log('Err in presigned url', err);
throw err;
}
} else { } else {
if (useLocal !== 'true') { if (!request?.user) {
const presignedUrl = getPresignedUrl(url); throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
return presignedUrl;
} else { } else {
return url; if (useLocal !== 'true') {
const presignedUrl = getPresignedUrl(url);
return presignedUrl;
} else {
return url;
}
} }
} }
} catch (err) { } catch (err) {
@@ -50,37 +50,24 @@ export default async function getSubscription(request) {
} }
} else if (contactId) { } else if (contactId) {
try { try {
const userRes = await axios.get(serverUrl + '/users/me', { const contactCls = new Parse.Query('contracts_Contactbook');
headers: { const contactUser = await contactCls.get(contactId, { useMasterKey: true });
'X-Parse-Application-Id': appId, if (contactUser) {
'X-Parse-Session-Token': request.headers['sessiontoken'], const subscriptionCls = new Parse.Query('contracts_Subscriptions');
}, subscriptionCls.equalTo('TenantId', {
}); __type: 'Pointer',
className: 'partners_Tenant',
const userId = userRes.data && userRes.data.objectId; objectId: contactUser.get('TenantId').id,
if (userId) { });
const contactCls = new Parse.Query('contracts_Contactbook'); subscriptionCls.descending('createdAt');
const contactUser = await contactCls.get(contactId, { useMasterKey: true }); const subcripitions = await subscriptionCls.first({ useMasterKey: true });
if (contactUser) { if (subcripitions) {
const subscriptionCls = new Parse.Query('contracts_Subscriptions'); const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
subscriptionCls.equalTo('TenantId', { if (_subcripitions.PlanCode === 'freeplan') {
__type: 'Pointer', return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } };
className: 'partners_Tenant', } else if (_subcripitions?.Next_billing_date?.iso) {
objectId: contactUser.get('TenantId').id, if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) {
}); return { status: 'success', result: { isSubscribed: true } };
subscriptionCls.descending('createdAt');
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
if (subcripitions) {
const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
if (_subcripitions.PlanCode === 'freeplan') {
return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } };
} else if (_subcripitions?.Next_billing_date?.iso) {
if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) {
return { status: 'success', result: { isSubscribed: true } };
} else {
return { status: 'success', result: { isSubscribed: false } };
}
} else { } else {
return { status: 'success', result: { isSubscribed: false } }; return { status: 'success', result: { isSubscribed: false } };
} }
@@ -88,10 +75,10 @@ export default async function getSubscription(request) {
return { status: 'success', result: { isSubscribed: false } }; return { status: 'success', result: { isSubscribed: false } };
} }
} else { } else {
return { status: 'error', result: 'User not found!' }; return { status: 'success', result: { isSubscribed: false } };
} }
} else { } else {
return { status: 'error', result: 'Invalid session token!' }; return { status: 'error', result: 'User not found!' };
} }
} catch (err) { } catch (err) {
console.log('Err in get subscription2', err.message); console.log('Err in get subscription2', err.message);
@@ -12,6 +12,8 @@ async function getUserDetails(request) {
} }
userQuery.include('TenantId'); userQuery.include('TenantId');
userQuery.include('UserId'); userQuery.include('UserId');
userQuery.include('CreatedBy');
userQuery.exclude('CreatedBy.authData');
userQuery.exclude('google_refresh_token'); userQuery.exclude('google_refresh_token');
if (userId) { if (userId) {
userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId }); userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
@@ -32,6 +32,7 @@ export default async function GenerateCertificate(docDetails) {
const OriginIp = docDetails?.OriginIp || ''; const OriginIp = docDetails?.OriginIp || '';
const company = docDetails?.ExtUserPtr?.Company || ''; const company = docDetails?.ExtUserPtr?.Company || '';
const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt; const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt;
const IsEnableOTP = docDetails?.IsEnableOTP || false;
const auditTrail = const auditTrail =
docDetails?.Signers?.length > 0 docDetails?.Signers?.length > 0
? docDetails.AuditTrail.map(x => { ? docDetails.AuditTrail.map(x => {
@@ -348,22 +349,22 @@ export default async function GenerateCertificate(docDetails) {
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Security level :', { if (IsEnableOTP) {
x: half + 55, page.drawText('Security level :', {
y: yPosition4 + 10, x: half + 55,
size: timeText, y: yPosition4 + 10,
font: timesRomanFont, size: timeText,
color: textKeyColor, font: timesRomanFont,
}); color: textKeyColor,
});
page.drawText(`Email, OTP Auth`, { page.drawText('Email, OTP Auth', {
x: half + 125, x: half + 125,
y: yPosition4 + 10, y: yPosition4 + 10,
size: timeText, size: timeText,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
}
page.drawText('Signature :', { page.drawText('Signature :', {
x: 30, x: 30,
y: yPosition5, y: yPosition5,
+151 -189
View File
@@ -29,11 +29,7 @@ async function uploadFile(pdfName, filepath) {
// `updateDoc` is used to update signedUrl, AuditTrail, Iscompleted in document // `updateDoc` is used to update signedUrl, AuditTrail, Iscompleted in document
async function updateDoc(docId, url, userId, ipAddress, data, className, sign) { async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
try { try {
const UserPtr = { const UserPtr = { __type: 'Pointer', className: className, objectId: userId };
__type: 'Pointer',
className: className,
objectId: userId,
};
const obj = { const obj = {
UserPtr: UserPtr, UserPtr: UserPtr,
SignedUrl: url, SignedUrl: url,
@@ -66,11 +62,7 @@ async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
} else { } else {
isCompleted = true; isCompleted = true;
} }
const body = { const body = { SignedUrl: url, AuditTrail: updateAuditTrail, IsCompleted: isCompleted };
SignedUrl: url,
AuditTrail: updateAuditTrail,
IsCompleted: isCompleted,
};
const signedRes = await axios.put(serverUrl + '/classes/contracts_Document/' + docId, body, { const signedRes = await axios.put(serverUrl + '/classes/contracts_Document/' + docId, body, {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -164,29 +156,16 @@ async function sendCompletedMail(obj) {
'X-Parse-Master-Key': masterKEY, 'X-Parse-Master-Key': masterKEY,
}, },
}); });
// console.log('Res ', res);
} }
// `sendDoctoWebhook` is used to send res data of document on webhook // `sendDoctoWebhook` is used to send res data of document on webhook
async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) { async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) {
let signers = []; let signers = [];
if (signUser) { if (signUser) {
signers = { signers = { name: signUser?.Name, email: signUser?.Email, phone: signUser?.Phone };
name: signUser?.Name,
email: signUser?.Email,
phone: signUser?.Phone,
};
} else { } else {
signers = doc?.Signers?.map(x => ({ signers = doc?.Signers?.map(x => ({ name: x.Name, email: x.Email, phone: x.Phone })) || [
name: x.Name, { name: doc?.ExtUserPtr?.Name, email: doc?.ExtUserPtr?.Email, phone: doc?.ExtUserPtr?.Phone },
email: x.Email,
phone: x.Phone,
})) || [
{
name: doc?.ExtUserPtr?.Name,
email: doc?.ExtUserPtr?.Email,
phone: doc?.ExtUserPtr?.Phone,
},
]; ];
} }
@@ -213,7 +192,6 @@ async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) {
}) })
.then(res => { .then(res => {
try { try {
// console.log('res ', res);
const webhook = new Parse.Object('contracts_Webhook'); const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status); webhook.set('Log', res?.status);
webhook.set('UserId', { webhook.set('UserId', {
@@ -241,7 +219,6 @@ async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) {
console.log('err save in contracts_Webhook', err.message); console.log('err save in contracts_Webhook', err.message);
} }
}); });
// console.log('res ', res.data);
} }
} }
@@ -281,15 +258,9 @@ const sendMailsaveCertifcate = async (doc, P12Buffer, url, isCustomMail, mailPro
if (doc.IsSendMail === false) { if (doc.IsSendMail === false) {
console.log("don't send mail"); console.log("don't send mail");
} else { } else {
const mailObj = { const mailObj = { url: url, isCustomMail: isCustomMail, doc: doc, mailProvider: mailProvider };
url: url,
isCustomMail: isCustomMail,
doc: doc,
mailProvider: mailProvider,
};
sendCompletedMail(mailObj); sendCompletedMail(mailObj);
} }
saveFileUsage(CertificateBuffer.length, file.imageUrl, userId); saveFileUsage(CertificateBuffer.length, file.imageUrl, userId);
sendDoctoWebhook(doc, url, 'completed', '', file.imageUrl); sendDoctoWebhook(doc, url, 'completed', '', file.imageUrl);
}; };
@@ -301,169 +272,160 @@ const sendMailsaveCertifcate = async (doc, P12Buffer, url, isCustomMail, mailPro
*/ */
async function PDF(req) { async function PDF(req) {
try { try {
if (!req?.user) { const userIP = req.headers['x-real-ip']; // client IPaddress
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.'); const docId = req.params.docId;
const reqUserId = req.params.userId;
const isCustomMail = req.params.isCustomCompletionMail || false;
const mailProvider = req.params.mailProvider || '';
const sign = req.params.signature || '';
// below bode is used to get info of docId
const docQuery = new Parse.Query('contracts_Document');
docQuery.include('ExtUserPtr,Signers');
docQuery.equalTo('objectId', docId);
const resDoc = await docQuery.first({ useMasterKey: true });
if (!resDoc) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
}
const IsEnableOTP = resDoc?.get('IsEnableOTP') || false;
// if `IsEnableOTP` is false then we don't have to check authentication
if (IsEnableOTP) {
if (!req?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
}
const _resDoc = resDoc?.toJSON();
let signUser;
let className;
// `reqUserId` is send throught pdfrequest signing flow
if (reqUserId) {
// to get contracts_Contactbook details for currentuser from reqUserId
const _contractUser = _resDoc.Signers.find(x => x.objectId === reqUserId);
if (_contractUser) {
signUser = _contractUser;
className = 'contracts_Contactbook';
}
} else { } else {
const password = ''; className = 'contracts_Users';
const authUser = req?.user?.toJSON(); signUser = _resDoc.ExtUserPtr;
const docId = req.params.docId; }
const reqUserId = req.params.userId;
const isCustomMail = req.params.isCustomCompletionMail || false;
const mailProvider = req.params.mailProvider || '';
const sign = req.params.signature || '';
// below bode is used to get info of docId
const docQuery = new Parse.Query('contracts_Document');
docQuery.include('ExtUserPtr,Signers');
docQuery.equalTo('objectId', docId);
const resDoc = await docQuery.first({ useMasterKey: true });
if (!resDoc) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
}
const _resDoc = resDoc?.toJSON();
let signUser; const username = signUser.Name;
let className; const userEmail = signUser.Email;
// `reqUserId` is send throught pdfrequest signing flow if (req.params.pdfFile) {
if (reqUserId) { // `PdfBuffer` used to create buffer from pdf file
// to get contracts_Contactbook details for currentuser from reqUserId let PdfBuffer = Buffer.from(req.params.pdfFile, 'base64');
const _contractUser = _resDoc.Signers.find(x => x.objectId === reqUserId); // `P12Buffer` used to create buffer from p12 certificate
if (_contractUser) { const pfxFile = process.env.PFX_BASE64;
signUser = _contractUser; // const P12Buffer = fs.readFileSync();
className = 'contracts_Contactbook'; const P12Buffer = Buffer.from(pfxFile, 'base64');
} const p12Cert = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null });
const UserPtr = { __type: 'Pointer', className: className, objectId: signUser.objectId };
const obj = { UserPtr: UserPtr, SignedUrl: '', Activity: 'Signed', ipAddress: userIP };
let updateAuditTrail;
if (_resDoc.AuditTrail && _resDoc.AuditTrail.length > 0) {
updateAuditTrail = [..._resDoc.AuditTrail, obj];
} else { } else {
className = 'contracts_Users'; updateAuditTrail = [obj];
signUser = _resDoc.ExtUserPtr;
} }
const username = signUser.Name; const auditTrail = updateAuditTrail.filter(x => x.Activity === 'Signed');
const userEmail = signUser.Email; let isCompleted = false;
if (req.params.pdfFile) { if (_resDoc.Signers && _resDoc.Signers.length > 0) {
// `PdfBuffer` used to create buffer from pdf file if (auditTrail.length === _resDoc.Signers.length) {
let PdfBuffer = Buffer.from(req.params.pdfFile, 'base64');
// `P12Buffer` used to create buffer from p12 certificate
const pfxFile = process.env.PFX_BASE64;
// const P12Buffer = fs.readFileSync();
const P12Buffer = Buffer.from(pfxFile, 'base64');
const p12Cert = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null });
const UserPtr = {
__type: 'Pointer',
className: className,
objectId: signUser.objectId,
};
const obj = {
UserPtr: UserPtr,
SignedUrl: '',
Activity: 'Signed',
ipAddress: req.headers['x-real-ip'],
};
let updateAuditTrail;
if (_resDoc.AuditTrail && _resDoc.AuditTrail.length > 0) {
updateAuditTrail = [..._resDoc.AuditTrail, obj];
} else {
updateAuditTrail = [obj];
}
const auditTrail = updateAuditTrail.filter(x => x.Activity === 'Signed');
let isCompleted = false;
if (_resDoc.Signers && _resDoc.Signers.length > 0) {
if (auditTrail.length === _resDoc.Signers.length) {
isCompleted = true;
}
} else {
isCompleted = true; isCompleted = true;
} }
const randomNumber = Math.floor(Math.random() * 5000);
const name = `exported_file_${randomNumber}.pdf`;
const pdfName = `./exports/${name}`;
let pdfSize = PdfBuffer.length;
if (isCompleted) {
const signersName = _resDoc.Signers?.map(x => x.Name + ' <' + x.Email + '>');
if (signersName && signersName.length > 0) {
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget
const pdfDoc = await PDFDocument.load(PdfBuffer);
pdflibAddPlaceholder({
pdfDoc: pdfDoc,
reason: 'Digitally signed by OpenSign for ' + signersName?.join(', '),
location: 'n/a',
name: eSignName,
contactInfo: eSigncontact,
signatureLength: 15000,
});
const pdfWithPlaceholderBytes = await pdfDoc.save();
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
} else {
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget (signyourself)
const pdfDoc = await PDFDocument.load(PdfBuffer);
pdflibAddPlaceholder({
pdfDoc: pdfDoc,
reason: 'Digitally signed by OpenSign for ' + username + ' <' + userEmail + '>',
location: 'n/a',
name: eSignName,
contactInfo: eSigncontact,
signatureLength: 15000,
});
const pdfWithPlaceholderBytes = await pdfDoc.save();
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
}
//`new signPDF` create new instance of pdfBuffer and p12Buffer
const OBJ = new SignPdf();
// `signedDocs` is used to signpdf digitally
const signedDocs = await OBJ.sign(PdfBuffer, p12Cert);
//`saveUrl` is used to save signed pdf in exports folder
const saveUrl = fs.writeFileSync(pdfName, signedDocs);
pdfSize = signedDocs.length;
} else {
//`saveUrl` is used to save signed pdf in exports folder
const saveUrl = fs.writeFileSync(pdfName, PdfBuffer);
pdfSize = PdfBuffer.length;
}
// `uploadFile` is used to upload pdf to aws s3 and get it's url
const data = await uploadFile(name, pdfName);
if (data && data.imageUrl) {
// `axios` is used to update signed pdf url in contracts_Document classes for given DocId
const updatedDoc = await updateDoc(
req.params.docId, //docId
data.imageUrl, // url
signUser.objectId, // userID
req.headers['x-real-ip'], // client ipAddress,
_resDoc, // auditTrail, signers, etc data
className,
sign
);
sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser);
saveFileUsage(pdfSize, data.imageUrl, authUser.objectId);
if (updatedDoc && updatedDoc.isCompleted) {
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail };
sendMailsaveCertifcate(
doc,
P12Buffer,
data.imageUrl,
isCustomMail,
mailProvider,
authUser.objectId
);
}
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
fs.unlinkSync(pdfName);
console.log(`New Signed PDF created called: ${pdfName}`);
if (updatedDoc.message === 'success') {
return { status: 'success', data: data.imageUrl };
} else {
const error = new Error('Please provide required parameters!');
error.code = 400; // Set the error code (e.g., 400 for bad request)
throw error;
}
}
} else { } else {
const error = new Error('Pdf file not present!'); isCompleted = true;
error.code = 400; // Set the error code (e.g., 400 for bad request)
throw error;
} }
const randomNumber = Math.floor(Math.random() * 5000);
const name = `exported_file_${randomNumber}.pdf`;
const pdfName = `./exports/${name}`;
let pdfSize = PdfBuffer.length;
if (isCompleted) {
const signersName = _resDoc.Signers?.map(x => x.Name + ' <' + x.Email + '>');
if (signersName && signersName.length > 0) {
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget
const pdfDoc = await PDFDocument.load(PdfBuffer);
pdflibAddPlaceholder({
pdfDoc: pdfDoc,
reason: 'Digitally signed by OpenSign for ' + signersName?.join(', '),
location: 'n/a',
name: eSignName,
contactInfo: eSigncontact,
signatureLength: 15000,
});
const pdfWithPlaceholderBytes = await pdfDoc.save();
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
} else {
// `pdflibAddPlaceholder` is used to add code of only digitial sign without widget (signyourself)
const pdfDoc = await PDFDocument.load(PdfBuffer);
pdflibAddPlaceholder({
pdfDoc: pdfDoc,
reason: 'Digitally signed by OpenSign for ' + username + ' <' + userEmail + '>',
location: 'n/a',
name: eSignName,
contactInfo: eSigncontact,
signatureLength: 15000,
});
const pdfWithPlaceholderBytes = await pdfDoc.save();
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
}
//`new signPDF` create new instance of pdfBuffer and p12Buffer
const OBJ = new SignPdf();
// `signedDocs` is used to signpdf digitally
const signedDocs = await OBJ.sign(PdfBuffer, p12Cert);
//`saveUrl` is used to save signed pdf in exports folder
const saveUrl = fs.writeFileSync(pdfName, signedDocs);
pdfSize = signedDocs.length;
} else {
//`saveUrl` is used to save signed pdf in exports folder
const saveUrl = fs.writeFileSync(pdfName, PdfBuffer);
pdfSize = PdfBuffer.length;
}
// `uploadFile` is used to upload pdf to aws s3 and get it's url
const data = await uploadFile(name, pdfName);
if (data && data.imageUrl) {
// `axios` is used to update signed pdf url in contracts_Document classes for given DocId
const updatedDoc = await updateDoc(
req.params.docId, //docId
data.imageUrl, // url
signUser.objectId, // userID
userIP, // client ipAddress,
_resDoc, // auditTrail, signers, etc data
className, // className based on flow
sign // sign base64
);
sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser);
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
if (updatedDoc && updatedDoc.isCompleted) {
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail };
sendMailsaveCertifcate(
doc,
P12Buffer,
data.imageUrl,
isCustomMail,
mailProvider,
_resDoc?.CreatedBy?.objectId
);
}
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder
fs.unlinkSync(pdfName);
console.log(`New Signed PDF created called: ${pdfName}`);
if (updatedDoc.message === 'success') {
return { status: 'success', data: data.imageUrl };
} else {
const error = new Error('Please provide required parameters!');
error.code = 400; // Set the error code (e.g., 400 for bad request)
throw error;
}
}
} else {
const error = new Error('Pdf file not present!');
error.code = 400; // Set the error code (e.g., 400 for bad request)
throw error;
} }
} catch (err) { } catch (err) {
console.log('Err in signpdf', err); console.log('Err in signpdf', err);
@@ -0,0 +1,33 @@
export default async function updateContactTour(request) {
const contactId = request.params.contactId;
try {
const contactCls = new Parse.Query('contracts_Contactbook');
const contactRes = await contactCls.get(contactId, { useMasterKey: true });
if (contactRes) {
const _contactRes = JSON.parse(JSON.stringify(contactRes));
const tourStatus = _contactRes?.TourStatus?.length > 0 ? _contactRes.TourStatus : [];
let updatedTourStatus = [];
if (tourStatus.length > 0) {
updatedTourStatus = [...tourStatus];
const requestSignIndex = tourStatus.findIndex(
obj => obj['requestSign'] === false || obj['requestSign'] === true
);
if (requestSignIndex !== -1) {
updatedTourStatus[requestSignIndex] = { requestSign: true };
} else {
updatedTourStatus.push({ requestSign: true });
}
} else {
updatedTourStatus = [{ requestSign: true }];
}
contactRes.set('TourStatus', updatedTourStatus);
const updateRes = await contactRes.save(null, { useMasterKey: true });
return updateRes;
} else {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'contact not found.');
}
} catch (err) {
console.log('Err in contracts_Contactbook class ', err);
throw err;
}
}
@@ -0,0 +1,29 @@
/**
*
* @param {Parse} Parse
*/
exports.up = async Parse => {
const templateSchema = new Parse.Schema('contracts_Template');
templateSchema.addBoolean('IsEnableOTP');
await templateSchema.update();
const className = 'contracts_Document';
const schema = new Parse.Schema(className);
schema.addBoolean('IsEnableOTP');
return schema.update();
};
/**
*
* @param {Parse} Parse
*/
exports.down = async Parse => {
const templateSchema = new Parse.Schema('contracts_Template');
templateSchema.deleteField('IsEnableOTP');
await templateSchema.update();
const className = 'contracts_Document';
const schema = new Parse.Schema(className);
schema.deleteField('IsEnableOTP');
return schema.update();
};
+174 -169
View File
@@ -19,17 +19,17 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.20.0", "express": "^4.21.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"generate-api-key": "^1.0.2", "generate-api-key": "^1.0.2",
"googleapis": "^140.0.1", "googleapis": "^140.0.1",
"jsonschema": "^1.4.1", "jsonschema": "^1.4.1",
"mailgun.js": "^10.2.3", "mailgun.js": "^10.2.3",
"mongoose": "^8.6.0", "mongoose": "^8.6.1",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1", "multer-s3": "^3.0.1",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"nodemailer": "^6.9.14", "nodemailer": "^6.9.15",
"parse": "^5.3.0", "parse": "^5.3.0",
"parse-dbtool": "^1.2.0", "parse-dbtool": "^1.2.0",
"parse-server": "^7.2.0", "parse-server": "^7.2.0",
@@ -41,7 +41,7 @@
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.25.1", "@babel/eslint-parser": "^7.25.1",
"eslint": "^9.9.1", "eslint": "^9.9.1",
"jasmine": "^5.2.0", "jasmine": "^5.3.0",
"mongodb-runner": "^5.6.6", "mongodb-runner": "^5.6.6",
"nodemon": "^3.1.4", "nodemon": "^3.1.4",
"nyc": "^17.0.0", "nyc": "^17.0.0",
@@ -1770,11 +1770,12 @@
} }
}, },
"node_modules/@google-cloud/firestore": { "node_modules/@google-cloud/firestore": {
"version": "7.9.0", "version": "7.10.0",
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.9.0.tgz", "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.10.0.tgz",
"integrity": "sha512-c4ALHT3G08rV7Zwv8Z2KG63gZh66iKdhCBeDfCpIkLrjX6EAjTD/szMdj14M+FnQuClZLFfW5bAgoOjfNmLtJg==", "integrity": "sha512-VFNhdHvfnmqcHHs6YhmSNHHxQqaaD64GwiL0c+e1qz85S8SWZPC2XFRf8p9yHRTF40Kow424s1KBU9f0fdQa+Q==",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@opentelemetry/api": "^1.3.0",
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"google-gax": "^4.3.3", "google-gax": "^4.3.3",
@@ -1866,9 +1867,9 @@
} }
}, },
"node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": { "node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": {
"version": "10.5.2", "version": "10.5.4",
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.2.tgz", "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz",
"integrity": "sha512-VZpw7wxwmQGcCGt8epw6fDb8LkoySbTJ/MU565ibKivPqCkH96XK36Et/N0RlRCYGN6QAXn5UIaSbOYYHrnpAA==", "integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==",
"dependencies": { "dependencies": {
"@graphql-typed-document-node/core": "^3.1.1", "@graphql-typed-document-node/core": "^3.1.1",
"cross-inspect": "1.0.1", "cross-inspect": "1.0.1",
@@ -1900,9 +1901,9 @@
} }
}, },
"node_modules/@graphql-tools/schema/node_modules/@graphql-tools/utils": { "node_modules/@graphql-tools/schema/node_modules/@graphql-tools/utils": {
"version": "10.5.2", "version": "10.5.4",
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.2.tgz", "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz",
"integrity": "sha512-VZpw7wxwmQGcCGt8epw6fDb8LkoySbTJ/MU565ibKivPqCkH96XK36Et/N0RlRCYGN6QAXn5UIaSbOYYHrnpAA==", "integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==",
"dependencies": { "dependencies": {
"@graphql-typed-document-node/core": "^3.1.1", "@graphql-typed-document-node/core": "^3.1.1",
"cross-inspect": "1.0.1", "cross-inspect": "1.0.1",
@@ -1936,9 +1937,9 @@
} }
}, },
"node_modules/@grpc/grpc-js": { "node_modules/@grpc/grpc-js": {
"version": "1.11.1", "version": "1.11.2",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.1.tgz", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.2.tgz",
"integrity": "sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw==", "integrity": "sha512-DWp92gDD7/Qkj7r8kus6/HCINeo3yPZWZ3paKgDgsbKbSpoxKg1yvN8xe2Q8uE3zOsPe3bX8FQX2+XValq2yTw==",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@grpc/proto-loader": "^0.7.13", "@grpc/proto-loader": "^0.7.13",
@@ -2625,6 +2626,15 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@opentelemetry/api": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"optional": true,
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@parse/fs-files-adapter": { "node_modules/@parse/fs-files-adapter": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-3.0.0.tgz",
@@ -3771,11 +3781,11 @@
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.2.0", "version": "22.5.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
"integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==", "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
"dependencies": { "dependencies": {
"undici-types": "~6.13.0" "undici-types": "~6.19.2"
} }
}, },
"node_modules/@types/node-fetch": { "node_modules/@types/node-fetch": {
@@ -3793,9 +3803,9 @@
"integrity": "sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw==" "integrity": "sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw=="
}, },
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.15", "version": "6.9.16",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A=="
}, },
"node_modules/@types/range-parser": { "node_modules/@types/range-parser": {
"version": "1.2.7", "version": "1.2.7",
@@ -4157,9 +4167,9 @@
} }
}, },
"node_modules/aws4": { "node_modules/aws4": {
"version": "1.13.1", "version": "1.13.2",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
"integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==" "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.7.7", "version": "1.7.7",
@@ -4270,9 +4280,9 @@
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.2", "version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
"content-type": "~1.0.5", "content-type": "~1.0.5",
@@ -4282,7 +4292,7 @@
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"qs": "6.11.0", "qs": "6.13.0",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "1.0.0" "unpipe": "1.0.0"
@@ -4305,6 +4315,20 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}, },
"node_modules/body-parser/node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/bowser": { "node_modules/bowser": {
"version": "2.11.0", "version": "2.11.0",
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz",
@@ -5201,9 +5225,9 @@
} }
}, },
"node_modules/dset": { "node_modules/dset": {
"version": "3.1.3", "version": "3.1.4",
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
"integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@@ -5746,9 +5770,9 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.20.0", "version": "4.21.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
"integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
@@ -5762,7 +5786,7 @@
"encodeurl": "~2.0.0", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"etag": "~1.8.1", "etag": "~1.8.1",
"finalhandler": "1.2.0", "finalhandler": "1.3.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"merge-descriptors": "1.0.3", "merge-descriptors": "1.0.3",
@@ -5771,11 +5795,11 @@
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.10", "path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.11.0", "qs": "6.13.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"send": "0.19.0", "send": "0.19.0",
"serve-static": "1.16.0", "serve-static": "1.16.2",
"setprototypeof": "1.2.0", "setprototypeof": "1.2.0",
"statuses": "2.0.1", "statuses": "2.0.1",
"type-is": "~1.6.18", "type-is": "~1.6.18",
@@ -5797,43 +5821,6 @@
"express": "^4 || ^5" "express": "^4 || ^5"
} }
}, },
"node_modules/express/node_modules/body-parser": {
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/express/node_modules/body-parser/node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/express/node_modules/debug": { "node_modules/express/node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -5850,11 +5837,42 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/express/node_modules/finalhandler": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/express/node_modules/ms": { "node_modules/express/node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}, },
"node_modules/express/node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/ext": { "node_modules/ext": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
@@ -6125,11 +6143,11 @@
} }
}, },
"node_modules/firebase-admin/node_modules/@types/node": { "node_modules/firebase-admin/node_modules/@types/node": {
"version": "20.14.15", "version": "20.16.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
"integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==", "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~6.19.2"
} }
}, },
"node_modules/firebase-admin/node_modules/long": { "node_modules/firebase-admin/node_modules/long": {
@@ -6137,11 +6155,6 @@
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
}, },
"node_modules/firebase-admin/node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"node_modules/flat-cache": { "node_modules/flat-cache": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
@@ -6583,9 +6596,9 @@
} }
}, },
"node_modules/google-gax": { "node_modules/google-gax": {
"version": "4.3.9", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.9.tgz", "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz",
"integrity": "sha512-tcjQr7sXVGMdlvcG25wSv98ap1dtF4Z6mcV0rztGIddOcezw4YMb/uTXg72JPrLep+kXcVjaJjg6oo3KLf4itQ==", "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@grpc/grpc-js": "^1.10.9", "@grpc/grpc-js": "^1.10.9",
@@ -7426,22 +7439,22 @@
} }
}, },
"node_modules/jasmine": { "node_modules/jasmine": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.2.0.tgz", "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.3.0.tgz",
"integrity": "sha512-il+noV96N1BGU9/FMmc8QtAMxC8lPnXUiAvgb0o9MDZATRdxglTQe9wo6UdL049ropQL6MopDYwDlludKR6wJQ==", "integrity": "sha512-Vrv5VWTXVZ/5xcNawlYCmE24pOaZu3KduLr9iAaENoMJ8W8Ryvhfpw2cf3rI4Unc2ajvu2t4tCKjS72TnraBGQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"glob": "^10.2.2", "glob": "^10.2.2",
"jasmine-core": "~5.2.0" "jasmine-core": "~5.3.0"
}, },
"bin": { "bin": {
"jasmine": "bin/jasmine.js" "jasmine": "bin/jasmine.js"
} }
}, },
"node_modules/jasmine-core": { "node_modules/jasmine-core": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.2.0.tgz", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz",
"integrity": "sha512-tSAtdrvWybZkQmmaIoDgnvHG8ORUNw5kEVlO5CvrXj02Jjr9TZrmjFq7FUiOUzJiOP2wLGYT6PgrQgQF4R1xiw==", "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==",
"dev": true "dev": true
}, },
"node_modules/jmespath": { "node_modules/jmespath": {
@@ -7828,9 +7841,9 @@
} }
}, },
"node_modules/loglevel": { "node_modules/loglevel": {
"version": "1.9.1", "version": "1.9.2",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
"integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==", "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
"engines": { "engines": {
"node": ">= 0.6.0" "node": ">= 0.6.0"
}, },
@@ -8276,9 +8289,9 @@
} }
}, },
"node_modules/mongoose": { "node_modules/mongoose": {
"version": "8.6.0", "version": "8.6.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.0.tgz", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.1.tgz",
"integrity": "sha512-p6VSbYKvD4ZIabqo8C0kS5eKX1Xpji+opTAIJ9wyuPJ8Y/FblgXSMnFRXnB40bYZLKPQT089K5KU8+bqIXtFdw==", "integrity": "sha512-dppGcYqvsdg+VcnqXR5b467V4a+iNhmvkfYNpEPi6AjaUxnz6ioEDmrMLOi+sOWjvoHapuwPOigV4f2l7HC6ag==",
"dependencies": { "dependencies": {
"bson": "^6.7.0", "bson": "^6.7.0",
"kareem": "2.6.3", "kareem": "2.6.3",
@@ -8501,9 +8514,9 @@
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.65.0", "version": "3.67.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz",
"integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", "integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==",
"dependencies": { "dependencies": {
"semver": "^7.3.5" "semver": "^7.3.5"
}, },
@@ -8596,9 +8609,9 @@
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g=="
}, },
"node_modules/nodemailer": { "node_modules/nodemailer": {
"version": "6.9.14", "version": "6.9.15",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.15.tgz",
"integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==", "integrity": "sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
} }
@@ -9397,6 +9410,42 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/parse-server/node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/parse-server/node_modules/body-parser/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/parse-server/node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/parse-server/node_modules/bson": { "node_modules/parse-server/node_modules/bson": {
"version": "5.5.1", "version": "5.5.1",
"resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz",
@@ -10400,9 +10449,9 @@
} }
}, },
"node_modules/protobufjs": { "node_modules/protobufjs": {
"version": "7.3.2", "version": "7.4.0",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
"integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
"hasInstallScript": true, "hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@@ -10458,9 +10507,9 @@
"dev": true "dev": true
}, },
"node_modules/pump": { "node_modules/pump": {
"version": "3.0.0", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
"dependencies": { "dependencies": {
"end-of-stream": "^1.1.0", "end-of-stream": "^1.1.0",
"once": "^1.3.1" "once": "^1.3.1"
@@ -10932,69 +10981,25 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "1.16.0", "version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": { "dependencies": {
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"send": "0.18.0" "send": "0.19.0"
}, },
"engines": { "engines": {
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/serve-static/node_modules/debug": { "node_modules/serve-static/node_modules/encodeurl": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/serve-static/node_modules/debug/node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
},
"node_modules/serve-static/node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"bin": {
"mime": "cli.js"
},
"engines": { "engines": {
"node": ">=4" "node": ">= 0.8"
}
},
"node_modules/serve-static/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serve-static/node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
} }
}, },
"node_modules/set-blocking": { "node_modules/set-blocking": {
@@ -11997,9 +12002,9 @@
"dev": true "dev": true
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.13.0", "version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
}, },
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
+4 -4
View File
@@ -28,17 +28,17 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.20.0", "express": "^4.21.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"generate-api-key": "^1.0.2", "generate-api-key": "^1.0.2",
"googleapis": "^140.0.1", "googleapis": "^140.0.1",
"jsonschema": "^1.4.1", "jsonschema": "^1.4.1",
"mailgun.js": "^10.2.3", "mailgun.js": "^10.2.3",
"mongoose": "^8.6.0", "mongoose": "^8.6.1",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1", "multer-s3": "^3.0.1",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"nodemailer": "^6.9.14", "nodemailer": "^6.9.15",
"parse": "^5.3.0", "parse": "^5.3.0",
"parse-dbtool": "^1.2.0", "parse-dbtool": "^1.2.0",
"parse-server": "^7.2.0", "parse-server": "^7.2.0",
@@ -51,7 +51,7 @@
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.25.1", "@babel/eslint-parser": "^7.25.1",
"eslint": "^9.9.1", "eslint": "^9.9.1",
"jasmine": "^5.2.0", "jasmine": "^5.3.0",
"mongodb-runner": "^5.6.6", "mongodb-runner": "^5.6.6",
"nodemon": "^3.1.4", "nodemon": "^3.1.4",
"nyc": "^17.0.0", "nyc": "^17.0.0",