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-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.8",
"lint-staged": "^15.2.10",
"mini-css-extract-plugin": "^2.9.1",
"postcss": "^8.4.45",
"prettier": "^3.3.3",
@@ -7592,9 +7592,9 @@
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"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==",
"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",
@@ -7604,7 +7604,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -11040,36 +11040,36 @@
}
},
"node_modules/express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"send": "0.19.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -11099,15 +11099,23 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/express/node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
},
"node_modules/express/node_modules/range-parser": {
"version": "1.2.1",
@@ -11374,12 +11382,12 @@
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"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": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@@ -11398,6 +11406,14 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -16287,9 +16303,9 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
"node_modules/lint-staged": {
"version": "15.2.9",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz",
"integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==",
"version": "15.2.10",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz",
"integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==",
"dev": true,
"dependencies": {
"chalk": "~5.3.0",
@@ -16298,7 +16314,7 @@
"execa": "~8.0.1",
"lilconfig": "~3.1.2",
"listr2": "~8.2.4",
"micromatch": "~4.0.7",
"micromatch": "~4.0.8",
"pidtree": "~0.6.0",
"string-argv": "~0.3.2",
"yaml": "~2.5.0"
@@ -16908,9 +16924,12 @@
"dev": true
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge-refs": {
"version": "1.3.0",
@@ -19758,11 +19777,11 @@
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"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.4"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -22319,9 +22338,9 @@
}
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
@@ -22504,19 +22523,27 @@
}
},
"node_modules/serve-static": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": {
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
"send": "0.19.0"
},
"engines": {
"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": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+1 -1
View File
@@ -109,7 +109,7 @@
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.8",
"lint-staged": "^15.2.10",
"mini-css-extract-plugin": "^2.9.1",
"postcss": "^8.4.45",
"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-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head":"Quota Reached",
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminName}}<{{adminEmail}}>.",
"sent-this-month":"Sent this month"
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminEmail}}.",
"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-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",
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminName}}<{{adminEmail}}>.",
"sent-this-month":"envoyé ce mois-ci"
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
"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);
setPlanInfo((obj) => ({ ...obj, totalAllowedUser: _resAddon.addon }));
}
if (props.handleBuyUsers) {
props.handleBuyUsers(amount.quantity, _resAddon.addon);
}
}
} catch (err) {
console.log("Err in buy addon", err);
@@ -495,8 +498,7 @@ const AddUser = (props) => {
{planInfo.adminId !== extUser?.objectId ? (
<div className="mb-3 mt-1 flex justify-center text-center items-center font-medium break-all">
{t("unauthorized-modal", {
adminName: extUser?.CreatedBy?.name,
adminEmail: extUser?.CreatedBy?.email
adminEmail: extUser?.TenantId?.EmailAddress
})}
</div>
) : (
+2 -7
View File
@@ -31,7 +31,6 @@ const BulkSendUi = (props) => {
const [isFreePlan, setIsFreePlan] = useState(false);
const [admin, setAdmin] = useState({
objectId: "",
name: "",
email: "",
isAdmin: true
});
@@ -63,8 +62,7 @@ const BulkSendUi = (props) => {
setAdmin((obj) => ({
...obj,
isAdmin: false,
name: extUser?.CreatedBy?.name,
email: extUser?.CreatedBy?.email
email: extUser?.TenantId?.EmailAddress
}));
}
setAdmin((obj) => ({ ...obj, objectId: subscription?.adminId }));
@@ -491,10 +489,7 @@ const BulkSendUi = (props) => {
</form>
) : (
<div className="mx-8 mt-4 mb-8 flex justify-center text-center items-center font-medium break-all">
{t("unauthorized-modal", {
adminName: admin?.name,
adminEmail: admin?.email
})}
{t("unauthorized-modal", { adminEmail: admin?.email })}
</div>
)}
</>
@@ -3,6 +3,8 @@ import { checkIsSubscribed, getFileName } from "../../constant/Utils";
import Upgrade from "../../primitives/Upgrade";
import { isEnableSubscription } from "../../constant/const";
import { useTranslation } from "react-i18next";
import { Tooltip } from "react-tooltip";
// import SelectFolder from "../../premitives/SelectFolder";
const EditTemplate = ({ template, onSuccess }) => {
@@ -14,7 +16,8 @@ const EditTemplate = ({ template, onSuccess }) => {
Description: template?.Description || "",
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
AutomaticReminders: template?.AutomaticReminders || false,
RemindOnceInEvery: template?.RemindOnceInEvery || 5
RemindOnceInEvery: template?.RemindOnceInEvery || 5,
IsEnableOTP: template?.IsEnableOTP ? `${template?.IsEnableOTP}` : "false"
});
const [isSubscribe, setIsSubscribe] = useState(false);
useEffect(() => {
@@ -41,7 +44,7 @@ const EditTemplate = ({ template, onSuccess }) => {
e.stopPropagation();
const isChecked = formData.SendinOrder === "true" ? true : false;
const AutoReminder = formData?.AutomaticReminders || false;
const IsEnableOTP = formData.IsEnableOTP === "true" ? true : false;
let reminderDate = {};
if (AutoReminder) {
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
@@ -49,7 +52,12 @@ const EditTemplate = ({ template, onSuccess }) => {
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
reminderDate = { NextReminderDate: ReminderDate };
}
const data = { ...formData, SendinOrder: isChecked, ...reminderDate };
const data = {
...formData,
SendinOrder: isChecked,
IsEnableOTP: IsEnableOTP,
...reminderDate
};
onSuccess(data);
};
const handleAutoReminder = () => {
@@ -184,6 +192,70 @@ const EditTemplate = ({ template, onSuccess }) => {
/>
</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">
<button type="submit" className="op-btn op-btn-primary">
{t("submit")}
@@ -154,7 +154,9 @@ function EmailComponent({
<div className="flex flex-row">
{!isAndroid && (
<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]"
>
<i className="fa-light fa-print" aria-hidden="true"></i>
@@ -142,7 +142,7 @@ function Header({
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading)
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
}
>
<div className="flex flex-row">
@@ -342,7 +342,9 @@ function Header({
alreadySign ? (
<div className="flex flex-row">
<button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
}
type="button"
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
>
@@ -459,7 +461,9 @@ function Header({
</button>
)}
<button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
}
type="button"
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 [isSignImg, setIsSignImg] = useState("");
const [signValue, setSignValue] = useState("");
const [textWidth, setTextWidth] = useState(null);
const [textHeight, setTextHeight] = useState(null);
const [textWidth, setTextWidth] = useState(0);
const [textHeight, setTextHeight] = useState(0);
const [signatureType, setSignatureType] = useState("draw");
const fontOptions = [
{ value: "Fasthand" },
@@ -51,7 +51,7 @@ function SignPad({
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const jsonSender = JSON.parse(senderUser);
const currentUserName = jsonSender && jsonSender.name;
const currentUserName = jsonSender && jsonSender?.name;
//function for clear signature image
const handleClear = () => {
@@ -137,7 +137,7 @@ function SignPad({
(isTab === "draw" && isSignImg) ||
(isTab === "image" && image) ||
(isTab === "mysignature" && isDefaultSign) ||
(isTab === "type" && textWidth)
(isTab === "type" && signValue)
? false
: image
? false
@@ -169,10 +169,10 @@ function SignPad({
}
}
const trimmedName = currentUserName && currentUserName.trim();
const trimmedName = currentUserName && currentUserName?.trim();
const firstCharacter = trimmedName?.charAt(0);
const userName = isInitial ? firstCharacter : currentUserName;
setSignValue(userName);
setSignValue(userName || "");
setFontSelect("Fasthand");
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -200,8 +200,10 @@ function SignPad({
canvasRef.current.fromDataURL(isSignImg);
}
if (isTab === "type") {
const trimmedName = signValue ? signValue.trim() : currentUserName.trim();
const firstCharacter = trimmedName.charAt(0);
const trimmedName = signValue
? signValue?.trim()
: currentUserName?.trim();
const firstCharacter = trimmedName?.charAt(0);
const userName = isInitial ? firstCharacter : signValue;
setSignValue(userName);
convertToImg(fontSelect, userName);
+13 -7
View File
@@ -708,7 +708,8 @@ export const createDocument = async (
Signers: signers,
SendinOrder: Doc?.SendinOrder || false,
AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5)
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5),
IsEnableOTP: Doc?.IsEnableOTP || false
};
try {
@@ -1741,9 +1742,7 @@ export const contactBook = async (objectId) => {
//function for getting document details from contract_Documents class
export const contractDocument = async (documentId) => {
const data = {
docId: documentId
};
const data = { docId: documentId };
const documentDeatils = await axios
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
headers: {
@@ -2047,11 +2046,12 @@ export const handleDownloadPdf = async (
) => {
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
setIsDownloading("pdf");
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl },
{ url: pdfUrl, docId: docId },
{
headers: {
"content-type": "Application/json",
@@ -2075,16 +2075,22 @@ export const sanitizeFileName = (pdfName) => {
return pdfName.replace(/ /g, "_");
};
//function for print digital sign pdf
export const handleToPrint = async (event, pdfUrl, setIsDownloading) => {
export const handleToPrint = async (
event,
pdfUrl,
setIsDownloading,
pdfDetails
) => {
event.preventDefault();
setIsDownloading("pdf");
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
//`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
const axiosRes = await axios.post(
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl },
{ url: pdfUrl, docId: docId },
{
headers: {
"content-type": "Application/json",
+2 -2
View File
@@ -252,9 +252,9 @@ const HomeLayout = () => {
}
};
const handleLoginBtn = () => {
const handleLoginBtn = async () => {
try {
Parse?.User?.logOut();
await Parse?.User?.logOut();
} catch (err) {
console.log("err ", err);
} finally {
+209 -108
View File
@@ -61,7 +61,8 @@ const Forms = (props) => {
password: "",
file: "",
remindOnceInEvery: 5,
autoreminder: false
autoreminder: false,
IsEnableOTP: "false"
});
const [fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
@@ -74,6 +75,7 @@ const Forms = (props) => {
const [isDecrypting, setIsDecrypting] = useState(false);
const [isCorrectPass, setIsCorrectPass] = useState(true);
const [isSubscribe, setIsSubscribe] = useState(false);
const [isAdvanceOpt, setIsAdvanceOpt] = useState(false);
const handleStrInput = (e) => {
setIsCorrectPass(true);
setFormData({ ...formData, [e.target.name]: e.target.value });
@@ -137,7 +139,6 @@ const Forms = (props) => {
} catch (err) {
console.log("err in sending posthog encryptedpdf", err);
}
// console.log("err ", err);
try {
setIsDecrypting(true);
const size = files?.[0].size;
@@ -402,6 +403,13 @@ const Forms = (props) => {
object.set("SendinOrder", isChecked);
object.set("AutomaticReminders", formData.autoreminder);
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("CreatedBy", Parse.User.createWithoutData(currentUser.id));
@@ -428,7 +436,17 @@ const Forms = (props) => {
setFormData({
Name: "",
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("");
setpercentage(0);
@@ -477,7 +495,8 @@ const Forms = (props) => {
password: "",
file: "",
remindOnceInEvery: 5,
autoreminder: false
autoreminder: false,
IsEnableOTP: "false"
});
setFileUpload("");
setpercentage(0);
@@ -641,7 +660,7 @@ const Forms = (props) => {
)}
<div className="text-xs">
<label className="block">
{`${t("report-heading.File")} (${t("file-type")} ${
{`${t("report-heading.File")} (${t("file-type")}${
isEnableSubscription ? ", docx)" : ")"
}`}
<span className="text-red-500 text-[13px]">*</span>
@@ -754,120 +773,73 @@ const Forms = (props) => {
isReset={isReset}
/>
)}
{props.title === "Request Signatures" && (
{props.title !== "Sign Yourself" && (
<div className="text-xs mt-2">
<label className="block">
{t("time-to-complete")}
<span className="text-red-500 text-[13px]">*</span>
{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>
<input
type="number"
name="TimeToCompleteDays"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.TimeToCompleteDays}
onChange={(e) => handleStrInput(e)}
onInvalid={(e) =>
e.target.setCustomValidity(t("input-required"))
}
onInput={(e) => e.target.setCustomValidity("")}
required
/>
<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>
)}
{props.title !== "Sign Yourself" && (
<>
<div className="text-xs mt-2">
<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 && (
{isAdvanceOpt && (
<div className={` overflow-y-auto z-[500] transition-all`}>
{props.title === "Request Signatures" && (
<div className="text-xs mt-2">
<label className="block">
{t("remind-once")}
{t("time-to-complete")}
<span className="text-red-500 text-[13px]">*</span>
</label>
<input
type="number"
value={formData.remindOnceInEvery}
name="remindOnceInEvery"
name="TimeToCompleteDays"
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) =>
e.target.setCustomValidity(t("input-required"))
}
@@ -876,7 +848,136 @@ const Forms = (props) => {
/>
</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">
<button
+1 -4
View File
@@ -28,7 +28,6 @@ function GenerateToken() {
plan: "",
isValid: false,
adminId: "",
adminName: "",
adminEmail: ""
});
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
@@ -154,8 +153,7 @@ function GenerateToken() {
} else {
setIsSubscribe((obj) => ({
...obj,
adminName: extUser?.CreatedBy?.name,
adminEmail: extUser?.CreatedBy?.email
adminEmail: extUser?.TenantId?.EmailAddress
}));
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">
{t("unauthorized-modal", {
adminName: isSubscribe?.adminName,
adminEmail: isSubscribe?.adminEmail
})}
</div>
+36 -12
View File
@@ -28,6 +28,28 @@ function GuestLogin() {
const [contactId, setContactId] = useState(contactBookId);
const [sendmail, setSendmail] = useState();
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(() => {
handleServerUrl();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -70,13 +92,14 @@ function GuestLogin() {
"linkcontacttodoc",
params
);
// console.log("linkContactRes ", linkContactRes);
setContactId(linkContactRes?.contactId);
await navigateToDoc(checkSplit[0], linkContactRes?.contactId);
} catch (err) {
console.log("Err in link ext contact", err);
}
} else {
setContactId(checkSplit[2]);
await navigateToDoc(checkSplit[0], checkSplit[2]);
}
}
@@ -114,15 +137,12 @@ function GuestLogin() {
if (OTP) {
setLoading(true);
try {
let url = `${serverUrl}functions/AuthLoginAsMail/`;
let url = `${serverUrl}functions/AuthLoginAsMail`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseId
};
let body = {
email: email,
otp: OTP
};
let body = { email: email, otp: OTP };
let user = await axios.post(url, body, { headers: headers });
if (user.data.result === "Invalid Otp") {
alert(t("invalid-otp"));
@@ -140,7 +160,6 @@ function GuestLogin() {
`Parse/${parseId}/currentUser`,
JSON.stringify(_user)
);
// console.log("contractUserDetails ", contractUserDetails);
if (contractUserDetails && contractUserDetails.length > 0) {
localStorage.setItem(
"Extand_Class",
@@ -174,10 +193,15 @@ function GuestLogin() {
try {
setLoading(true);
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
// console.log("linkContactRes ", linkContactRes);
setContactId(linkContactRes.contactId);
setEnterOtp(true);
await SendOtp();
const IsEnableOTP = await navigateToDoc(
documentId,
linkContactRes.contactId
);
if (!IsEnableOTP) {
setEnterOtp(true);
await SendOtp();
}
} catch (err) {
setLoading(false);
alert(t("something-went-wrong-mssg"));
@@ -208,7 +232,7 @@ function GuestLogin() {
<div className="w-full md:w-[50%] text-base-content">
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
{t("guest-email-alert")}
{t("get-otp-alert")}
</legend>
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
<input
@@ -236,7 +260,7 @@ function GuestLogin() {
>
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
<legend className="text-[12px] text-[#878787] mt-2">
{t("get-verification-code-2")}
{t("guest-email-alert")}
</legend>
<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>
+196 -175
View File
@@ -142,23 +142,23 @@ function PdfRequestFiles(props) {
let isGuestSignFlow = false;
let sendmail;
let getDocId = "";
const route = !props.templateId && window.location.pathname; //'/load/recipientSignPdf/TOAVuhXbfw/fPAKdK1qgX'
//window.location.search = ?sendmail=false
const getQuery =
!props.templateId &&
window.location?.search &&
window.location?.search?.split("?"); //['','sendmail=false']
//'sendmail=false'
let contactBookId = "";
const route = !props.templateId && window.location.pathname;
const getQuery = !props.templateId && window.location?.search?.split("?"); //['','sendmail=false']
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;
getDocId = checkSplit[3];
getDocId = routeId[3];
contactBookId = routeId[4];
} 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;
useEffect(() => {
@@ -372,9 +372,10 @@ function PdfRequestFiles(props) {
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const jsonSender = JSON.parse(senderUser);
// `currUserId` will be contactId or extUserId
let currUserId;
//getting document details
const documentData = await contractDocument(documentId || docId);
const documentData = await contractDocument(docId);
if (documentData && documentData.length > 0) {
const url =
documentData[0] &&
@@ -399,13 +400,13 @@ function PdfRequestFiles(props) {
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
const getSigners = documentData[0].Signers;
const getCurrentSigner =
getSigners &&
getSigners.filter(
(data) => data.UserId.objectId === jsonSender?.objectId
);
const getCurrentSigner = getSigners?.find(
(data) => data.UserId.objectId === jsonSender?.objectId
);
currUserId = getCurrentSigner[0] ? getCurrentSigner[0].objectId : "";
currUserId = getCurrentSigner?.objectId
? getCurrentSigner.objectId
: contactBookId || "";
if (isEnableSubscription) {
await checkIsSubscribed(
documentData[0]?.ExtUserPtr?.objectId,
@@ -428,10 +429,7 @@ function PdfRequestFiles(props) {
setIsCelebration(true);
setTimeout(() => setIsCelebration(false), 5000);
} else if (declined) {
const currentDecline = {
currnt: "another",
isDeclined: true
};
const currentDecline = { currnt: "another", isDeclined: true };
setIsDecline(currentDecline);
} else if (currDate > expireUpdateDate) {
const expireDateFormat = moment(new Date(expireDate)).format(
@@ -457,36 +455,24 @@ function PdfRequestFiles(props) {
}
}
}
const audittrailData =
documentData[0].AuditTrail &&
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
const audittrailData = documentData?.[0]?.AuditTrail?.filter(
(data) => data.Activity === "Signed"
);
const checkAlreadySign =
documentData[0].AuditTrail &&
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
documentData?.[0]?.AuditTrail?.some(
(data) =>
data.UserPtr?.objectId === currUserId &&
data?.UserPtr?.objectId === currUserId &&
data.Activity === "Signed"
);
if (
checkAlreadySign &&
checkAlreadySign[0] &&
checkAlreadySign.length > 0
) {
) || false;
if (checkAlreadySign) {
setAlreadySign(true);
} else {
const obj = documentData?.[0];
setSendInOrder(obj?.SendinOrder || false);
if (
obj &&
obj.Signers &&
obj.Signers.length > 0 &&
obj.Placeholders &&
obj.Placeholders.length > 0
obj?.Signers?.length > 0 &&
obj?.Placeholders?.length > 0
) {
const params = {
event: "viewed",
@@ -502,7 +488,10 @@ function PdfRequestFiles(props) {
email: x?.Email,
phone: x?.Phone
})),
viewedBy: jsonSender.email,
viewedBy:
documentData?.[0].Signers?.find(
(x) => x.objectId === currUserId
)?.Email || jsonSender?.email,
viewedAt: new Date(),
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
//then stop to display tour message
if (
(checkAlreadySign &&
checkAlreadySign[0] &&
checkAlreadySign.length > 0) ||
checkAlreadySign ||
!currUserId ||
declined ||
currDate > expireUpdateDate
) {
setRequestSignTour(true);
} else {
//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 statu
const res = await contractUsers();
if (res === "Error: Something went wrong!") {
setHandleError(t("something-went-wrong-mssg"));
} else if (res[0] && res?.length) {
setContractName("_Users");
currUserId = res[0].objectId;
setSignerUserId(currUserId);
const tourData = res[0].TourStatus && res[0].TourStatus;
if (tourData && tourData.length > 0) {
const checkTourRequest = tourData.filter(
(data) => data?.requestSign
const isEnableOTP = documentData?.[0]?.IsEnableOTP || false;
if (!isEnableOTP) {
try {
const resContact = await axios.post(
`${localStorage.getItem("baseUrl")}functions/getcontact`,
{
contactId: currUserId
},
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
}
}
);
setTourStatus(tourData);
setRequestSignTour(checkTourRequest[0]?.requestSign || false);
const contact = resContact?.data?.result;
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) {
const res = await contactBook(currUserId);
} else {
//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!") {
setHandleError(t("something-went-wrong-mssg"));
} else if (res[0] && res.length) {
setContractName("_Contactbook");
const objectId = res[0].objectId;
setSignerUserId(objectId);
} else if (res[0] && res?.length) {
setContractName("_Users");
currUserId = res[0].objectId;
setSignerUserId(currUserId);
const tourData = res[0].TourStatus && res[0].TourStatus;
if (tourData && tourData.length > 0) {
const checkTourRequest = tourData.filter(
@@ -625,8 +625,25 @@ function PdfRequestFiles(props) {
setTourStatus(tourData);
setRequestSignTour(checkTourRequest[0]?.requestSign || false);
}
} else if (res.length === 0) {
setHandleError(t("user-not-exist"));
} else if (res?.length === 0) {
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 });
}
//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") {
setDefaultSignImg(defaultSignRes?.res?.defaultSignature);
setMyInitial(defaultSignRes?.res?.defaultInitial);
} else if (defaultSignRes?.status === "error") {
setHandleError("Error: Something went wrong!");
const sign = defaultSignRes?.res?.defaultSignature || "";
const initials = defaultSignRes?.res?.defaultInitial || "";
setDefaultSignImg(sign);
setMyInitial(initials);
}
setIsLoading({ isLoad: false });
} catch (err) {
@@ -664,20 +681,30 @@ function PdfRequestFiles(props) {
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
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 (!currentUser?.emailVerified) {
const userQuery = new Parse.Query(Parse.User);
const getUser = await userQuery.get(currentUser?.objectId, {
sessionToken: currentUser?.sessionToken
});
if (getUser) {
currentUser = JSON.parse(JSON.stringify(getUser));
if (isEnableOTP) {
try {
if (!currentUser?.emailVerified) {
const userQuery = new Parse.Query(Parse.User);
const getUser = await userQuery.get(currentUser?.objectId, {
sessionToken:
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
if (isEmailVerified) {
setIsEmailVerified(isEmailVerified);
if (!isEnableOTP || isEmailVerified) {
try {
const checkUser = signerPos.filter(
(data) => data.signerObjId === signerObjectId
@@ -858,17 +885,9 @@ function PdfRequestFiles(props) {
// console.log("pdfte", pdfBytes);
//get ExistUserPtr object id of user class to get tenantDetails
const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId;
//get ExistUserPtr email to get userDetails
const res = await contractUsers();
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;
}
let activeMailAdapter =
pdfDetails?.[0]?.ExtUserPtr?.active_mail_adapter;
//function for call to embed signature in pdf and get digital signature pdf
const resSign = await signPdfFun(
pdfBytes,
@@ -880,13 +899,13 @@ function PdfRequestFiles(props) {
widgets
);
if (resSign && resSign.status === "success") {
setPdfUrl(res.data);
setPdfUrl(resSign.data);
setIsSigned(true);
setSignedSigners([]);
setUnSignedSigners([]);
getDocumentDetails(true);
const index = pdfDetails?.[0].Signers.findIndex(
(x) => x.Email === currentUser?.email
getDocumentDetails(documentId, true);
const index = pdfDetails?.[0]?.Signers.findIndex(
(x) => x.objectId === signerObjectId
);
const newIndex = index + 1;
const usermail = {
@@ -1054,21 +1073,6 @@ function PdfRequestFiles(props) {
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);
setIsDecline({ isDeclined: false });
const data = {
IsDeclined: true,
DeclineReason: reason,
DeclineBy: {
__type: "Pointer",
className: "_User",
objectId: jsonSender?.objectId
}
};
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
.put(
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${documentId}`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
.post(`${localStorage.getItem("baseUrl")}functions/declinedoc`, params, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
)
})
.then(async (result) => {
const res = result.data;
if (res) {
@@ -1260,7 +1259,8 @@ function PdfRequestFiles(props) {
email: x?.Email,
phone: x?.Phone
})),
declinedBy: jsonSender.email,
declinedBy: email,
declinedReason: reason,
declinedAt: new Date(),
createdAt: pdfDetails?.[0].createdAt
}
@@ -1314,38 +1314,58 @@ function PdfRequestFiles(props) {
const closeRequestSignTour = async () => {
setRequestSignTour(true);
if (isDontShow) {
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 });
const isEnableOTP = pdfDetails?.[0]?.IsEnableOTP || false;
if (!isEnableOTP) {
try {
await axios.post(
`${localStorage.getItem("baseUrl")}functions/updatecontacttour`,
{
contactId: signerObjectId
},
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
}
}
);
} catch (e) {
console.log("update tour messages error", e);
}
} else {
updatedTourStatus = [{ requestSign: true }];
}
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")
}
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 });
}
);
} catch (e) {
console.log("update tour messages error", e);
} else {
updatedTourStatus = [{ requestSign: true }];
}
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 */}
<PdfDeclineModal
show={isDecline.isDeclined}
headMsg={
pdfDetails[0]?.IsDeclined
? t("document-declined")
: t("document-decline")
}
headMsg={t("document-declined")}
bodyMssg={
isDecline.currnt === "Sure"
? t("decline-alert-1")
@@ -1938,7 +1954,12 @@ function PdfRequestFiles(props) {
<div className="flex mt-4 gap-1 px-[15px]">
<button
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading)
handleToPrint(
e,
pdfUrl,
setIsDownloading,
pdfDetails
)
}
type="button"
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 () => {
try {
Parse?.User?.logOut();
await Parse?.User?.logOut();
} catch (err) {
console.log("Err", err);
console.log("Err while logging out", err);
}
let appdata = localStorage.getItem("userSettings");
let applogo = localStorage.getItem("appLogo");
@@ -779,6 +779,7 @@ const TemplatePlaceholder = () => {
AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
NextReminderDate: pdfDetails[0]?.NextReminderDate,
IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
URL: pdfUrl
};
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 SubscribeCard from "../primitives/SubscribeCard";
import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribed } from "../constant/Utils";
import { fetchSubscriptionInfo } from "../constant/Utils";
import Title from "../components/Title";
import { validplan } from "../json/plansArr";
import { useTranslation } from "react-i18next";
@@ -19,7 +19,11 @@ const UserList = () => {
const { t } = useTranslation();
const [userList, setUserList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
const [isModal, setIsModal] = useState(false);
const [isModal, setIsModal] = useState({
form: false,
addseats: false,
options: false
});
const location = useLocation();
const isDashboard =
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
@@ -27,9 +31,16 @@ const UserList = () => {
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isActiveModal, setIsActiveModal] = 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 [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 startIndex = (currentPage - 1) * recordperPage; // user per page
@@ -81,7 +92,6 @@ const UserList = () => {
pages.push(lastPageIndex);
}
}
return pages;
};
const pageNumbers = getPaginationRange();
@@ -96,13 +106,43 @@ const UserList = () => {
async function fetchUserList() {
try {
setIsLoader(true);
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (isEnableSubscription) {
const subscribe = await checkIsSubscribed();
setIsSubscribe(subscribe);
const subscribe = await fetchSubscriptionInfo();
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 {
setIsSubscribe({ plan: "teams-yearly", isValid: true });
}
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (extUser) {
const admin =
extUser?.UserRole &&
@@ -121,14 +161,12 @@ const UserList = () => {
console.log("Err in fetch userlist", err);
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
} finally {
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
}, 1500);
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
setIsLoader(false);
}
}
const handleFormModal = () => {
setIsModal(!isModal);
const handleModal = (modalName) => {
setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
};
// Change page
@@ -146,7 +184,13 @@ const UserList = () => {
};
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
// if data is of array type then it will join array items with ","
@@ -162,9 +206,8 @@ const UserList = () => {
return "-";
}
};
const handleClose = () => {
setIsActiveModal({});
};
const handleClose = () => setIsActiveModal({});
const handleToggleSubmit = async (user) => {
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
if (index !== -1) {
@@ -196,6 +239,49 @@ const UserList = () => {
const handleToggleBtn = (user) => {
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 (
<div className="relative">
<Title title={isAdmin ? "Users" : "Page not found"} />
@@ -205,7 +291,7 @@ const UserList = () => {
</div>
)}
{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 />
</div>
)}
@@ -216,19 +302,46 @@ const UserList = () => {
{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="font-light">
{t("report-name.Users")}
{t("report-name.Users")}{" "}
<span className="text-xs md:text-[13px] font-normal">
<Tooltip message={t("users-from-teams")} />
</span>
</div>
<div
className="cursor-pointer"
onClick={() => handleFormModal()}
>
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
<div className="flex flex-row gap-2 items-center">
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
<div
className="hidden md:flex op-btn op-btn-sm h-[35px] op-btn-primary op-btn-outline text-xs mb-0.5"
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 className={` overflow-x-auto w-full`}>
<div className="overflow-x-auto w-full">
<table className="op-table border-collapse w-full">
<thead className="text-[14px]">
<tr className="border-y-[1px]">
@@ -313,34 +426,42 @@ const UserList = () => {
</tbody>
</table>
</div>
<div className="op-join flex flex-wrap items-center p-2">
{userList.length > recordperPage && (
<button
onClick={() => paginateBack()}
className="op-join-item op-btn op-btn-sm"
>
{t("prev")}
</button>
)}
{pageNumbers.map((x, i) => (
<button
key={i}
onClick={() => setCurrentPage(x)}
disabled={x === "..."}
className={`${
x === currentPage ? "op-btn-active" : ""
} op-join-item op-btn op-btn-sm`}
>
{x}
</button>
))}
{userList.length > recordperPage && (
<button
onClick={() => paginateFront()}
className="op-join-item op-btn op-btn-sm"
>
{t("next")}
</button>
<div className="flex flex-row justify-between items-center text-xs font-medium">
<div className="op-join flex flex-wrap items-center p-2">
{userList.length > recordperPage && (
<button
onClick={() => paginateBack()}
className="op-join-item op-btn op-btn-sm"
>
{t("prev")}
</button>
)}
{pageNumbers.map((x, i) => (
<button
key={i}
onClick={() => setCurrentPage(x)}
disabled={x === "..."}
className={`${
x === currentPage ? "op-btn-active" : ""
} op-join-item op-btn op-btn-sm`}
>
{x}
</button>
))}
{userList.length > recordperPage && (
<button
onClick={() => paginateFront()}
className="op-join-item op-btn op-btn-sm"
>
{t("next")}
</button>
)}
</div>
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
<div>
{t("available-seats")}: {usersCount.allowed}/
{usersCount.totalAllowed}
</div>
)}
</div>
{userList?.length <= 0 && (
@@ -362,17 +483,60 @@ const UserList = () => {
</div>
)}
<ModalUi
isOpen={isModal}
isOpen={isModal.form}
title={formHeader}
handleClose={handleFormModal}
handleClose={() => handleModal("form")}
>
<AddUser
setIsAlert={setIsAlert}
handleUserData={handleUserData}
closePopup={handleFormModal}
handleBuyUsers={handleBuyUsers}
closePopup={() => handleModal("form")}
setFormHeader={setFormHeader}
/>
</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 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,
SendinOrder: Doc?.SendinOrder || false,
AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
IsEnableOTP: Doc?.IsEnableOTP || false
};
try {
const res = await axios.post(
@@ -515,7 +516,6 @@ const ReportTable = (props) => {
.then(async (result) => {
const res = result.data;
if (res) {
setReason("");
setActLoader({});
setIsAlert(true);
setAlertMsg({
@@ -527,7 +527,43 @@ const ReportTable = (props) => {
(x) => x.objectId !== item.objectId
);
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) => {
console.log("err", err);
@@ -41,8 +41,8 @@ function CustomModal(props) {
className="op-btn op-btn-primary mr-2 px-6"
type="button"
onClick={() => {
setReason("");
props.declineDoc(reason);
setReason("");
}}
>
{t("yes")}
@@ -41,7 +41,7 @@
"upgrade-now": "Upgrade now",
"upgrade-to": "Upgrade to",
"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.",
"user-name-limit-char": "To have a username less than 8 character please subscribe",
"tour-content": "Don't show this again",
@@ -614,25 +614,35 @@
"select-date-format": "Select a date format",
"quantity-of-credits": "Quantity of premium credits",
"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",
"quota-err-quicksend": "Quota Reached, You don't have enough credits.",
"buy-credits": "Buy Premium Credits",
"rotate-right":"Rotate right",
"rotate-left":"Rotate left",
"rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?",
"templateid":"Template-Id",
"bulk-send-subcription-alert":"Please upgrade to Professional or Team plan to use bulk send.",
"generate-test-token":"Generate 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-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",
"rotate-right": "Rotate right",
"rotate-left": "Rotate left",
"rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?",
"templateid": "Template-Id",
"bulk-send-subcription-alert": "Please upgrade to Professional or Team plan to use bulk send.",
"generate-test-token": "Generate 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-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": "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-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head":"Quota Reached",
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminName}}<{{adminEmail}}>.",
"sent-this-month":"Sent this month"
"quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head": "Quota Reached",
"unauthorized-modal": "You don't have permission to perform this action, please contact {{adminEmail}}.",
"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",
"pro": "PRO",
"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.",
"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",
@@ -611,28 +611,37 @@
"Add-seats": "Ajouter des sièges",
"format": "format",
"select-date-format": "Sélectionnez un format de date",
"quantity-of-credits":"Quantité de crédits de prime",
"remaining-credits":"Crédits premium disponibles :",
"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.",
"quantity-of-credits": "Quantité de crédits de prime",
"remaining-credits": "Crédits premium disponibles :",
"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.",
"quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.",
"buy-credits": "Acheter des crédits premium",
"rotate-right" :"Faire pivoter à droite",
"rotate-left" :"Faire pivoter à gauche",
"rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?",
"templateid":"ID de modèle",
"bulk-send-subcription-alert":"Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.",
"rotate-right": "Faire pivoter à droite",
"rotate-left": "Faire pivoter à gauche",
"rotate-alert-mssg": "Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?",
"templateid": "ID de modèle",
"bulk-send-subcription-alert": "Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.",
"generate-test-token": "Générer 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-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",
"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-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": "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-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",
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminName}}<{{adminEmail}}>.",
"sent-this-month":"envoyé ce mois-ci"
"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",
"unauthorized-modal": "Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
"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) => {
//checking server url and save file's size
try {
const tenantQuery = new Parse.Query('partners_Tenant');
tenantQuery.equalTo('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
const tenant = await tenantQuery.first();
if (tenant) {
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
try {
const tenantCredits = new Parse.Query('partners_TenantCredits');
tenantCredits.equalTo('PartnersTenant', tenantPtr);
const res = await tenantCredits.first({ useMasterKey: true });
if (res) {
const response = JSON.parse(JSON.stringify(res));
const usedStorage = response?.usedStorage ? response.usedStorage + size : size;
const updateCredit = new Parse.Object('partners_TenantCredits');
updateCredit.id = res.id;
updateCredit.set('usedStorage', usedStorage);
await updateCredit.save(null, { useMasterKey: true });
} else {
const newCredit = new Parse.Object('partners_TenantCredits');
newCredit.set('usedStorage', size);
newCredit.set('PartnersTenant', tenantPtr);
await newCredit.save(null, { useMasterKey: true });
if (userId) {
const tenantQuery = new Parse.Query('partners_Tenant');
tenantQuery.equalTo('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
const tenant = await tenantQuery.first();
if (tenant) {
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
try {
const tenantCredits = new Parse.Query('partners_TenantCredits');
tenantCredits.equalTo('PartnersTenant', tenantPtr);
const res = await tenantCredits.first({ useMasterKey: true });
if (res) {
const response = JSON.parse(JSON.stringify(res));
const usedStorage = response?.usedStorage ? response.usedStorage + size : size;
const updateCredit = new Parse.Object('partners_TenantCredits');
updateCredit.id = res.id;
updateCredit.set('usedStorage', usedStorage);
await updateCredit.save(null, { useMasterKey: true });
} else {
const newCredit = new Parse.Object('partners_TenantCredits');
newCredit.set('usedStorage', size);
newCredit.set('PartnersTenant', tenantPtr);
await newCredit.save(null, { useMasterKey: true });
}
} catch (err) {
console.log('err in save usage', err);
}
} catch (err) {
console.log('err in save usage', err);
saveDataFile(size, fileUrl, tenantPtr);
}
saveDataFile(size, fileUrl, tenantPtr);
}
} catch (err) {
console.log('err in fetch tenant Id', err);
@@ -196,6 +196,9 @@ export default async function createDocumentWithTemplate(request, response) {
if (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('ExtUserPtr', {
__type: 'Pointer',
@@ -63,6 +63,7 @@ export default async function createDocumentwithCoordinate(request, response) {
const email_body = request.body.email_body;
const sendInOrder = request.body.sendInOrder || false;
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
const IsEnableOTP = request.body?.enableOTP === true ? true : false;
// console.log('fileData ', fileData);
const protocol = customAPIurl();
const baseUrl = new URL(process.env.PUBLIC_URL);
@@ -162,6 +163,7 @@ export default async function createDocumentwithCoordinate(request, response) {
if (TimeToCompleteDays) {
object.set('TimeToCompleteDays', TimeToCompleteDays);
}
object.set('IsEnableOTP', IsEnableOTP);
object.set('IsSendMail', send_email);
let contact = [];
if (signers && signers.length > 0) {
@@ -9,6 +9,7 @@ export default async function createTemplate(request, response) {
const SendinOrder = request.body.sendInOrder || false;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const baseUrl = new URL(process.env.PUBLIC_URL);
const isEnableOTP = request.body?.enableOTP === true ? true : false;
try {
const reqToken = request.headers['x-api-token'];
@@ -65,6 +66,7 @@ export default async function createTemplate(request, response) {
object.set('URL', fileUrl);
object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr);
object.set('IsEnableOTP', isEnableOTP);
if (SendinOrder) {
object.set('SendinOrder', SendinOrder);
}
@@ -17,6 +17,8 @@ export default async function createTemplatewithCoordinate(request, response) {
const base64File = request.body.file;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const SendinOrder = request.body.sendInOrder || false;
const isEnableOTP = request.body?.enableOTP === true ? true : false;
// console.log('fileData ', fileData);
const protocol = customAPIurl();
@@ -80,6 +82,7 @@ export default async function createTemplatewithCoordinate(request, response) {
object.set('URL', fileUrl);
object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr);
object.set('IsEnableOTP', isEnableOTP);
let contact = [];
if (signers && signers.length > 0) {
let parseSigners;
@@ -12,6 +12,8 @@ export default async function draftDocument(request, response) {
const send_email = request.body.send_email || true;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const SendinOrder = request.body.sendInOrder || false;
const isEnableOTP = request.body?.enableOTP === true ? true : false;
// console.log('fileData ', fileData);
const protocol = customAPIurl();
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('ExtUserPtr', extUserPtr);
object.set('IsSendMail', send_email);
object.set('IsEnableOTP', isEnableOTP);
if (signers && signers.length > 0) {
let parseSigners;
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 })) ||
[],
sendInOrder: document?.SendinOrder || false,
enableOTP: document?.IsEnableOTP || false,
createdAt: document.createdAt,
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 })) ||
[],
sendInOrder: x?.SendinOrder || false,
enableOTP: x?.IsEnableOTP || false,
createdAt: x.createdAt,
updatedAt: x.updatedAt,
}));
@@ -61,6 +61,7 @@ export default async function getTemplate(request, response) {
),
})) || [],
sendInOrder: template?.SendinOrder || false,
enableOTP: template?.IsEnableOTP || false,
createdAt: template.createdAt,
updatedAt: template.updatedAt,
});
@@ -88,6 +88,7 @@ export default async function getTemplatetList(request, response) {
),
})) || [],
sendInOrder: template?.SendinOrder || false,
enableOTP: template?.IsEnableOTP || false,
createdAt: template.createdAt,
updatedAt: template.updatedAt,
}));
@@ -10,7 +10,7 @@ export default async function updateDocument(request, response) {
const token = await tokenQuery.first({ useMasterKey: true });
if (token !== undefined) {
// Valid Token then proceed request
const allowedKeys = ['name', 'note', 'description', 'folderId'];
const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP'];
const objectKeys = Object.keys(request.body);
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
const parseUser = JSON.parse(JSON.stringify(token));
@@ -48,6 +48,10 @@ export default async function updateDocument(request, response) {
objectId: request?.body?.folderId,
});
}
if (request.body?.enableOTP) {
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
}
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
if (updatedRes) {
if (request.posthog) {
@@ -10,7 +10,7 @@ export default async function updateTemplate(request, response) {
const token = await tokenQuery.first({ useMasterKey: true });
if (token !== undefined) {
// Valid Token then proceed request
const allowedKeys = ['name', 'note', 'description', 'folderId'];
const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP'];
const objectKeys = Object.keys(request.body);
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
const parseUser = JSON.parse(JSON.stringify(token));
@@ -48,6 +48,9 @@ export default async function updateTemplate(request, response) {
objectId: request?.body?.folderId,
});
}
if (request.body?.enableOTP) {
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
}
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
if (updatedRes) {
if (request.posthog) {
+6
View File
@@ -65,6 +65,9 @@ import ExtUserAftersave from './parsefunction/ExtUserAftersave.js';
import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js';
import AllowedCredits from './parsefunction/AllowedCredits.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.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
@@ -142,3 +145,6 @@ Parse.Cloud.define('allowedusers', AllowedUsers);
Parse.Cloud.define('buyaddonusers', BuyAddonUsers);
Parse.Cloud.define('allowedcredits', AllowedCredits);
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('ExtUserPtr', template?.ExtUserPtr);
object.set('OriginIp', template?.OriginIp || '');
object.set('IsEnableOTP', template?.IsEnableOTP || false);
let signers = template?.Signers || [];
const signerobj = {
__type: 'Pointer',
@@ -7,99 +7,101 @@ export default async function callWebhook(request) {
const contactId = request.params.contactId;
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const appId = process.env.APP_ID;
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
if (event === 'viewed' && contactId) {
const docQuery = new Parse.Query('contracts_Document');
const res = await docQuery.get(docId, { useMasterKey: true });
if (res) {
const _res = res.toJSON();
const userPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: contactId,
};
const date = new Date().toISOString();
const obj = {
UserPtr: userPtr,
SignedUrl: _res.SignedUrl,
Activity: 'Viewed',
ipAddress: request.headers['x-real-ip'],
ViewedOn: date,
};
const isUserExist = _res?.AuditTrail?.some(
x => x.UserPtr.objectId === contactId && x?.ViewedOn
);
if (!isUserExist) {
const updateDoc = new Parse.Object('contracts_Document');
updateDoc.id = res.id;
if (_res?.AuditTrail && _res?.AuditTrail?.length > 0) {
updateDoc.set('AuditTrail', [..._res?.AuditTrail, obj]);
} else {
updateDoc.set('AuditTrail', [obj]);
try {
const docQuery = new Parse.Query('contracts_Document');
const docRes = await docQuery.get(docId, { useMasterKey: true });
const isEnableOTP = docRes?.get('IsEnableOTP') || false;
let userId;
if (isEnableOTP) {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
userId = userRes.data && userRes.data.objectId;
}
if (!isEnableOTP || userId) {
if (event === 'viewed' && contactId) {
if (docRes) {
const _docRes = docRes.toJSON();
const userPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: contactId,
};
const date = new Date().toISOString();
const obj = {
UserPtr: userPtr,
SignedUrl: _docRes.SignedUrl,
Activity: 'Viewed',
ipAddress: request.headers['x-real-ip'],
ViewedOn: date,
};
const isUserExist = _docRes?.AuditTrail?.some(
x => x.UserPtr.objectId === contactId && x?.ViewedOn
);
if (!isUserExist) {
const updateDoc = new Parse.Object('contracts_Document');
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 docQuery = new Parse.Query('contracts_Document');
const resDoc = await docQuery.get(docId, { useMasterKey: true });
const extendcls = new Parse.Query('contracts_Users');
extendcls.equalTo('objectId', resDoc.get('ExtUserPtr')?.id);
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
const res = await extendcls.first({ useMasterKey: true });
if (res) {
const extUser = JSON.parse(JSON.stringify(res));
if (extUser?.Webhook) {
const params = {
event: event,
...body,
};
await axios
.post(extUser?.Webhook, params, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
try {
// console.log('res ', res);
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err.message);
}
})
.catch(err => {
console.log('Err send data to webhook', err.message);
try {
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', err?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err.message);
}
});
const extendcls = new Parse.Query('contracts_Users');
extendcls.equalTo('objectId', docRes.get('ExtUserPtr')?.id);
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
const resExt = await extendcls.first({ useMasterKey: true });
if (resExt) {
const extUser = JSON.parse(JSON.stringify(resExt));
if (extUser?.Webhook) {
const params = { event: event, ...body };
await axios
.post(extUser?.Webhook, params, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
try {
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err.message);
}
})
.catch(err => {
console.log('Err send data to webhook', err.message);
try {
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', err?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err.message);
}
});
}
return { message: 'webhook called!' };
}
return { message: 'webhook called!' };
} else {
return { message: 'User not found!' };
}
} else {
return { message: 'User not found!' };
} catch (err) {
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,
OriginIp: Ip,
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;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (docId && userId) {
if (docId) {
try {
const query = new Parse.Query('contracts_Document');
query.equalTo('objectId', docId);
@@ -26,11 +19,32 @@ export default async function getDocument(request) {
query.notEqualTo('IsArchive', true);
const res = await query.first({ useMasterKey: true });
if (res) {
const acl = res.getACL();
if (acl && acl.getReadAccess(userId)) {
const IsEnableOTP = res?.get('IsEnableOTP') || false;
if (!IsEnableOTP) {
return res;
} 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 {
return { error: "You don't have access of this document!" };
@@ -28,15 +28,42 @@ export default function getPresignedUrl(url) {
export async function getSignedUrl(request) {
try {
const docId = request.params.docId || '';
const url = request.params.url;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
if (docId) {
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 {
if (useLocal !== 'true') {
const presignedUrl = getPresignedUrl(url);
return presignedUrl;
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
} else {
return url;
if (useLocal !== 'true') {
const presignedUrl = getPresignedUrl(url);
return presignedUrl;
} else {
return url;
}
}
}
} catch (err) {
@@ -50,37 +50,24 @@ export default async function getSubscription(request) {
}
} else if (contactId) {
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const contactCls = new Parse.Query('contracts_Contactbook');
const contactUser = await contactCls.get(contactId, { useMasterKey: true });
if (contactUser) {
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
subscriptionCls.equalTo('TenantId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: contactUser.get('TenantId').id,
});
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 } };
}
const contactCls = new Parse.Query('contracts_Contactbook');
const contactUser = await contactCls.get(contactId, { useMasterKey: true });
if (contactUser) {
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
subscriptionCls.equalTo('TenantId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: contactUser.get('TenantId').id,
});
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 } };
}
@@ -88,10 +75,10 @@ export default async function getSubscription(request) {
return { status: 'success', result: { isSubscribed: false } };
}
} else {
return { status: 'error', result: 'User not found!' };
return { status: 'success', result: { isSubscribed: false } };
}
} else {
return { status: 'error', result: 'Invalid session token!' };
return { status: 'error', result: 'User not found!' };
}
} catch (err) {
console.log('Err in get subscription2', err.message);
@@ -12,6 +12,8 @@ async function getUserDetails(request) {
}
userQuery.include('TenantId');
userQuery.include('UserId');
userQuery.include('CreatedBy');
userQuery.exclude('CreatedBy.authData');
userQuery.exclude('google_refresh_token');
if (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 company = docDetails?.ExtUserPtr?.Company || '';
const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt;
const IsEnableOTP = docDetails?.IsEnableOTP || false;
const auditTrail =
docDetails?.Signers?.length > 0
? docDetails.AuditTrail.map(x => {
@@ -348,22 +349,22 @@ export default async function GenerateCertificate(docDetails) {
font: timesRomanFont,
color: textValueColor,
});
page.drawText('Security level :', {
x: half + 55,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
page.drawText(`Email, OTP Auth`, {
x: half + 125,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
if (IsEnableOTP) {
page.drawText('Security level :', {
x: half + 55,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
page.drawText('Email, OTP Auth', {
x: half + 125,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
}
page.drawText('Signature :', {
x: 30,
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
async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
try {
const UserPtr = {
__type: 'Pointer',
className: className,
objectId: userId,
};
const UserPtr = { __type: 'Pointer', className: className, objectId: userId };
const obj = {
UserPtr: UserPtr,
SignedUrl: url,
@@ -66,11 +62,7 @@ async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
} else {
isCompleted = true;
}
const body = {
SignedUrl: url,
AuditTrail: updateAuditTrail,
IsCompleted: isCompleted,
};
const body = { SignedUrl: url, AuditTrail: updateAuditTrail, IsCompleted: isCompleted };
const signedRes = await axios.put(serverUrl + '/classes/contracts_Document/' + docId, body, {
headers: {
'Content-Type': 'application/json',
@@ -164,29 +156,16 @@ async function sendCompletedMail(obj) {
'X-Parse-Master-Key': masterKEY,
},
});
// console.log('Res ', res);
}
// `sendDoctoWebhook` is used to send res data of document on webhook
async function sendDoctoWebhook(doc, Url, event, signUser, certificateUrl) {
let signers = [];
if (signUser) {
signers = {
name: signUser?.Name,
email: signUser?.Email,
phone: signUser?.Phone,
};
signers = { name: signUser?.Name, email: signUser?.Email, phone: signUser?.Phone };
} else {
signers = doc?.Signers?.map(x => ({
name: x.Name,
email: x.Email,
phone: x.Phone,
})) || [
{
name: doc?.ExtUserPtr?.Name,
email: doc?.ExtUserPtr?.Email,
phone: doc?.ExtUserPtr?.Phone,
},
signers = doc?.Signers?.map(x => ({ name: x.Name, 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 => {
try {
// console.log('res ', res);
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status);
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('res ', res.data);
}
}
@@ -281,15 +258,9 @@ const sendMailsaveCertifcate = async (doc, P12Buffer, url, isCustomMail, mailPro
if (doc.IsSendMail === false) {
console.log("don't send mail");
} else {
const mailObj = {
url: url,
isCustomMail: isCustomMail,
doc: doc,
mailProvider: mailProvider,
};
const mailObj = { url: url, isCustomMail: isCustomMail, doc: doc, mailProvider: mailProvider };
sendCompletedMail(mailObj);
}
saveFileUsage(CertificateBuffer.length, file.imageUrl, userId);
sendDoctoWebhook(doc, url, 'completed', '', file.imageUrl);
};
@@ -301,169 +272,160 @@ const sendMailsaveCertifcate = async (doc, P12Buffer, url, isCustomMail, mailPro
*/
async function PDF(req) {
try {
if (!req?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
const userIP = req.headers['x-real-ip']; // client IPaddress
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 {
const password = '';
const authUser = req?.user?.toJSON();
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();
className = 'contracts_Users';
signUser = _resDoc.ExtUserPtr;
}
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';
}
const username = signUser.Name;
const userEmail = signUser.Email;
if (req.params.pdfFile) {
// `PdfBuffer` used to create buffer from pdf file
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: userIP };
let updateAuditTrail;
if (_resDoc.AuditTrail && _resDoc.AuditTrail.length > 0) {
updateAuditTrail = [..._resDoc.AuditTrail, obj];
} else {
className = 'contracts_Users';
signUser = _resDoc.ExtUserPtr;
updateAuditTrail = [obj];
}
const username = signUser.Name;
const userEmail = signUser.Email;
if (req.params.pdfFile) {
// `PdfBuffer` used to create buffer from pdf file
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 {
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;
}
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 {
const error = new Error('Pdf file not present!');
error.code = 400; // Set the error code (e.g., 400 for bad request)
throw error;
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
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) {
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",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.20.0",
"express": "^4.21.0",
"form-data": "^4.0.0",
"generate-api-key": "^1.0.2",
"googleapis": "^140.0.1",
"jsonschema": "^1.4.1",
"mailgun.js": "^10.2.3",
"mongoose": "^8.6.0",
"mongoose": "^8.6.1",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
"node-forge": "^1.3.1",
"nodemailer": "^6.9.14",
"nodemailer": "^6.9.15",
"parse": "^5.3.0",
"parse-dbtool": "^1.2.0",
"parse-server": "^7.2.0",
@@ -41,7 +41,7 @@
"devDependencies": {
"@babel/eslint-parser": "^7.25.1",
"eslint": "^9.9.1",
"jasmine": "^5.2.0",
"jasmine": "^5.3.0",
"mongodb-runner": "^5.6.6",
"nodemon": "^3.1.4",
"nyc": "^17.0.0",
@@ -1770,11 +1770,12 @@
}
},
"node_modules/@google-cloud/firestore": {
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.9.0.tgz",
"integrity": "sha512-c4ALHT3G08rV7Zwv8Z2KG63gZh66iKdhCBeDfCpIkLrjX6EAjTD/szMdj14M+FnQuClZLFfW5bAgoOjfNmLtJg==",
"version": "7.10.0",
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.10.0.tgz",
"integrity": "sha512-VFNhdHvfnmqcHHs6YhmSNHHxQqaaD64GwiL0c+e1qz85S8SWZPC2XFRf8p9yHRTF40Kow424s1KBU9f0fdQa+Q==",
"optional": true,
"dependencies": {
"@opentelemetry/api": "^1.3.0",
"fast-deep-equal": "^3.1.1",
"functional-red-black-tree": "^1.0.1",
"google-gax": "^4.3.3",
@@ -1866,9 +1867,9 @@
}
},
"node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": {
"version": "10.5.2",
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.2.tgz",
"integrity": "sha512-VZpw7wxwmQGcCGt8epw6fDb8LkoySbTJ/MU565ibKivPqCkH96XK36Et/N0RlRCYGN6QAXn5UIaSbOYYHrnpAA==",
"version": "10.5.4",
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz",
"integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==",
"dependencies": {
"@graphql-typed-document-node/core": "^3.1.1",
"cross-inspect": "1.0.1",
@@ -1900,9 +1901,9 @@
}
},
"node_modules/@graphql-tools/schema/node_modules/@graphql-tools/utils": {
"version": "10.5.2",
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.2.tgz",
"integrity": "sha512-VZpw7wxwmQGcCGt8epw6fDb8LkoySbTJ/MU565ibKivPqCkH96XK36Et/N0RlRCYGN6QAXn5UIaSbOYYHrnpAA==",
"version": "10.5.4",
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.4.tgz",
"integrity": "sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ==",
"dependencies": {
"@graphql-typed-document-node/core": "^3.1.1",
"cross-inspect": "1.0.1",
@@ -1936,9 +1937,9 @@
}
},
"node_modules/@grpc/grpc-js": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.1.tgz",
"integrity": "sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw==",
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.11.2.tgz",
"integrity": "sha512-DWp92gDD7/Qkj7r8kus6/HCINeo3yPZWZ3paKgDgsbKbSpoxKg1yvN8xe2Q8uE3zOsPe3bX8FQX2+XValq2yTw==",
"optional": true,
"dependencies": {
"@grpc/proto-loader": "^0.7.13",
@@ -2625,6 +2626,15 @@
"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": {
"version": "3.0.0",
"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=="
},
"node_modules/@types/node": {
"version": "22.2.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz",
"integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==",
"version": "22.5.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
"dependencies": {
"undici-types": "~6.13.0"
"undici-types": "~6.19.2"
}
},
"node_modules/@types/node-fetch": {
@@ -3793,9 +3803,9 @@
"integrity": "sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw=="
},
"node_modules/@types/qs": {
"version": "6.9.15",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg=="
"version": "6.9.16",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
"integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A=="
},
"node_modules/@types/range-parser": {
"version": "1.2.7",
@@ -4157,9 +4167,9 @@
}
},
"node_modules/aws4": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz",
"integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA=="
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
"integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="
},
"node_modules/axios": {
"version": "1.7.7",
@@ -4270,9 +4280,9 @@
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"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==",
"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",
@@ -4282,7 +4292,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -4305,6 +4315,20 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"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": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz",
@@ -5201,9 +5225,9 @@
}
},
"node_modules/dset": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz",
"integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==",
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
"integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
"engines": {
"node": ">=4"
}
@@ -5746,9 +5770,9 @@
}
},
"node_modules/express": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz",
"integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -5762,7 +5786,7 @@
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.3",
@@ -5771,11 +5795,11 @@
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -5797,43 +5821,6 @@
"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": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -5850,11 +5837,42 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"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": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
@@ -6125,11 +6143,11 @@
}
},
"node_modules/firebase-admin/node_modules/@types/node": {
"version": "20.14.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
"integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==",
"version": "20.16.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
"dependencies": {
"undici-types": "~5.26.4"
"undici-types": "~6.19.2"
}
},
"node_modules/firebase-admin/node_modules/long": {
@@ -6137,11 +6155,6 @@
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
"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": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
@@ -6583,9 +6596,9 @@
}
},
"node_modules/google-gax": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.3.9.tgz",
"integrity": "sha512-tcjQr7sXVGMdlvcG25wSv98ap1dtF4Z6mcV0rztGIddOcezw4YMb/uTXg72JPrLep+kXcVjaJjg6oo3KLf4itQ==",
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz",
"integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==",
"optional": true,
"dependencies": {
"@grpc/grpc-js": "^1.10.9",
@@ -7426,22 +7439,22 @@
}
},
"node_modules/jasmine": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.2.0.tgz",
"integrity": "sha512-il+noV96N1BGU9/FMmc8QtAMxC8lPnXUiAvgb0o9MDZATRdxglTQe9wo6UdL049ropQL6MopDYwDlludKR6wJQ==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.3.0.tgz",
"integrity": "sha512-Vrv5VWTXVZ/5xcNawlYCmE24pOaZu3KduLr9iAaENoMJ8W8Ryvhfpw2cf3rI4Unc2ajvu2t4tCKjS72TnraBGQ==",
"dev": true,
"dependencies": {
"glob": "^10.2.2",
"jasmine-core": "~5.2.0"
"jasmine-core": "~5.3.0"
},
"bin": {
"jasmine": "bin/jasmine.js"
}
},
"node_modules/jasmine-core": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.2.0.tgz",
"integrity": "sha512-tSAtdrvWybZkQmmaIoDgnvHG8ORUNw5kEVlO5CvrXj02Jjr9TZrmjFq7FUiOUzJiOP2wLGYT6PgrQgQF4R1xiw==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz",
"integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==",
"dev": true
},
"node_modules/jmespath": {
@@ -7828,9 +7841,9 @@
}
},
"node_modules/loglevel": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
"integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
"integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
"engines": {
"node": ">= 0.6.0"
},
@@ -8276,9 +8289,9 @@
}
},
"node_modules/mongoose": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.0.tgz",
"integrity": "sha512-p6VSbYKvD4ZIabqo8C0kS5eKX1Xpji+opTAIJ9wyuPJ8Y/FblgXSMnFRXnB40bYZLKPQT089K5KU8+bqIXtFdw==",
"version": "8.6.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.1.tgz",
"integrity": "sha512-dppGcYqvsdg+VcnqXR5b467V4a+iNhmvkfYNpEPi6AjaUxnz6ioEDmrMLOi+sOWjvoHapuwPOigV4f2l7HC6ag==",
"dependencies": {
"bson": "^6.7.0",
"kareem": "2.6.3",
@@ -8501,9 +8514,9 @@
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node_modules/node-abi": {
"version": "3.65.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
"integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
"version": "3.67.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz",
"integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==",
"dependencies": {
"semver": "^7.3.5"
},
@@ -8596,9 +8609,9 @@
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g=="
},
"node_modules/nodemailer": {
"version": "6.9.14",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz",
"integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==",
"version": "6.9.15",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.15.tgz",
"integrity": "sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==",
"engines": {
"node": ">=6.0.0"
}
@@ -9397,6 +9410,42 @@
"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": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz",
@@ -10400,9 +10449,9 @@
}
},
"node_modules/protobufjs": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz",
"integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==",
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
"integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
@@ -10458,9 +10507,9 @@
"dev": true
},
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
@@ -10932,69 +10981,25 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serve-static": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz",
"integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": {
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
"send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/serve-static/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/serve-static/node_modules/debug/node_modules/ms": {
"node_modules/serve-static/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"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"
},
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">=4"
}
},
"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": ">= 0.8"
}
},
"node_modules/set-blocking": {
@@ -11997,9 +12002,9 @@
"dev": true
},
"node_modules/undici-types": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz",
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg=="
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"node_modules/unpipe": {
"version": "1.0.0",
+4 -4
View File
@@ -28,17 +28,17 @@
"axios": "^1.7.7",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.20.0",
"express": "^4.21.0",
"form-data": "^4.0.0",
"generate-api-key": "^1.0.2",
"googleapis": "^140.0.1",
"jsonschema": "^1.4.1",
"mailgun.js": "^10.2.3",
"mongoose": "^8.6.0",
"mongoose": "^8.6.1",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
"node-forge": "^1.3.1",
"nodemailer": "^6.9.14",
"nodemailer": "^6.9.15",
"parse": "^5.3.0",
"parse-dbtool": "^1.2.0",
"parse-server": "^7.2.0",
@@ -51,7 +51,7 @@
"devDependencies": {
"@babel/eslint-parser": "^7.25.1",
"eslint": "^9.9.1",
"jasmine": "^5.2.0",
"jasmine": "^5.3.0",
"mongodb-runner": "^5.6.6",
"nodemon": "^3.1.4",
"nyc": "^17.0.0",