Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9aaf4309e | |||
| 80fa1085d2 | |||
| 88195291fd | |||
| 39ad600d00 | |||
| c63a3aba6b | |||
| 782ecbe307 | |||
| f75bbfa048 | |||
| 3a772cc983 | |||
| 807113523e | |||
| 7df2af8611 | |||
| 10c1697b00 | |||
| 742e5d38ab | |||
| 1d3e7f8af0 | |||
| c99bacab64 | |||
| 95d7555ebc | |||
| 5854e0a23c | |||
| 81f7f32767 | |||
| c0374a7da1 | |||
| ed65e655b9 | |||
| d250e516b5 | |||
| e4f404b2c7 | |||
| 86571331f8 | |||
| 163d420af9 | |||
| 4925ea4af0 | |||
| 57b05ce348 | |||
| 427b53fcbd | |||
| 2ac7a31be6 | |||
| 4baed6409f | |||
| 2ea0ff0965 | |||
| 88b9a7edce | |||
| 538066b960 | |||
| b10dd1d75a | |||
| f743580b55 | |||
| 0688467302 | |||
| 29e972dbf2 | |||
| bd99697c5b | |||
| 1d5c431ff6 | |||
| 3736c510ff | |||
| 26c12c3a85 | |||
| 10bb08e5e6 | |||
| b50d5b6121 | |||
| 38b28752e1 | |||
| 87c51009de | |||
| a950a47b28 | |||
| 2609d10c0b | |||
| 7b4cb0f66c | |||
| 26db0e1e69 | |||
| 62e64cbd22 | |||
| 844a47830f | |||
| 2cc1e32f45 | |||
| 9890958b1e | |||
| 6dbd6d6edc | |||
| bf7a4dfd28 | |||
| f52626bda0 | |||
| 88cec4bf2b | |||
| b880def108 | |||
| bfd5dc039a | |||
| c0d236dff3 | |||
| 743d5fc306 | |||
| 2f51516163 | |||
| b606b46aa4 |
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.guides.bracketPairs": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||
"eslint.validate": ["javascript", "typescript", "vue"],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"i18n-ally.localesPaths": ["src/i18n"],
|
||||
"typescript.format.enable": true,
|
||||
"typescript.format.indentSwitchCase": false,
|
||||
"typescript.validate.enable": true,
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm install -g pnpm lerna
|
||||
RUN pnpm install
|
||||
RUN lerna run build
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.0.18](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.17...cooparser-ts@1.0.18) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.17](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.17-alpha.2...cooparser-ts@1.0.17) (2024-07-25)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pkg-placeholder",
|
||||
"version": "1.0.17",
|
||||
"version": "1.0.20-alpha.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pkg-placeholder",
|
||||
"version": "1.0.17",
|
||||
"version": "1.0.20-alpha.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^2.16.0",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "cooparser-ts",
|
||||
"type": "module",
|
||||
"version": "1.0.17",
|
||||
"private": true,
|
||||
"version": "1.0.20-alpha.0",
|
||||
"private": false,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "",
|
||||
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
||||
|
||||
Generated
+19
-225
@@ -69,9 +69,6 @@ importers:
|
||||
esno:
|
||||
specifier: ^4.7.0
|
||||
version: 4.7.0
|
||||
lint-staged:
|
||||
specifier: ^15.2.2
|
||||
version: 15.2.2
|
||||
nodemon:
|
||||
specifier: ^3.1.4
|
||||
version: 3.1.4
|
||||
@@ -1039,10 +1036,6 @@ packages:
|
||||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
ansi-escapes@6.2.1:
|
||||
resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1233,14 +1226,6 @@ packages:
|
||||
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1271,9 +1256,6 @@ packages:
|
||||
colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
|
||||
colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
|
||||
colorspace@1.1.4:
|
||||
resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
|
||||
|
||||
@@ -1281,10 +1263,6 @@ packages:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
commander@11.1.0:
|
||||
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
commander@7.2.0:
|
||||
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -1506,9 +1484,6 @@ packages:
|
||||
elliptic@6.5.4:
|
||||
resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==}
|
||||
|
||||
emoji-regex@10.3.0:
|
||||
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
@@ -1770,9 +1745,6 @@ packages:
|
||||
eventemitter3@4.0.7:
|
||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||
|
||||
eventemitter3@5.0.1:
|
||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||
|
||||
execa@8.0.1:
|
||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||
engines: {node: '>=16.17'}
|
||||
@@ -1893,10 +1865,6 @@ packages:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
get-east-asian-width@1.2.0:
|
||||
resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
get-func-name@2.0.2:
|
||||
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
|
||||
|
||||
@@ -2083,14 +2051,6 @@ packages:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-fullwidth-code-point@4.0.0:
|
||||
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-fullwidth-code-point@5.0.0:
|
||||
resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2200,10 +2160,6 @@ packages:
|
||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
lilconfig@3.0.0:
|
||||
resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
lilconfig@3.1.1:
|
||||
resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -2211,15 +2167,6 @@ packages:
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
lint-staged@15.2.2:
|
||||
resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
hasBin: true
|
||||
|
||||
listr2@8.0.1:
|
||||
resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
local-pkg@0.5.0:
|
||||
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -2257,10 +2204,6 @@ packages:
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
log-update@6.0.0:
|
||||
resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
logform@2.6.0:
|
||||
resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -2346,10 +2289,6 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
mimic-fn@4.0.0:
|
||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -2546,10 +2485,6 @@ packages:
|
||||
one-time@1.0.0:
|
||||
resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
|
||||
|
||||
onetime@5.1.2:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
onetime@6.0.0:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -2682,11 +2617,6 @@ packages:
|
||||
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pidtree@0.6.0:
|
||||
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
|
||||
engines: {node: '>=0.10'}
|
||||
hasBin: true
|
||||
|
||||
pkg-types@1.1.0:
|
||||
resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==}
|
||||
|
||||
@@ -2976,17 +2906,10 @@ packages:
|
||||
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
||||
hasBin: true
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
reusify@1.0.4:
|
||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
rfdc@1.3.1:
|
||||
resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
|
||||
|
||||
rimraf@3.0.2:
|
||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||
hasBin: true
|
||||
@@ -3085,9 +3008,6 @@ packages:
|
||||
siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
|
||||
signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -3118,14 +3038,6 @@ packages:
|
||||
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
slice-ansi@7.1.0:
|
||||
resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
source-map-js@1.2.0:
|
||||
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3179,10 +3091,6 @@ packages:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
string-width@7.1.0:
|
||||
resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
string_decoder@1.3.0:
|
||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||
|
||||
@@ -3558,10 +3466,6 @@ packages:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
wrap-ansi@9.0.0:
|
||||
resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
@@ -3595,10 +3499,6 @@ packages:
|
||||
resolution: {integrity: sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
|
||||
yaml@2.3.4:
|
||||
resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
yaml@2.4.2:
|
||||
resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -3703,7 +3603,7 @@ snapshots:
|
||||
'@babel/traverse': 7.24.1
|
||||
'@babel/types': 7.24.0
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
@@ -3804,7 +3704,7 @@ snapshots:
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
'@babel/parser': 7.24.4
|
||||
'@babel/types': 7.24.0
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -4013,7 +3913,7 @@ snapshots:
|
||||
'@eslint/eslintrc@2.1.4':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
espree: 9.6.1
|
||||
globals: 13.24.0
|
||||
ignore: 5.3.1
|
||||
@@ -4029,7 +3929,7 @@ snapshots:
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -4348,7 +4248,7 @@ snapshots:
|
||||
'@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.7.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.1
|
||||
@@ -4366,7 +4266,7 @@ snapshots:
|
||||
'@typescript-eslint/types': 7.7.1
|
||||
'@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.7.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
optionalDependencies:
|
||||
typescript: 5.4.5
|
||||
@@ -4387,7 +4287,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
ts-api-utils: 1.3.0(typescript@5.4.5)
|
||||
optionalDependencies:
|
||||
@@ -4403,7 +4303,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 6.21.0
|
||||
'@typescript-eslint/visitor-keys': 6.21.0
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.3
|
||||
@@ -4418,7 +4318,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.7.1
|
||||
'@typescript-eslint/visitor-keys': 7.7.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.4
|
||||
@@ -4550,8 +4450,6 @@ snapshots:
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
ansi-escapes@6.2.1: {}
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.0.1: {}
|
||||
@@ -4762,15 +4660,6 @@ snapshots:
|
||||
dependencies:
|
||||
escape-string-regexp: 1.0.5
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
dependencies:
|
||||
restore-cursor: 4.0.0
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
dependencies:
|
||||
slice-ansi: 5.0.0
|
||||
string-width: 7.1.0
|
||||
|
||||
cliui@8.0.1:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
@@ -4803,8 +4692,6 @@ snapshots:
|
||||
|
||||
colord@2.9.3: {}
|
||||
|
||||
colorette@2.0.20: {}
|
||||
|
||||
colorspace@1.1.4:
|
||||
dependencies:
|
||||
color: 3.2.1
|
||||
@@ -4814,8 +4701,6 @@ snapshots:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
commander@11.1.0: {}
|
||||
|
||||
commander@7.2.0: {}
|
||||
|
||||
comment-parser@1.4.1: {}
|
||||
@@ -4952,10 +4837,6 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
debug@4.3.4:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
debug@4.3.4(supports-color@5.5.0):
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
@@ -5040,8 +4921,6 @@ snapshots:
|
||||
minimalistic-assert: 1.0.1
|
||||
minimalistic-crypto-utils: 1.0.1
|
||||
|
||||
emoji-regex@10.3.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
@@ -5185,7 +5064,7 @@ snapshots:
|
||||
eslint-plugin-import-x@0.5.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
doctrine: 3.0.0
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
@@ -5202,7 +5081,7 @@ snapshots:
|
||||
'@es-joy/jsdoccomment': 0.42.0
|
||||
are-docs-informative: 0.0.2
|
||||
comment-parser: 1.4.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint: 8.57.0
|
||||
esquery: 1.5.0
|
||||
@@ -5258,7 +5137,7 @@ snapshots:
|
||||
|
||||
eslint-plugin-toml@0.11.0(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
eslint-compat-utils: 0.5.0(eslint@8.57.0)
|
||||
lodash: 4.17.21
|
||||
@@ -5322,7 +5201,7 @@ snapshots:
|
||||
|
||||
eslint-plugin-yml@1.14.0(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
eslint-compat-utils: 0.5.0(eslint@8.57.0)
|
||||
lodash: 4.17.21
|
||||
@@ -5358,7 +5237,7 @@ snapshots:
|
||||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.3
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
doctrine: 3.0.0
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 7.2.2
|
||||
@@ -5420,8 +5299,6 @@ snapshots:
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
|
||||
eventemitter3@5.0.1: {}
|
||||
|
||||
execa@8.0.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
@@ -5587,8 +5464,6 @@ snapshots:
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
get-east-asian-width@1.2.0: {}
|
||||
|
||||
get-func-name@2.0.2: {}
|
||||
|
||||
get-intrinsic@1.2.4:
|
||||
@@ -5760,7 +5635,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@ioredis/commands': 1.2.0
|
||||
cluster-key-slot: 1.1.2
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
denque: 2.1.0
|
||||
lodash.defaults: 4.2.0
|
||||
lodash.isarguments: 3.1.0
|
||||
@@ -5801,12 +5676,6 @@ snapshots:
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-fullwidth-code-point@4.0.0: {}
|
||||
|
||||
is-fullwidth-code-point@5.0.0:
|
||||
dependencies:
|
||||
get-east-asian-width: 1.2.0
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
@@ -5891,36 +5760,10 @@ snapshots:
|
||||
prelude-ls: 1.2.1
|
||||
type-check: 0.4.0
|
||||
|
||||
lilconfig@3.0.0: {}
|
||||
|
||||
lilconfig@3.1.1: {}
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
lint-staged@15.2.2:
|
||||
dependencies:
|
||||
chalk: 5.3.0
|
||||
commander: 11.1.0
|
||||
debug: 4.3.4
|
||||
execa: 8.0.1
|
||||
lilconfig: 3.0.0
|
||||
listr2: 8.0.1
|
||||
micromatch: 4.0.5
|
||||
pidtree: 0.6.0
|
||||
string-argv: 0.3.2
|
||||
yaml: 2.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
listr2@8.0.1:
|
||||
dependencies:
|
||||
cli-truncate: 4.0.0
|
||||
colorette: 2.0.20
|
||||
eventemitter3: 5.0.1
|
||||
log-update: 6.0.0
|
||||
rfdc: 1.3.1
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
local-pkg@0.5.0:
|
||||
dependencies:
|
||||
mlly: 1.6.1
|
||||
@@ -5952,14 +5795,6 @@ snapshots:
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
||||
log-update@6.0.0:
|
||||
dependencies:
|
||||
ansi-escapes: 6.2.1
|
||||
cli-cursor: 4.0.0
|
||||
slice-ansi: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
logform@2.6.0:
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
@@ -6023,7 +5858,7 @@ snapshots:
|
||||
|
||||
micromark@2.11.4:
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
parse-entities: 2.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6041,8 +5876,6 @@ snapshots:
|
||||
|
||||
mime@1.6.0: {}
|
||||
|
||||
mimic-fn@2.1.0: {}
|
||||
|
||||
mimic-fn@4.0.0: {}
|
||||
|
||||
min-indent@1.0.1: {}
|
||||
@@ -6210,10 +6043,6 @@ snapshots:
|
||||
dependencies:
|
||||
fn.name: 1.1.0
|
||||
|
||||
onetime@5.1.2:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
onetime@6.0.0:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
@@ -6329,8 +6158,6 @@ snapshots:
|
||||
|
||||
picomatch@4.0.2: {}
|
||||
|
||||
pidtree@0.6.0: {}
|
||||
|
||||
pkg-types@1.1.0:
|
||||
dependencies:
|
||||
confbox: 0.1.7
|
||||
@@ -6601,15 +6428,8 @@ snapshots:
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
dependencies:
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
|
||||
reusify@1.0.4: {}
|
||||
|
||||
rfdc@1.3.1: {}
|
||||
|
||||
rimraf@3.0.2:
|
||||
dependencies:
|
||||
glob: 7.2.3
|
||||
@@ -6742,8 +6562,6 @@ snapshots:
|
||||
|
||||
siginfo@2.0.0: {}
|
||||
|
||||
signal-exit@3.0.7: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
simple-git-hooks@2.11.1: {}
|
||||
@@ -6764,16 +6582,6 @@ snapshots:
|
||||
|
||||
slash@5.1.0: {}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 4.0.0
|
||||
|
||||
slice-ansi@7.1.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 5.0.0
|
||||
|
||||
source-map-js@1.2.0: {}
|
||||
|
||||
sparse-bitfield@3.0.3:
|
||||
@@ -6825,12 +6633,6 @@ snapshots:
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
string-width@7.1.0:
|
||||
dependencies:
|
||||
emoji-regex: 10.3.0
|
||||
get-east-asian-width: 1.2.0
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
string_decoder@1.3.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
@@ -7087,7 +6889,7 @@ snapshots:
|
||||
vite-node@1.5.2(@types/node@20.12.7):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.0.0
|
||||
vite: 5.2.10(@types/node@20.12.7)
|
||||
@@ -7119,7 +6921,7 @@ snapshots:
|
||||
'@vitest/utils': 1.5.2
|
||||
acorn-walk: 8.3.2
|
||||
chai: 4.4.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
execa: 8.0.1
|
||||
local-pkg: 0.5.0
|
||||
magic-string: 0.30.10
|
||||
@@ -7149,7 +6951,7 @@ snapshots:
|
||||
|
||||
vue-eslint-parser@9.4.2(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
eslint-scope: 7.2.2
|
||||
eslint-visitor-keys: 3.4.3
|
||||
@@ -7219,12 +7021,6 @@ snapshots:
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
wrap-ansi@9.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
string-width: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@7.5.9: {}
|
||||
@@ -7243,8 +7039,6 @@ snapshots:
|
||||
lodash: 4.17.21
|
||||
yaml: 2.4.2
|
||||
|
||||
yaml@2.3.4: {}
|
||||
|
||||
yaml@2.4.2: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
@@ -14,6 +14,7 @@ export async function BlockParser(db: Database, reader: EosioShipReaderResolved)
|
||||
setTimeout(() => process.exit(1), 10000)
|
||||
})
|
||||
|
||||
|
||||
blocks$.subscribe(async (block: IBlock) => {
|
||||
// console.log('new block: ', block)
|
||||
// process.stdout.write('\r') // Возврат каретки в начало строки
|
||||
|
||||
@@ -11,7 +11,6 @@ export class Database {
|
||||
private sync: Collection | undefined
|
||||
|
||||
constructor() {
|
||||
console.log('mongo2: ', mongoUri)
|
||||
this.client = new MongoClient(mongoUri)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ function getEnvVar(key: string): string {
|
||||
return envVar
|
||||
}
|
||||
export const node_env = getEnvVar('NODE_ENV')
|
||||
console.log('ENV: ', node_env)
|
||||
export const eosioApi = getEnvVar('API')
|
||||
export const shipApi = getEnvVar('SHIP')
|
||||
export const mongoUri = `${getEnvVar('MONGO_EXPLORER_URI')}${node_env === 'test' ? '-test' : ''}`
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "error",
|
||||
"no-console": "warn",
|
||||
"func-names": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"consistent-return": "off",
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"subcode"
|
||||
]
|
||||
],
|
||||
"editor.formatOnSave": true,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.7.34](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.33...coopback@1.7.34) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.33](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.32...coopback@1.7.33) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.32](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.31...coopback@1.7.32) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.31](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.31-alpha.1...coopback@1.7.31) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.30](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.29...coopback@1.7.30) (2024-08-13)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.29](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.29-alpha.0...coopback@1.7.29) (2024-08-05)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "create-nodejs-express-app",
|
||||
"version": "1.7.29",
|
||||
"version": "1.7.37-alpha.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "create-nodejs-express-app",
|
||||
"version": "1.7.29",
|
||||
"version": "1.7.37-alpha.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@a2seven/yoo-checkout": "^1.1.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "coopback",
|
||||
"version": "1.7.29",
|
||||
"version": "1.7.37-alpha.0",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"bin": "bin/createNodejsApp.js",
|
||||
|
||||
@@ -17,12 +17,11 @@ const [username] = args;
|
||||
async function createServiceUser(username: string) {
|
||||
try {
|
||||
await mongoose.connect(config.mongoose.url, config.mongoose.options);
|
||||
|
||||
const user = await userService.createServiceUser(username);
|
||||
const token = await tokenService.generateServiceAccessToken(user);
|
||||
logger.log('token:', token.access.token);
|
||||
console.log('token:', token.access.token);
|
||||
} catch (e: any) {
|
||||
logger.log('Ошибка: ', e.message);
|
||||
logger.error('Ошибка: ', e.message);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
|
||||
@@ -17,7 +17,7 @@ async function deleteUser(username: string) {
|
||||
try {
|
||||
await mongoose.connect(config.mongoose.url, config.mongoose.options);
|
||||
|
||||
await userService.deleteUserById(username);
|
||||
await userService.deleteUserByUsername(username);
|
||||
|
||||
console.log('Пользователь удалён: ', username);
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -15,17 +15,12 @@ async function init() {
|
||||
|
||||
await mongoose.connect(config.mongoose.url, config.mongoose.options);
|
||||
const wif = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3';
|
||||
const password = await crypto.createHash('sha256').update(wif).digest('hex');
|
||||
const hashed_password = await hash(password, 8);
|
||||
|
||||
console.log('password: ', hashed_password);
|
||||
|
||||
await userService.createUser({
|
||||
username: 'ant',
|
||||
email: 'dacom.dark.sun@gmail.com',
|
||||
password,
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
role: 'chairman',
|
||||
role: 'user',
|
||||
type: 'individual',
|
||||
individual_data: {
|
||||
first_name: 'Иван',
|
||||
@@ -46,7 +41,6 @@ async function init() {
|
||||
const voskhod = await userService.createUser({
|
||||
username: 'voskhod',
|
||||
email: 'chairman.voskhod@gmail.com',
|
||||
password,
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
role: 'user',
|
||||
type: 'organization',
|
||||
|
||||
@@ -8,6 +8,7 @@ const envVarsSchema = Joi.object()
|
||||
.keys({
|
||||
NODE_ENV: Joi.string().valid('production', 'development', 'test').required(),
|
||||
BASE_URL: Joi.string().required(),
|
||||
SERVER_SECRET: Joi.string().required(),
|
||||
SERVICE_USERNAME: Joi.string().required(),
|
||||
SERVICE_WIF: Joi.string().required(),
|
||||
PORT: Joi.number().default(3000),
|
||||
@@ -21,6 +22,9 @@ const envVarsSchema = Joi.object()
|
||||
JWT_VERIFY_EMAIL_EXPIRATION_MINUTES: Joi.number()
|
||||
.default(10)
|
||||
.description('minutes after which verify email token expires'),
|
||||
|
||||
JWT_INVITE_EXPIRATION_MINUTES: Joi.number().default(3600).description('minutes after invite token expires'),
|
||||
|
||||
SMTP_HOST: Joi.string().description('server that will send the emails'),
|
||||
SMTP_PORT: Joi.number().description('port to connect to the email server'),
|
||||
SMTP_USERNAME: Joi.string().description('username for email server'),
|
||||
@@ -41,6 +45,7 @@ export default {
|
||||
env: envVars.NODE_ENV,
|
||||
base_url: envVars.BASE_URL,
|
||||
port: envVars.PORT,
|
||||
server_secret: envVars.SERVER_SECRET,
|
||||
service_wif: envVars.SERVICE_WIF,
|
||||
service_username: envVars.SERVICE_USERNAME,
|
||||
mongoose: {
|
||||
@@ -57,6 +62,7 @@ export default {
|
||||
refreshExpirationDays: envVars.JWT_REFRESH_EXPIRATION_DAYS,
|
||||
resetPasswordExpirationMinutes: envVars.JWT_RESET_PASSWORD_EXPIRATION_MINUTES,
|
||||
verifyEmailExpirationMinutes: envVars.JWT_VERIFY_EMAIL_EXPIRATION_MINUTES,
|
||||
inviteExpirationMinutes: envVars.JWT_INVITE_EXPIRATION_MINUTES,
|
||||
},
|
||||
email: {
|
||||
smtp: {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import {Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'
|
||||
import config from './config'
|
||||
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';
|
||||
import config from './config';
|
||||
import { tokenTypes } from './tokens';
|
||||
import { User } from '../models';
|
||||
|
||||
|
||||
const jwtOptions = {
|
||||
secretOrKey: config.jwt.secret,
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
@@ -14,7 +13,7 @@ const jwtVerify = async (payload, done) => {
|
||||
if (payload.type !== tokenTypes.ACCESS) {
|
||||
throw new Error('Invalid token type');
|
||||
}
|
||||
const user = await User.findOne({_id: payload.sub});
|
||||
const user = await User.findOne({ _id: payload.sub });
|
||||
if (!user) {
|
||||
return done(null, false);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const allRoles = {
|
||||
user: [''],
|
||||
service: ['sendNotification'],
|
||||
chairman: ['getUsers', 'manageUsers', 'loadAgenda', 'loadStaff', 'getDocuments', 'loadInfo'],
|
||||
service: ['addUser', 'sendNotification', 'install'],
|
||||
chairman: ['addUser', 'getUsers', 'manageUsers', 'loadAgenda', 'loadStaff', 'getDocuments', 'loadInfo', 'set-vars'],
|
||||
member: ['getUsers', 'manageUsers', 'loadAgenda', 'loadStaff', 'getDocuments', 'loadInfo'],
|
||||
};
|
||||
|
||||
|
||||
@@ -3,4 +3,5 @@ export const tokenTypes = {
|
||||
REFRESH: 'refresh',
|
||||
RESET_PASSWORD: 'resetPassword',
|
||||
VERIFY_EMAIL: 'verifyEmail',
|
||||
INVITE: 'invite',
|
||||
};
|
||||
|
||||
@@ -26,8 +26,8 @@ export const refreshTokens = catchAsync(async (req: RRefreshTokens, res: any) =>
|
||||
});
|
||||
|
||||
export const lostKey = catchAsync(async (req: RForgotKey, res) => {
|
||||
const resetKeyToken = await tokenService.generateResetPasswordToken(req.body.email);
|
||||
await emailService.sendResetPasswordEmail(req.body.email, resetKeyToken);
|
||||
const resetKeyToken = await tokenService.generateResetKeyToken(req.body.email);
|
||||
await emailService.sendResetKeyEmail(req.body.email, resetKeyToken);
|
||||
res.status(NO_CONTENT).send();
|
||||
});
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export const loadAgenda = catchAsync(async (req: Request, res: Response) => {
|
||||
const { coopname } = req.query;
|
||||
const agenda = await coopService.loadAgenda(coopname as string);
|
||||
|
||||
const complexAgenda: Cooperative.Documents.IComplexAgenda[] = [];
|
||||
const complexAgenda: Cooperative.Document.IComplexAgenda[] = [];
|
||||
|
||||
for (const { action, table } of agenda) {
|
||||
const documents = await documentService.buildComplexDocument(action);
|
||||
|
||||
@@ -4,4 +4,5 @@ export * as documentController from './document.controller';
|
||||
export * as paymentController from './payment.controller';
|
||||
export * as coopController from './coop.controller';
|
||||
export * as notifyController from './notify.controller';
|
||||
export * as monoController from './mono.controller';
|
||||
export * as systemController from './system.controller';
|
||||
export * as participantController from './participant.controller';
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { getMonoStatus } from '../services/mono.service';
|
||||
import { getBlockchainInfo } from '../services/blockchain.service';
|
||||
import { IHealthResponse } from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
|
||||
export const getHealth = catchAsync(async (req: Request, res: Response) => {
|
||||
const status = await getMonoStatus();
|
||||
const blockchain = await getBlockchainInfo();
|
||||
|
||||
const result: IHealthResponse = {
|
||||
status,
|
||||
blockchain,
|
||||
};
|
||||
|
||||
res.status(httpStatus.OK).send(result);
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { participantService } from '../services';
|
||||
import type { RJoinCooperative } from '../types';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
|
||||
export const joinCooperative = catchAsync(async (req: RJoinCooperative, res) => {
|
||||
await participantService.joinCooperative(req.body);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
@@ -91,7 +91,8 @@ export const addPaymentMethod = catchAsync(async (req: RSavePaymentMethod, res)
|
||||
const paymentData: Cooperative.Payments.IPaymentData = {
|
||||
username: req.body.username,
|
||||
method_id: req.body.method_id,
|
||||
user_type: user.type,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
user_type: user.type as any,
|
||||
method_type: req.body.method_type,
|
||||
is_default: false,
|
||||
data: req.body.data,
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { getMonoStatus } from '../services/system.service';
|
||||
import { getBlockchainInfo } from '../services/blockchain.service';
|
||||
import { IHealthResponse, IInstall, RInstall } from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { systemService } from '../services';
|
||||
import type { ISetVars, RSetVars } from '../types/auto-generated/system.validation';
|
||||
|
||||
export const install = catchAsync(async (req: RInstall, res: Response) => {
|
||||
const { body } = req;
|
||||
await systemService.install(body as IInstall);
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const getHealth = catchAsync(async (req: Request, res: Response) => {
|
||||
const status = await getMonoStatus();
|
||||
const blockchain = await getBlockchainInfo();
|
||||
|
||||
const result: IHealthResponse = {
|
||||
status,
|
||||
blockchain,
|
||||
};
|
||||
|
||||
res.status(httpStatus.OK).send(result);
|
||||
});
|
||||
|
||||
export const setVars = catchAsync(async (req: RSetVars, res: Response) => {
|
||||
await systemService.setVars(req.body as ISetVars);
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const getVarsSchema = catchAsync(async (req: RSetVars, res: Response) => {
|
||||
const schema = await systemService.getVarsSchema();
|
||||
res.status(httpStatus.OK).send(schema);
|
||||
});
|
||||
@@ -1,12 +1,16 @@
|
||||
import http from 'http-status';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { userService, tokenService } from '../services';
|
||||
import { RCreateUser, RJoinCooperative } from '../types';
|
||||
import { userService, tokenService, emailService, blockchainService } from '../services';
|
||||
import { IAddUser, ICreateUser, RCreateUser } from '../types';
|
||||
import httpStatus from 'http-status';
|
||||
import pick from '../utils/pick';
|
||||
import { IGetResponse } from '../types/common';
|
||||
import { IUser } from '../models/user.model';
|
||||
import { IUser, userStatus } from '../models/user.model';
|
||||
import { Request, Response } from 'express';
|
||||
import { generateUsername } from '../../tests/utils/generateUsername';
|
||||
import config from '../config/config';
|
||||
import logger from '../config/logger';
|
||||
|
||||
/**
|
||||
* Порядок регистрации:
|
||||
@@ -19,9 +23,9 @@ import { IUser } from '../models/user.model';
|
||||
* 7. (joinCooperative) Пользователь подписывает заявление на вступление и вызывает метод joinCooperative, прикладывая подписанное заявление.
|
||||
* 8. Система сохраняет подписанное заявление
|
||||
* 9. (createInitialPayment) Пользователь получает ордер на оплату.
|
||||
* 9. Пользователь оплачивает ордер.
|
||||
* 10. Система принимает оплату и регистрирует аккаунт в блокчейне.
|
||||
* 11. (trx confirmpay) Пользователь подписывает велком-письмо с подтверждением собственноручности оплаты (транзакция в блокчейне для активации)
|
||||
* 12. Регистрация продолжается ожиданием решения совета
|
||||
*/
|
||||
export const createUser = catchAsync(async (req: RCreateUser, res) => {
|
||||
const user = await userService.createUser(req.body);
|
||||
@@ -30,10 +34,40 @@ export const createUser = catchAsync(async (req: RCreateUser, res) => {
|
||||
res.status(http.CREATED).send({ user, tokens });
|
||||
});
|
||||
|
||||
export const joinCooperative = catchAsync(async (req: RJoinCooperative, res) => {
|
||||
await userService.joinCooperative(req.body);
|
||||
export const addUser = catchAsync(async (req: Request, res: Response) => {
|
||||
const body: IAddUser = req.body;
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
const newUser: ICreateUser = {
|
||||
...body,
|
||||
public_key: '',
|
||||
role: 'user',
|
||||
username: generateUsername(),
|
||||
};
|
||||
|
||||
const user = await userService.createUser(newUser);
|
||||
user.status = userStatus['4_Registered'];
|
||||
user.is_registered = true;
|
||||
await user.save();
|
||||
|
||||
try {
|
||||
await blockchainService.addUser({
|
||||
...body,
|
||||
...newUser,
|
||||
registrator: config.service_username,
|
||||
referer: body.referer ? body.referer : '',
|
||||
coopname: config.coopname,
|
||||
meta: '',
|
||||
});
|
||||
|
||||
const token = await tokenService.generateInviteToken(user.email);
|
||||
await emailService.sendInviteEmail(req.body.email, token);
|
||||
} catch (e: any) {
|
||||
logger.warn('error on add user: ', e);
|
||||
await userService.deleteUserByUsername(newUser.username);
|
||||
throw new ApiError(httpStatus.BAD_GATEWAY, e.message);
|
||||
}
|
||||
|
||||
res.status(httpStatus.CREATED).send({ user });
|
||||
});
|
||||
|
||||
export const getUsers = catchAsync(async (req, res) => {
|
||||
@@ -47,7 +81,7 @@ export const getUsers = catchAsync(async (req, res) => {
|
||||
for await (const user of users.results) {
|
||||
const json = user.toJSON();
|
||||
if (user.type != 'service') {
|
||||
json.private_data = (await user.getPrivateData()) || {};
|
||||
json.private_data = await user.getPrivateData();
|
||||
data.push(json);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +102,9 @@ export const getUser = catchAsync(async (req, res) => {
|
||||
}
|
||||
const json = user.toJSON();
|
||||
|
||||
json.private_data = await user.getPrivateData();
|
||||
if (user.type != 'service') {
|
||||
json.private_data = await user.getPrivateData();
|
||||
}
|
||||
|
||||
res.send(json);
|
||||
});
|
||||
@@ -82,6 +118,6 @@ export const updateUser = catchAsync(async (req, res) => {
|
||||
});
|
||||
|
||||
export const deleteUser = catchAsync(async (req, res) => {
|
||||
await userService.deleteUserById(req.params.username);
|
||||
await userService.deleteUserByUsername(req.params.username);
|
||||
res.status(http.NO_CONTENT).send();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import config from './config/config';
|
||||
import logger from './config/logger';
|
||||
import { connectGenerator } from './services/document.service';
|
||||
import { initSocketConnection } from './controllers/ws.controller';
|
||||
import { monoService } from './services';
|
||||
import { systemService } from './services';
|
||||
|
||||
const SERVER_URL: string = process.env.SOCKET_SERVER || 'http://localhost:2222';
|
||||
|
||||
@@ -15,7 +15,7 @@ let server: any;
|
||||
mongoose.connect(config.mongoose.url).then(async () => {
|
||||
logger.info('Connected to MongoDB');
|
||||
|
||||
await monoService.init();
|
||||
await systemService.init();
|
||||
|
||||
// подключаемся к хранилищу приватных данных
|
||||
await connectGenerator();
|
||||
|
||||
@@ -6,6 +6,13 @@ import { roleRights } from '../config/roles';
|
||||
const { UNAUTHORIZED, FORBIDDEN } = httpStatus;
|
||||
|
||||
const verifyCallback = (req, resolve, reject, requiredRights) => async (err, user, info) => {
|
||||
const serverSecret = process.env.SERVER_SECRET;
|
||||
|
||||
// Проверка заголовка server-secret
|
||||
if (serverSecret && req.headers['server-secret'] === serverSecret) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
if (err || info || !user) {
|
||||
return reject(new ApiError(UNAUTHORIZED, 'Please authenticate'));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import mongoose, { Schema } from 'mongoose';
|
||||
import { paginate, toJSON } from './plugins';
|
||||
|
||||
export enum tempdocType {
|
||||
JoinStatement = 'joinStatement',
|
||||
WalletAgreement = 'walletAgreement',
|
||||
SignatureAgreement = 'signatureAgreement',
|
||||
PrivacyAgreement = 'privacyAgreement',
|
||||
UserAgreement = 'userAgreement',
|
||||
}
|
||||
|
||||
export interface ITempDocument {
|
||||
username: string;
|
||||
type: tempdocType;
|
||||
document: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
}
|
||||
|
||||
const MonoSchema = new Schema<ITempDocument>({
|
||||
username: { type: String, required: true },
|
||||
type: { type: String, required: true, enum: ['joinStatement', 'walletAgreement'] },
|
||||
document: {
|
||||
public_key: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
signature: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
meta: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
hash: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
MonoSchema.plugin(toJSON);
|
||||
MonoSchema.plugin(paginate);
|
||||
|
||||
const TempDocument = mongoose.model<ITempDocument>('TempDocument', MonoSchema);
|
||||
|
||||
export default TempDocument;
|
||||
@@ -25,7 +25,7 @@ const tokenSchema = new Schema<IToken>(
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: [tokenTypes.REFRESH, tokenTypes.RESET_PASSWORD, tokenTypes.VERIFY_EMAIL],
|
||||
enum: [tokenTypes.REFRESH, tokenTypes.RESET_PASSWORD, tokenTypes.VERIFY_EMAIL, tokenTypes.INVITE],
|
||||
required: true,
|
||||
},
|
||||
expires: {
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
import mongoose, { Schema, model, Model } from 'mongoose';
|
||||
import validator from 'validator/index';
|
||||
import bcryptjs from 'bcryptjs';
|
||||
import { toJSON, paginate } from './plugins/index';
|
||||
import { roles } from '../config/roles';
|
||||
import { generator } from '../services/document.service';
|
||||
import { Cooperative } from 'cooptypes';
|
||||
|
||||
const { isEmail } = validator;
|
||||
const { compare, hash } = bcryptjs;
|
||||
|
||||
export enum userStatus {
|
||||
'1_Created' = 'created',
|
||||
'2_Joined' = 'joined',
|
||||
'3_Payed' = 'payed',
|
||||
'4_Registered' = 'registered',
|
||||
'5_Active' = 'active',
|
||||
'10_Failed' = 'failed',
|
||||
'200_Blocked' = 'blocked',
|
||||
}
|
||||
|
||||
export interface IUser {
|
||||
username: string;
|
||||
status: 'created' | 'joined' | 'payed' | 'registered' | 'active' | 'failed' | 'blocked';
|
||||
status: userStatus;
|
||||
message: string;
|
||||
is_registered: boolean;
|
||||
has_account: boolean;
|
||||
type: 'individual' | 'entrepreneur' | 'organization';
|
||||
type: 'individual' | 'entrepreneur' | 'organization' | 'service';
|
||||
public_key: string;
|
||||
referer: string;
|
||||
email: string;
|
||||
password: string;
|
||||
role: string;
|
||||
is_email_verified: boolean;
|
||||
statement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
// statement: {
|
||||
// hash: string;
|
||||
// meta: object;
|
||||
// public_key: string;
|
||||
// signature: string;
|
||||
// };
|
||||
private_data:
|
||||
| Cooperative.Users.IIndividualData
|
||||
| Cooperative.Users.IEntrepreneurData
|
||||
@@ -36,7 +43,6 @@ export interface IUser {
|
||||
getPrivateData(): Promise<
|
||||
Cooperative.Users.IIndividualData | Cooperative.Users.IEntrepreneurData | Cooperative.Users.IOrganizationData | null
|
||||
>;
|
||||
isPasswordMatch(password: string): Promise<boolean>;
|
||||
}
|
||||
|
||||
interface IUserModel extends Model<IUser> {
|
||||
@@ -54,8 +60,8 @@ const userSchema = new Schema<IUser, IUserModel>(
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['created', 'joined', 'payed', 'registered', 'active', 'failed', 'blocked'],
|
||||
default: 'created',
|
||||
enum: Object.values(userStatus),
|
||||
default: userStatus['1_Created'],
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
@@ -72,7 +78,7 @@ const userSchema = new Schema<IUser, IUserModel>(
|
||||
},
|
||||
public_key: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
referer: {
|
||||
type: String,
|
||||
@@ -80,7 +86,7 @@ const userSchema = new Schema<IUser, IUserModel>(
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: false,
|
||||
unique: true,
|
||||
trim: true,
|
||||
lowercase: true,
|
||||
@@ -90,18 +96,6 @@ const userSchema = new Schema<IUser, IUserModel>(
|
||||
}
|
||||
},
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
minlength: 8,
|
||||
validate(value) {
|
||||
if (!value.match(/\d/) || !value.match(/[a-zA-Z]/)) {
|
||||
throw new Error('Password must contain at least one letter and one number');
|
||||
}
|
||||
},
|
||||
private: true, // used by the toJSON plugin
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
enum: roles,
|
||||
@@ -115,24 +109,24 @@ const userSchema = new Schema<IUser, IUserModel>(
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
statement: {
|
||||
public_key: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
signature: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
meta: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
hash: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
// statement: {
|
||||
// public_key: {
|
||||
// type: String,
|
||||
// default: '',
|
||||
// },
|
||||
// signature: {
|
||||
// type: String,
|
||||
// default: '',
|
||||
// },
|
||||
// meta: {
|
||||
// type: Object,
|
||||
// default: {},
|
||||
// },
|
||||
// hash: {
|
||||
// type: String,
|
||||
// default: '',
|
||||
// },
|
||||
// },
|
||||
},
|
||||
{
|
||||
minimize: false,
|
||||
@@ -163,21 +157,6 @@ userSchema.methods.getPrivateData = async function (): Promise<
|
||||
return result;
|
||||
};
|
||||
|
||||
userSchema.methods.isPasswordMatch = async function (password) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const user = this;
|
||||
return compare(password, user.password);
|
||||
};
|
||||
|
||||
userSchema.pre('save', async function (next) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const user = this;
|
||||
if (user.isModified('password')) {
|
||||
user.password = await hash(user.password, 8);
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
const User = model<IUser, IUserModel>('User', userSchema);
|
||||
|
||||
export default User;
|
||||
|
||||
@@ -4,9 +4,10 @@ import userRoute from './user.route';
|
||||
import docsRoute from './docs.route';
|
||||
import paymentRoute from './payment.route';
|
||||
import coopRoute from './coop.route';
|
||||
import monoRoute from './mono.route';
|
||||
import monoRoute from './system.route';
|
||||
import dataRoute from './document.route';
|
||||
import notifyRoute from './notify.route';
|
||||
import participantsRoute from './participant.route';
|
||||
|
||||
import config from '../../config/config';
|
||||
|
||||
@@ -14,7 +15,7 @@ const router = Router();
|
||||
|
||||
const defaultRoutes = [
|
||||
{
|
||||
path: '/mono',
|
||||
path: '/system',
|
||||
route: monoRoute,
|
||||
},
|
||||
{
|
||||
@@ -25,6 +26,10 @@ const defaultRoutes = [
|
||||
path: '/users',
|
||||
route: userRoute,
|
||||
},
|
||||
{
|
||||
path: '/participants',
|
||||
route: participantsRoute,
|
||||
},
|
||||
{
|
||||
path: '/documents',
|
||||
route: dataRoute,
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Router } from 'express';
|
||||
import { monoController } from '../../controllers';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.route('/health').get(monoController.getHealth);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Router } from 'express';
|
||||
import auth from '../../middlewares/auth';
|
||||
import validate from '../../middlewares/validate';
|
||||
import { participantValidation } from '../../validations';
|
||||
import { participantController } from '../../controllers';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router
|
||||
.route('/join-cooperative')
|
||||
.post(auth(), validate(participantValidation.RJoinCooperative), participantController.joinCooperative);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Router } from 'express';
|
||||
import { systemController } from '../../controllers';
|
||||
import auth from '../../middlewares/auth';
|
||||
import validate from '../../middlewares/validate';
|
||||
import { systemValidation } from '../../validations';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.route('/install').post(auth('install'), validate(systemValidation.RInstall), systemController.install);
|
||||
|
||||
router.route('/get-vars-schema').post(auth(), systemController.getVarsSchema);
|
||||
|
||||
router.route('/set-vars').post(auth('set-vars'), validate(systemValidation.RSetVars), systemController.setVars);
|
||||
router.route('/get-vars').post(auth(), validate(systemValidation.RSetVars), systemController.setVars);
|
||||
|
||||
router.route('/health').get(systemController.getHealth);
|
||||
|
||||
export default router;
|
||||
@@ -11,9 +11,7 @@ router
|
||||
.post(validate(userValidation.RCreateUser), userController.createUser)
|
||||
.get(auth('getUsers'), validate(userValidation.RGetUsers), userController.getUsers);
|
||||
|
||||
router
|
||||
.route('/join-cooperative')
|
||||
.post(validate(userValidation.RJoinCooperative), userController.joinCooperative)
|
||||
router.route('/add').post(auth('addUser'), validate(userValidation.RAddUser), userController.addUser);
|
||||
|
||||
router
|
||||
.route('/:username')
|
||||
|
||||
@@ -41,27 +41,13 @@ export const loginUserWithSignature = async (email, now, signature) => {
|
||||
|
||||
if (!hasKey) throw new ApiError(httpStatus.UNAUTHORIZED, 'Неверный приватный ключ');
|
||||
} catch (e) {
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'Аккаунт в блокчейне не найден');
|
||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'Неверный приватный ключ');
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
/**
|
||||
* Login with email and password
|
||||
* @param {string} email
|
||||
* @param {string} password
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
export const loginUserWithEmailAndPassword = async (email, password) => {
|
||||
const user = await userService.getUserByEmail(email);
|
||||
if (!user || !(await user.isPasswordMatch(password))) {
|
||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'Incorrect email or password');
|
||||
}
|
||||
return user;
|
||||
};
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @param {string} refreshToken
|
||||
@@ -102,26 +88,27 @@ export const refreshAuth = async (data: IRefreshTokens) => {
|
||||
*/
|
||||
export const resetKey = async (resetKeyToken, publicKey) => {
|
||||
try {
|
||||
const resetPasswordTokenDoc = await tokenService.verifyToken(resetKeyToken, tokenTypes.RESET_PASSWORD);
|
||||
const resetKeyTokenDoc = await tokenService.verifyToken(resetKeyToken, [tokenTypes.RESET_PASSWORD, tokenTypes.INVITE]);
|
||||
|
||||
const user = await userService.getUserById(resetPasswordTokenDoc.user);
|
||||
const user = await userService.getUserById(resetKeyTokenDoc.user);
|
||||
if (!user) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
await blockchainService.changeKey({
|
||||
coopname: config.coopname,
|
||||
changer: config.service_username,
|
||||
username: user.username,
|
||||
public_key: publicKey,
|
||||
});
|
||||
if (config.env !== 'test')
|
||||
await blockchainService.changeKey({
|
||||
coopname: config.coopname,
|
||||
changer: config.service_username,
|
||||
username: user.username,
|
||||
public_key: publicKey,
|
||||
});
|
||||
|
||||
await userService.updateUserById(user._id, { public_key: publicKey });
|
||||
|
||||
await Token.deleteMany({ user: user._id, type: tokenTypes.RESET_PASSWORD });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'Password reset failed');
|
||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'Token reset failed');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ import { GatewayContract, RegistratorContract, SovietContract } from 'cooptypes'
|
||||
import { IUser } from '../models/user.model';
|
||||
import { GetAccountResult, GetInfoResult } from 'eosjs/dist/eosjs-rpc-interfaces';
|
||||
import config from '../config/config';
|
||||
import TempDocument, { tempdocType } from '../models/tempDocument.model';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import httpStatus from 'http-status';
|
||||
|
||||
const rpc = new JsonRpc(process.env.BLOCKCHAIN_RPC as string, { fetch });
|
||||
|
||||
@@ -84,9 +87,9 @@ async function getCooperative(coopname) {
|
||||
|
||||
const [cooperative] = await lazyFetch(
|
||||
api,
|
||||
process.env.REGISTRATOR_CONTRACT,
|
||||
process.env.REGISTRATOR_CONTRACT,
|
||||
'orgs',
|
||||
RegistratorContract.contractName.production,
|
||||
RegistratorContract.contractName.production,
|
||||
RegistratorContract.Tables.Cooperatives.tableName,
|
||||
coopname,
|
||||
coopname,
|
||||
1
|
||||
@@ -95,7 +98,7 @@ async function getCooperative(coopname) {
|
||||
}
|
||||
|
||||
async function registerBlockchainAccount(user: IUser, orderData: GatewayContract.Actions.CompleteDeposit.ICompleteDeposit) {
|
||||
const eos = await getInstance(process.env.REGISTRATOR_WIF);
|
||||
const eos = await getInstance(process.env.SERVICE_WIF);
|
||||
|
||||
const newaccount: RegistratorContract.Actions.CreateAccount.ICreateAccount = {
|
||||
registrator: process.env.COOPNAME as string,
|
||||
@@ -113,11 +116,59 @@ async function registerBlockchainAccount(user: IUser, orderData: GatewayContract
|
||||
type: user.type,
|
||||
};
|
||||
|
||||
const statement = await TempDocument.findOne({ username: user.username, type: tempdocType.JoinStatement });
|
||||
if (!statement) throw new ApiError(httpStatus.BAD_REQUEST, 'Не найдено заявление на вступление');
|
||||
|
||||
const joinCooperativeData: RegistratorContract.Actions.JoinCooperative.IJoinCooperative = {
|
||||
coopname: process.env.COOPNAME as string,
|
||||
registrator: process.env.COOPNAME as string,
|
||||
username: user.username,
|
||||
document: { ...user.statement, meta: JSON.stringify(user.statement.meta) },
|
||||
document: { ...statement.document, meta: JSON.stringify(statement.document.meta) },
|
||||
};
|
||||
|
||||
//TODO добавить здесь соглашений
|
||||
const walletAgreement = await TempDocument.findOne({ username: user.username, type: tempdocType.WalletAgreement });
|
||||
if (!walletAgreement) throw new ApiError(httpStatus.BAD_REQUEST, 'Не найдено заявление на вступление');
|
||||
|
||||
const walletAgreementData: SovietContract.Actions.Agreements.SendAgreement.ISendAgreement = {
|
||||
coopname: process.env.COOPNAME as string,
|
||||
administrator: process.env.COOPNAME as string,
|
||||
username: user.username,
|
||||
agreement_type: 'wallet',
|
||||
document: { ...walletAgreement.document, meta: JSON.stringify(walletAgreement.document.meta) },
|
||||
};
|
||||
|
||||
const privacyAgreement = await TempDocument.findOne({ username: user.username, type: tempdocType.PrivacyAgreement });
|
||||
if (!privacyAgreement) throw new ApiError(httpStatus.BAD_REQUEST, 'Не найдено соглашение о политике конфиденциальности');
|
||||
|
||||
const privacyAgreementData: SovietContract.Actions.Agreements.SendAgreement.ISendAgreement = {
|
||||
coopname: process.env.COOPNAME as string,
|
||||
administrator: process.env.COOPNAME as string,
|
||||
username: user.username,
|
||||
agreement_type: 'privacy',
|
||||
document: { ...privacyAgreement.document, meta: JSON.stringify(privacyAgreement.document.meta) },
|
||||
};
|
||||
|
||||
const signatureAgreement = await TempDocument.findOne({ username: user.username, type: tempdocType.SignatureAgreement });
|
||||
if (!signatureAgreement) throw new ApiError(httpStatus.BAD_REQUEST, 'Не найдено соглашение о правилах использования ЭЦП');
|
||||
|
||||
const signatureAgreementData: SovietContract.Actions.Agreements.SendAgreement.ISendAgreement = {
|
||||
coopname: process.env.COOPNAME as string,
|
||||
administrator: process.env.COOPNAME as string,
|
||||
username: user.username,
|
||||
agreement_type: 'signature',
|
||||
document: { ...signatureAgreement.document, meta: JSON.stringify(signatureAgreement.document.meta) },
|
||||
};
|
||||
|
||||
const userAgreement = await TempDocument.findOne({ username: user.username, type: tempdocType.UserAgreement });
|
||||
if (!userAgreement) throw new ApiError(httpStatus.BAD_REQUEST, 'Не найдено подписанное пользовательское соглашение');
|
||||
|
||||
const userAgreementData: SovietContract.Actions.Agreements.SendAgreement.ISendAgreement = {
|
||||
coopname: process.env.COOPNAME as string,
|
||||
administrator: process.env.COOPNAME as string,
|
||||
username: user.username,
|
||||
agreement_type: 'user',
|
||||
document: { ...userAgreement.document, meta: JSON.stringify(userAgreement.document.meta) },
|
||||
};
|
||||
|
||||
const actions = [
|
||||
@@ -165,6 +216,50 @@ async function registerBlockchainAccount(user: IUser, orderData: GatewayContract
|
||||
],
|
||||
data: orderData,
|
||||
},
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Agreements.SendAgreement.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: process.env.COOPNAME as string,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: walletAgreementData,
|
||||
},
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Agreements.SendAgreement.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: process.env.COOPNAME as string,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: signatureAgreementData,
|
||||
},
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Agreements.SendAgreement.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: process.env.COOPNAME as string,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: privacyAgreementData,
|
||||
},
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Agreements.SendAgreement.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: process.env.COOPNAME as string,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: userAgreementData,
|
||||
},
|
||||
];
|
||||
|
||||
const result = await eos.transact(
|
||||
@@ -176,14 +271,46 @@ async function registerBlockchainAccount(user: IUser, orderData: GatewayContract
|
||||
expireSeconds: 30,
|
||||
}
|
||||
);
|
||||
|
||||
console.dir(result, { depth: null });
|
||||
}
|
||||
|
||||
async function createOrder(data) {
|
||||
const eos = await getInstance(process.env.REGISTRATOR_WIF);
|
||||
async function createBoard(data: SovietContract.Actions.Boards.CreateBoard.ICreateboard) {
|
||||
const eos = await getInstance(config.service_wif);
|
||||
|
||||
console.log('data: ', data);
|
||||
|
||||
const actions = [
|
||||
{
|
||||
account: process.env.GATEWAY_CONTRACT as string,
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Boards.CreateBoard.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: config.service_username,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
];
|
||||
|
||||
await eos.transact(
|
||||
{
|
||||
actions,
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function createOrder(data) {
|
||||
const eos = await getInstance(process.env.SERVICE_WIF);
|
||||
|
||||
const actions = [
|
||||
{
|
||||
account: GatewayContract.contractName.production,
|
||||
name: 'deposit',
|
||||
authorization: [
|
||||
{
|
||||
@@ -211,7 +338,7 @@ async function createOrder(data) {
|
||||
}
|
||||
|
||||
async function completeOrder(data: GatewayContract.Actions.CompleteDeposit.ICompleteDeposit) {
|
||||
const eos = await getInstance(process.env.REGISTRATOR_WIF);
|
||||
const eos = await getInstance(process.env.SERVICE_WIF);
|
||||
|
||||
const actions = [
|
||||
{
|
||||
@@ -239,11 +366,11 @@ async function completeOrder(data: GatewayContract.Actions.CompleteDeposit.IComp
|
||||
}
|
||||
|
||||
async function failOrder(data) {
|
||||
const eos = await getInstance(process.env.REGISTRATOR_WIF);
|
||||
const eos = await getInstance(process.env.SERVICE_WIF);
|
||||
|
||||
const actions = [
|
||||
{
|
||||
account: process.env.GATEWAY_CONTRACT as string,
|
||||
account: GatewayContract.contractName.production,
|
||||
name: 'dpfail',
|
||||
authorization: [
|
||||
{
|
||||
@@ -266,6 +393,34 @@ async function failOrder(data) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function addUser(data: RegistratorContract.Actions.AddUser.IAddUser) {
|
||||
const eos = await getInstance(config.service_wif);
|
||||
|
||||
const actions = [
|
||||
{
|
||||
account: RegistratorContract.contractName.production,
|
||||
name: RegistratorContract.Actions.AddUser.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: config.service_username,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
];
|
||||
|
||||
await eos.transact(
|
||||
{
|
||||
actions,
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function changeKey(data: RegistratorContract.Actions.ChangeKey.IChangeKey) {
|
||||
const eos = await getInstance(config.service_wif);
|
||||
|
||||
@@ -297,7 +452,7 @@ export async function changeKey(data: RegistratorContract.Actions.ChangeKey.ICha
|
||||
async function getSoviet(coopname) {
|
||||
const api = await getApi();
|
||||
|
||||
const soviet = (await lazyFetch(api, process.env.SOVIET_CONTRACT, coopname, 'boards'))[0];
|
||||
const soviet = (await lazyFetch(api, SovietContract.contractName.production, coopname, 'boards'))[0];
|
||||
|
||||
return soviet;
|
||||
}
|
||||
@@ -305,7 +460,7 @@ async function getSoviet(coopname) {
|
||||
async function fetchAllParticipants() {
|
||||
const api = await getApi();
|
||||
|
||||
const participants = await lazyFetch(api, process.env.SOVIET_CONTRACT, process.env.COOPNAME, 'participants');
|
||||
const participants = await lazyFetch(api, SovietContract.contractName.production, process.env.COOPNAME, 'participants');
|
||||
return participants;
|
||||
}
|
||||
|
||||
@@ -323,4 +478,5 @@ export {
|
||||
getBlockchainInfo,
|
||||
getBlockchainAccount,
|
||||
hasActiveKey,
|
||||
createBoard,
|
||||
};
|
||||
|
||||
@@ -6,23 +6,23 @@ import ApiError from '../utils/ApiError';
|
||||
import httpStatus from 'http-status';
|
||||
import logger from '../config/logger';
|
||||
|
||||
export const loadAgenda = async (coopname: string): Promise<Cooperative.Documents.IAgenda[]> => {
|
||||
export const loadAgenda = async (coopname: string): Promise<Cooperative.Document.IAgenda[]> => {
|
||||
const api = await blockchainService.getApi();
|
||||
|
||||
const decisions = (await blockchainService.lazyFetch(
|
||||
api,
|
||||
process.env.SOVIET_CONTRACT as string,
|
||||
SovietContract.contractName.production as string,
|
||||
coopname,
|
||||
'decisions'
|
||||
)) as SovietContract.Tables.Decisions.IDecision[];
|
||||
|
||||
const agenda = [] as Cooperative.Documents.IAgenda[];
|
||||
const agenda = [] as Cooperative.Document.IAgenda[];
|
||||
|
||||
for (const table of decisions) {
|
||||
const action = (
|
||||
await getActions(`${process.env.SIMPLE_EXPLORER_API}/get-actions`, {
|
||||
filter: JSON.stringify({
|
||||
account: process.env.SOVIET_CONTRACT,
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Registry.NewSubmitted.actionName,
|
||||
receiver: process.env.COOPNAME,
|
||||
'data.decision_id': String(table.id),
|
||||
@@ -40,7 +40,7 @@ export const loadAgenda = async (coopname: string): Promise<Cooperative.Document
|
||||
export const loadStaff = async (coopname) => {
|
||||
const api = await blockchainService.getApi();
|
||||
|
||||
const staff = await blockchainService.lazyFetch(api, process.env.SOVIET_CONTRACT, coopname, 'staff');
|
||||
const staff = await blockchainService.lazyFetch(api, SovietContract.contractName.production, coopname, 'staff');
|
||||
|
||||
for (const staf of staff) {
|
||||
const user = await userService.getUserByUsername(staf.username);
|
||||
|
||||
@@ -18,19 +18,27 @@ export const generateDocument = async (options: IGenerate) => {
|
||||
// Шаг 1: Создание новой функции для сборки complexDocument
|
||||
export async function buildComplexDocument(
|
||||
raw_action_document: Cooperative.Blockchain.IAction
|
||||
): Promise<Cooperative.Documents.IComplexDocument> {
|
||||
let statement = {} as Cooperative.Documents.IComplexStatement;
|
||||
let decision = {} as Cooperative.Documents.IComplexDecision;
|
||||
let act = {} as Cooperative.Documents.IComplexAct;
|
||||
): Promise<Cooperative.Document.IComplexDocument> {
|
||||
let statement = {} as Cooperative.Document.IComplexStatement;
|
||||
let decision = {} as Cooperative.Document.IComplexDecision;
|
||||
const act = {} as Cooperative.Document.IComplexAct;
|
||||
const links: Cooperative.Document.IGeneratedDocument[] = [];
|
||||
|
||||
const raw_document = raw_action_document.data as SovietContract.Actions.Registry.NewSubmitted.INewSubmitted;
|
||||
|
||||
// Готовим заявления
|
||||
{
|
||||
const document = await generator.getDocument({ hash: raw_document.document.hash });
|
||||
|
||||
if (document)
|
||||
for (const link of document.meta.links) {
|
||||
const linked_document = await generator.getDocument({ hash: link });
|
||||
links.push(linked_document);
|
||||
}
|
||||
|
||||
const user = await User.findOne({ username: raw_document.username });
|
||||
|
||||
if (user) {
|
||||
if (user && user.type != 'service') {
|
||||
const user_data = await user?.getPrivateData();
|
||||
|
||||
const action: Cooperative.Blockchain.IExtendedAction = {
|
||||
@@ -39,8 +47,6 @@ export async function buildComplexDocument(
|
||||
};
|
||||
|
||||
statement = { action, document };
|
||||
} else {
|
||||
// throw new ApiError(400, 'Ошибка, один из пользователей не найден. Обратитесь в поддержку.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +57,7 @@ export async function buildComplexDocument(
|
||||
const decision_action = (
|
||||
await getActions(`${process.env.SIMPLE_EXPLORER_API}/get-actions`, {
|
||||
filter: JSON.stringify({
|
||||
account: process.env.SOVIET_CONTRACT,
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Registry.NewDecision.actionName,
|
||||
receiver: process.env.COOPNAME,
|
||||
'data.decision_id': String(raw_document.decision_id),
|
||||
@@ -65,8 +71,6 @@ export async function buildComplexDocument(
|
||||
const user = await User.findOne({ username: decision_action?.data?.username });
|
||||
|
||||
if (user) {
|
||||
const user_data = user.getPrivateData();
|
||||
|
||||
decision_extended_action = {
|
||||
...decision_action,
|
||||
user: (await user?.getPrivateData()) || null,
|
||||
@@ -74,6 +78,12 @@ export async function buildComplexDocument(
|
||||
|
||||
const document = await generator.getDocument({ hash: decision_action?.data?.document?.hash });
|
||||
|
||||
if (document)
|
||||
for (const link of document.meta.links) {
|
||||
const linked_document = await generator.getDocument({ hash: link });
|
||||
links.push(linked_document);
|
||||
}
|
||||
|
||||
decision = {
|
||||
document,
|
||||
action: decision_extended_action,
|
||||
@@ -87,21 +97,21 @@ export async function buildComplexDocument(
|
||||
}
|
||||
|
||||
// Готовим акты
|
||||
const acts: Cooperative.Documents.IComplexAct[] = [];
|
||||
const acts: Cooperative.Document.IComplexAct[] = [];
|
||||
|
||||
return { statement, decision, acts };
|
||||
return { statement, decision, acts, links };
|
||||
}
|
||||
|
||||
export const queryDocuments = async (
|
||||
filter: any,
|
||||
page = 1,
|
||||
limit = 100
|
||||
): Promise<Cooperative.Documents.IGetComplexDocuments> => {
|
||||
): Promise<Cooperative.Document.IGetComplexDocuments> => {
|
||||
const actions = await getActions<SovietContract.Actions.Registry.NewResolved.INewResolved>(
|
||||
`${process.env.SIMPLE_EXPLORER_API}/get-actions`,
|
||||
{
|
||||
filter: JSON.stringify({
|
||||
account: process.env.SOVIET_CONTRACT,
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Registry.NewResolved.actionName,
|
||||
receiver: process.env.COOPNAME,
|
||||
...filter,
|
||||
@@ -111,7 +121,7 @@ export const queryDocuments = async (
|
||||
}
|
||||
);
|
||||
|
||||
const response: Cooperative.Documents.IGetComplexDocuments = {
|
||||
const response: Cooperative.Document.IGetComplexDocuments = {
|
||||
results: [],
|
||||
page,
|
||||
limit,
|
||||
|
||||
@@ -4,7 +4,7 @@ import logger from '../config/logger';
|
||||
|
||||
const { email, env } = config;
|
||||
|
||||
const transport = createTransport(email.smtp);
|
||||
export const transport = createTransport(email.smtp);
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (env !== 'test') {
|
||||
@@ -21,7 +21,7 @@ if (env !== 'test') {
|
||||
* @param {string} text
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const sendEmail = async (to, subject, text) => {
|
||||
export const sendEmail = async (to, subject, text) => {
|
||||
const msg = { from: email.from, to, subject, text };
|
||||
await transport.sendMail(msg);
|
||||
};
|
||||
@@ -32,7 +32,7 @@ const sendEmail = async (to, subject, text) => {
|
||||
* @param {string} token
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const sendResetPasswordEmail = async (to, token) => {
|
||||
export const sendResetKeyEmail = async (to, token) => {
|
||||
const subject = 'Восстановление доступа';
|
||||
|
||||
const resetPasswordUrl = `${config.base_url}/#/${config.coopname}/auth/reset-key?token=${token}`;
|
||||
@@ -44,13 +44,31 @@ const sendResetPasswordEmail = async (to, token) => {
|
||||
await sendEmail(to, subject, text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send reset password email
|
||||
* @param {string} to
|
||||
* @param {string} token
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export const sendInviteEmail = async (to, token) => {
|
||||
const subject = 'Приглашение в Цифровой Кооператив';
|
||||
|
||||
const inviteUrl = `${config.base_url}/#/${config.coopname}/auth/reset-key?token=${token}`;
|
||||
const text = `Вам отправлено приглашение на подключение к Цифровому Кооперативу в качестве действующего пайщика.
|
||||
Для того, чтобы воспользоваться приглашением и получить ключ доступа, пожалуйста, нажмите на ссылку: ${inviteUrl}
|
||||
|
||||
Время действия ссылки - 24 часа.`;
|
||||
|
||||
await sendEmail(to, subject, text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send verification email
|
||||
* @param {string} to
|
||||
* @param {string} token
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const sendVerificationEmail = async (to, token) => {
|
||||
export const sendVerificationEmail = async (to, token) => {
|
||||
const subject = 'Email Verification';
|
||||
// replace this url with the link to the email verification page of your front-end app
|
||||
const verificationEmailUrl = `http://link-to-app/verify-email?token=${token}`;
|
||||
@@ -59,5 +77,3 @@ To verify your email, click on this link: ${verificationEmailUrl}
|
||||
If you did not create an account, then ignore this email.`;
|
||||
await sendEmail(to, subject, text);
|
||||
};
|
||||
|
||||
export { transport, sendEmail, sendResetPasswordEmail, sendVerificationEmail };
|
||||
|
||||
@@ -7,4 +7,5 @@ export * as paymentService from './payment.service';
|
||||
export * as documentService from './document.service';
|
||||
export * as coopService from './coop.service';
|
||||
export * as wsService from './ws.service';
|
||||
export * as monoService from './mono.service';
|
||||
export * as systemService from './system.service';
|
||||
export * as participantService from './participant.service';
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { Mono } from '../models';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import config from '../config/config';
|
||||
import logger from '../config/logger';
|
||||
import { IHealthStatus } from '../types';
|
||||
|
||||
export const init = async (): Promise<void> => {
|
||||
const mono = await Mono.findOne({ coopname: config.coopname });
|
||||
|
||||
if (!mono)
|
||||
await Mono.create({
|
||||
coopname: config.coopname,
|
||||
status: 'install',
|
||||
});
|
||||
|
||||
logger.info('MONO инициализирован');
|
||||
};
|
||||
|
||||
export const getMonoStatus = async (): Promise<IHealthStatus> => {
|
||||
const mono = await Mono.findOne({ coopname: config.coopname });
|
||||
|
||||
if (!mono) throw new ApiError(httpStatus.BAD_REQUEST, 'Установщик не найден');
|
||||
|
||||
return mono.status;
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
import { PublicKey, Signature } from '@wharfkit/antelope';
|
||||
import type { IDocument, IJoinCooperative } from '../types';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import { getUserByUsername } from './user.service';
|
||||
import http from 'http-status';
|
||||
import TempDocument, { tempdocType } from '../models/tempDocument.model';
|
||||
import mongoose from 'mongoose';
|
||||
import { userStatus, type IUser } from '../models/user.model';
|
||||
|
||||
const verifyDocumentSignature = (user: IUser, document: IDocument): void => {
|
||||
const { hash, public_key, signature } = document;
|
||||
const publicKeyObj = PublicKey.from(public_key);
|
||||
const signatureObj = Signature.from(signature);
|
||||
|
||||
const verified: boolean = signatureObj.verifyDigest(hash, publicKeyObj);
|
||||
if (!verified) {
|
||||
throw new ApiError(http.INTERNAL_SERVER_ERROR, 'Invalid signature');
|
||||
}
|
||||
|
||||
if (user.public_key !== document.public_key) throw new ApiError(http.BAD_REQUEST, 'Public keys are mismatched');
|
||||
};
|
||||
|
||||
/**
|
||||
* Join a Cooperative
|
||||
*
|
||||
*/
|
||||
export const joinCooperative = async (data: IJoinCooperative): Promise<void> => {
|
||||
console.log('data: ', data);
|
||||
const user = await getUserByUsername(data.username);
|
||||
|
||||
if (!user) {
|
||||
throw new ApiError(http.NOT_FOUND, 'Пользователь не найден');
|
||||
}
|
||||
|
||||
if (user.status !== userStatus['1_Created'] && user.status !== userStatus['2_Joined']) {
|
||||
throw new ApiError(http.NOT_FOUND, 'Пользователь уже вступил в кооператив');
|
||||
}
|
||||
|
||||
verifyDocumentSignature(user, data.statement);
|
||||
verifyDocumentSignature(user, data.wallet_agreement);
|
||||
verifyDocumentSignature(user, data.user_agreement);
|
||||
verifyDocumentSignature(user, data.privacy_agreement);
|
||||
verifyDocumentSignature(user, data.signature_agreement);
|
||||
|
||||
const session = await mongoose.startSession();
|
||||
|
||||
await session.withTransaction(async () => {
|
||||
await TempDocument.findOneAndUpdate(
|
||||
{ username: user.username, type: tempdocType.JoinStatement },
|
||||
{ $set: { document: data.statement } },
|
||||
{ upsert: true, new: true, session }
|
||||
);
|
||||
|
||||
await TempDocument.findOneAndUpdate(
|
||||
{ username: user.username, type: tempdocType.WalletAgreement },
|
||||
{ $set: { document: data.wallet_agreement } },
|
||||
{ upsert: true, new: true, session }
|
||||
);
|
||||
|
||||
await TempDocument.findOneAndUpdate(
|
||||
{ username: user.username, type: tempdocType.PrivacyAgreement },
|
||||
{ $set: { document: data.privacy_agreement } },
|
||||
{ upsert: true, new: true, session }
|
||||
);
|
||||
|
||||
await TempDocument.findOneAndUpdate(
|
||||
{ username: user.username, type: tempdocType.SignatureAgreement },
|
||||
{ $set: { document: data.signature_agreement } },
|
||||
{ upsert: true, new: true, session }
|
||||
);
|
||||
|
||||
await TempDocument.findOneAndUpdate(
|
||||
{ username: user.username, type: tempdocType.UserAgreement },
|
||||
{ $set: { document: data.user_agreement } },
|
||||
{ upsert: true, new: true, session }
|
||||
);
|
||||
|
||||
user.status = userStatus['2_Joined'];
|
||||
await user.save({ session });
|
||||
});
|
||||
|
||||
session.endSession();
|
||||
};
|
||||
@@ -12,6 +12,7 @@ import httpStatus from 'http-status';
|
||||
import { ICreatedPayment, IYandexIPN, PaymentDetails } from '../types/common';
|
||||
import { Cooperative } from 'cooptypes';
|
||||
import { FilterQuery } from 'mongoose';
|
||||
import { userStatus } from '../models/user.model';
|
||||
|
||||
const { connection } = mongoose;
|
||||
|
||||
@@ -198,7 +199,10 @@ export async function createInitialOrder(username: string, data: ICreateInitialP
|
||||
}
|
||||
|
||||
export async function catchIPN(ipnBody: IYandexIPN) {
|
||||
if (!connection.db) throw new Error('Нет подключения');
|
||||
|
||||
const payments = await connection.db.collection('payments');
|
||||
|
||||
const exist = await payments.findOne({ 'object.id': ipnBody.object.id });
|
||||
|
||||
if (!exist) {
|
||||
@@ -238,7 +242,7 @@ export async function catchIPN(ipnBody: IYandexIPN) {
|
||||
});
|
||||
|
||||
logger.info('Зарегистрирован новый пользователь: ', user.username);
|
||||
user.status = 'registered';
|
||||
user.status = userStatus['4_Registered'];
|
||||
user.is_registered = true;
|
||||
} else if (order.type === 'deposit') {
|
||||
await blockchainService.completeOrder({
|
||||
@@ -268,7 +272,7 @@ export async function catchIPN(ipnBody: IYandexIPN) {
|
||||
memo: '',
|
||||
});
|
||||
|
||||
user.status = 'failed';
|
||||
user.status = userStatus['10_Failed'];
|
||||
user.message = e.message;
|
||||
await user.save();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { Mono } from '../models';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import config from '../config/config';
|
||||
import logger from '../config/logger';
|
||||
import { IAddUser, ICreateUser, IHealthStatus, IInstall } from '../types';
|
||||
import { generateUsername } from '../../tests/utils/generateUsername';
|
||||
import { generator } from './document.service';
|
||||
import { blockchainService, emailService, tokenService, userService } from '.';
|
||||
import { IUser, userStatus } from '../models/user.model';
|
||||
import axios from 'axios';
|
||||
import { getBlockchainInfo } from './blockchain.service';
|
||||
import { RegistratorContract, type Cooperative } from 'cooptypes';
|
||||
import type { ISetVars } from '../types/auto-generated/system.validation';
|
||||
import { VarsSchema } from 'coopdoc-generator-ts';
|
||||
|
||||
export const install = async (soviet: IInstall): Promise<void> => {
|
||||
const mono = await Mono.findOne({ coopname: config.coopname });
|
||||
const info = await getBlockchainInfo();
|
||||
const coop = await blockchainService.getCooperative(config.coopname);
|
||||
|
||||
if (!coop) throw new ApiError(httpStatus.BAD_REQUEST, 'Информация о кооперативе не обнаружена');
|
||||
|
||||
if (mono && mono.status != 'install') {
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'Установка уже выполнена');
|
||||
}
|
||||
|
||||
const users = [] as IUser[];
|
||||
const members = [] as any;
|
||||
const sovietExt = [] as any;
|
||||
|
||||
try {
|
||||
for (const member of soviet) {
|
||||
const username = generateUsername();
|
||||
sovietExt.push({ ...member, username });
|
||||
|
||||
const addUser: RegistratorContract.Actions.AddUser.IAddUser = {
|
||||
registrator: config.service_username,
|
||||
coopname: config.coopname,
|
||||
referer: '',
|
||||
username,
|
||||
type: 'individual',
|
||||
created_at: info.head_block_time,
|
||||
initial: coop.initial,
|
||||
minimum: coop.minimum,
|
||||
spread_initial: false,
|
||||
meta: '',
|
||||
};
|
||||
|
||||
await blockchainService.addUser(addUser);
|
||||
|
||||
const createUser: ICreateUser = {
|
||||
email: member.individual_data.email,
|
||||
individual_data: member.individual_data,
|
||||
referer: '',
|
||||
role: 'user',
|
||||
type: 'individual',
|
||||
username,
|
||||
};
|
||||
|
||||
const user = await userService.createUser(createUser);
|
||||
user.status = userStatus['4_Registered'];
|
||||
user.is_registered = true;
|
||||
await user.save();
|
||||
|
||||
//Генерируем токен и отправляем приглашение
|
||||
const token = await tokenService.generateInviteToken(member.individual_data.email);
|
||||
await emailService.sendInviteEmail(member.individual_data.email, token);
|
||||
|
||||
//Добавляем в массив членов для отправки в бч
|
||||
members.push({
|
||||
username: username,
|
||||
is_voting: true,
|
||||
position_title: member.role === 'chairman' ? 'Председатель совета' : 'Член совета',
|
||||
position: member.role,
|
||||
});
|
||||
|
||||
users.push(user);
|
||||
}
|
||||
|
||||
const chairman = sovietExt.find((el) => el.role == 'chairman');
|
||||
|
||||
//TODO создаёт доску совета
|
||||
await blockchainService.createBoard({
|
||||
coopname: config.coopname,
|
||||
username: config.service_username,
|
||||
type: 'soviet',
|
||||
members: members,
|
||||
name: 'Совет',
|
||||
description: '',
|
||||
});
|
||||
} catch (e: any) {
|
||||
console.log('on error', e);
|
||||
for (const user of users) {
|
||||
await userService.deleteUserByUsername(user.username);
|
||||
await generator.del('individual', { username: user.username });
|
||||
}
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, e.message);
|
||||
}
|
||||
|
||||
await Mono.updateOne(
|
||||
{ coopname: config.coopname },
|
||||
{
|
||||
status: 'active',
|
||||
}
|
||||
);
|
||||
|
||||
logger.info('MONO активирован');
|
||||
};
|
||||
|
||||
export const init = async (): Promise<void> => {
|
||||
const mono = await Mono.findOne({ coopname: config.coopname });
|
||||
|
||||
if (!mono)
|
||||
await Mono.create({
|
||||
coopname: config.coopname,
|
||||
status: 'install',
|
||||
});
|
||||
|
||||
logger.info('MONO инициализирован');
|
||||
};
|
||||
|
||||
export const getMonoStatus = async (): Promise<IHealthStatus> => {
|
||||
const mono = await Mono.findOne({ coopname: config.coopname });
|
||||
|
||||
if (!mono) throw new ApiError(httpStatus.BAD_REQUEST, 'Установщик не найден');
|
||||
|
||||
return mono.status;
|
||||
};
|
||||
|
||||
export const setVars = async (vars: ISetVars): Promise<void> => {
|
||||
await generator.save('vars', vars);
|
||||
};
|
||||
|
||||
export const getVarsSchema = async (): Promise<unknown> => {
|
||||
return VarsSchema;
|
||||
};
|
||||
@@ -48,12 +48,17 @@ export const saveToken = async (token, userId, expires, type, blacklisted = fals
|
||||
/**
|
||||
* Verify token and return token doc (or throw an error if it is not valid)
|
||||
* @param {string} token
|
||||
* @param {string} type
|
||||
* @param {string[]} types
|
||||
* @returns {Promise<Token>}
|
||||
*/
|
||||
export const verifyToken = async (token, type) => {
|
||||
export const verifyToken = async (token, types) => {
|
||||
const payload = jwt.verify(token, config.jwt.secret);
|
||||
const tokenDoc = await Token.findOne({ token, type, user: payload.sub, blacklisted: false });
|
||||
const tokenDoc = await Token.findOne({
|
||||
token,
|
||||
$or: types.map((type) => ({ type })),
|
||||
user: payload.sub,
|
||||
blacklisted: false,
|
||||
});
|
||||
if (!tokenDoc) {
|
||||
throw new Error('Token not found');
|
||||
}
|
||||
@@ -68,7 +73,7 @@ export const verifyToken = async (token, type) => {
|
||||
export const generateServiceAccessToken = async (user) => {
|
||||
const accessTokenExpires = moment().add(100, 'years'); // Пример с очень долгим сроком действия
|
||||
const accessToken = generateToken(user.id, accessTokenExpires, tokenTypes.ACCESS);
|
||||
|
||||
console.log('on generate', accessToken);
|
||||
return {
|
||||
access: {
|
||||
token: accessToken,
|
||||
@@ -107,7 +112,7 @@ export const generateAuthTokens = async (user) => {
|
||||
* @param {string} email
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const generateResetPasswordToken = async (email) => {
|
||||
export const generateResetKeyToken = async (email) => {
|
||||
const user = await userService.getUserByEmail(email);
|
||||
if (!user) {
|
||||
throw new ApiError(httpStatus.NOT_FOUND, 'No users found with this email');
|
||||
@@ -118,6 +123,22 @@ export const generateResetPasswordToken = async (email) => {
|
||||
return resetKeyToken;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate invite token
|
||||
* @param {string} email
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const generateInviteToken = async (email) => {
|
||||
const user = await userService.getUserByEmail(email);
|
||||
if (!user) {
|
||||
throw new ApiError(httpStatus.NOT_FOUND, 'No users found with this email');
|
||||
}
|
||||
const expires = moment().add(config.jwt.inviteExpirationMinutes, 'minutes');
|
||||
const inviteToken = generateToken(user.id, expires, tokenTypes.INVITE);
|
||||
await saveToken(inviteToken, user.id, expires, tokenTypes.INVITE);
|
||||
return inviteToken;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate verify email token
|
||||
* @param {User} user
|
||||
|
||||
@@ -2,21 +2,15 @@ import http from 'http-status';
|
||||
import { User } from '../models';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import { generator } from './document.service';
|
||||
import { ICreateUser, IJoinCooperative } from '../types/auto-generated/user.validation';
|
||||
import ecc from 'eosjs-ecc';
|
||||
import { ICreateUser } from '../types/auto-generated/user.validation';
|
||||
import { PublicKey, Signature } from '@wharfkit/antelope';
|
||||
import faker from 'faker';
|
||||
import { randomBytes } from 'crypto';
|
||||
|
||||
export const createServiceUser = async (username: string) => {
|
||||
const password = randomBytes(16).toString('hex');
|
||||
return User.create({
|
||||
username,
|
||||
type: 'service',
|
||||
role: 'service',
|
||||
public_key: 'thanks-no-need',
|
||||
password,
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -28,6 +22,7 @@ export const createServiceUser = async (username: string) => {
|
||||
export const createUser = async (userBody: ICreateUser) => {
|
||||
//TODO проверяем на существование пользователя
|
||||
//допускаем обновление личных данных, если пользователь находится в статусе 'created'
|
||||
|
||||
const exist = await User.findOne({ email: userBody.email });
|
||||
|
||||
if (userBody.type === 'individual' && !userBody.individual_data)
|
||||
@@ -62,35 +57,6 @@ export const createUser = async (userBody: ICreateUser) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Join a Cooperative
|
||||
*
|
||||
*/
|
||||
export const joinCooperative = async (data: IJoinCooperative): Promise<void> => {
|
||||
const user = await getUserByUsername(data.username);
|
||||
|
||||
if (!user) {
|
||||
throw new ApiError(http.NOT_FOUND, 'Пользователь не найден');
|
||||
}
|
||||
|
||||
user.statement = data.statement;
|
||||
user.status = 'joined';
|
||||
|
||||
const hash = data.statement.hash;
|
||||
const public_key = PublicKey.from(data.statement.public_key);
|
||||
const signature = Signature.from(data.statement.signature);
|
||||
|
||||
const verified: boolean = signature.verifyDigest(hash, public_key);
|
||||
|
||||
if (!verified) {
|
||||
throw new ApiError(http.INTERNAL_SERVER_ERROR, 'Invalid signature');
|
||||
}
|
||||
|
||||
if (user.public_key !== data.statement.public_key) throw new ApiError(http.BAD_REQUEST, 'Public keys are mismatched');
|
||||
|
||||
await user.save();
|
||||
};
|
||||
|
||||
/**
|
||||
* Query for users
|
||||
* @param {Object} filter - Mongo filter
|
||||
@@ -186,7 +152,7 @@ export const updateUserByUsername = async (username, updateBody) => {
|
||||
* @param {string} username
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
export const deleteUserById = async (username) => {
|
||||
export const deleteUserByUsername = async (username) => {
|
||||
const user = await getUserByUsername(username);
|
||||
if (!user) {
|
||||
throw new ApiError(http.NOT_FOUND, 'Пользователь не найден');
|
||||
|
||||
@@ -16,7 +16,9 @@ export const updateBoard = async (action: SovietContract.Actions.Boards.UpdateBo
|
||||
await user.save();
|
||||
}
|
||||
|
||||
const chairman = await userService.getUserByUsername(action.chairman);
|
||||
const chairman_username = action.members.find((el) => el.position == 'chairman')?.username;
|
||||
|
||||
const chairman = await userService.getUserByUsername(chairman_username as string);
|
||||
chairman.role = 'chairman';
|
||||
await chairman.save();
|
||||
};
|
||||
|
||||
@@ -8,13 +8,13 @@ export interface IGenerate {
|
||||
* Unknown Property
|
||||
*/
|
||||
[x: string]: unknown;
|
||||
action: string;
|
||||
block_num?: number;
|
||||
code: string;
|
||||
coopname: string;
|
||||
created_at?: string;
|
||||
generator?: string;
|
||||
lang?: 'ru';
|
||||
links?: string[];
|
||||
registry_id: number;
|
||||
timezone?: string;
|
||||
username: string;
|
||||
version?: string;
|
||||
@@ -39,13 +39,13 @@ export interface RGenerate {
|
||||
* Unknown Property
|
||||
*/
|
||||
[x: string]: unknown;
|
||||
action: string;
|
||||
block_num?: number;
|
||||
code: string;
|
||||
coopname: string;
|
||||
created_at?: string;
|
||||
generator?: string;
|
||||
lang?: 'ru';
|
||||
links?: string[];
|
||||
registry_id: number;
|
||||
timezone?: string;
|
||||
username: string;
|
||||
version?: string;
|
||||
|
||||
@@ -7,5 +7,7 @@ export * from './auth.validation';
|
||||
export * from './coop.validation';
|
||||
export * from './document.validation';
|
||||
export * from './notify.validation';
|
||||
export * from './participant.validation';
|
||||
export * from './payment.validation';
|
||||
export * from './system.validation';
|
||||
export * from './user.validation';
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* This file was automatically generated by joi-to-typescript
|
||||
* Do not modify this file manually
|
||||
*/
|
||||
|
||||
export type IInstall = ({
|
||||
individual_data: {
|
||||
birthdate: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
role: 'chairman' | 'member';
|
||||
})[];
|
||||
|
||||
export interface RInstall {
|
||||
body: ({
|
||||
individual_data: {
|
||||
birthdate: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
role: 'chairman' | 'member';
|
||||
})[];
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* This file was automatically generated by joi-to-typescript
|
||||
* Do not modify this file manually
|
||||
*/
|
||||
|
||||
export interface IDocument {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface IJoinCooperative {
|
||||
privacy_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
signature_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
statement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
user_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
username: string;
|
||||
wallet_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RJoinCooperative {
|
||||
body: {
|
||||
privacy_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
signature_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
statement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
user_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
username: string;
|
||||
wallet_agreement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* This file was automatically generated by joi-to-typescript
|
||||
* Do not modify this file manually
|
||||
*/
|
||||
|
||||
export type IInstall = {
|
||||
individual_data: {
|
||||
birthdate: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
role: 'chairman' | 'member';
|
||||
}[];
|
||||
|
||||
export interface ISetVars {
|
||||
/**
|
||||
* Unknown Property
|
||||
*/
|
||||
[x: string]: unknown;
|
||||
confidential_email: string;
|
||||
confidential_link: string;
|
||||
contact_email: string;
|
||||
coopname: string;
|
||||
full_abbr: string;
|
||||
full_abbr_dative: string;
|
||||
full_abbr_genitive: string;
|
||||
name: string;
|
||||
privacy_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
short_abbr: string;
|
||||
signature_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
user_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
wallet_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
website: string;
|
||||
}
|
||||
|
||||
export interface RInstall {
|
||||
body: {
|
||||
individual_data: {
|
||||
birthdate: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
role: 'chairman' | 'member';
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface RSetVars {
|
||||
body: {
|
||||
/**
|
||||
* Unknown Property
|
||||
*/
|
||||
[x: string]: unknown;
|
||||
confidential_email: string;
|
||||
confidential_link: string;
|
||||
contact_email: string;
|
||||
coopname: string;
|
||||
full_abbr: string;
|
||||
full_abbr_dative: string;
|
||||
full_abbr_genitive: string;
|
||||
name: string;
|
||||
privacy_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
short_abbr: string;
|
||||
signature_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
user_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
wallet_agreement: {
|
||||
protocol_day_month_year: string;
|
||||
protocol_number: string;
|
||||
};
|
||||
website: string;
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,84 @@
|
||||
* Do not modify this file manually
|
||||
*/
|
||||
|
||||
export interface IAddUser {
|
||||
created_at: string;
|
||||
email: string;
|
||||
entrepreneur_data?: {
|
||||
bank_account: {
|
||||
account_number: string;
|
||||
bank_name: string;
|
||||
card_number?: string;
|
||||
currency: 'RUB' | 'Other';
|
||||
details: {
|
||||
bik: string;
|
||||
corr: string;
|
||||
kpp: string;
|
||||
};
|
||||
};
|
||||
birthdate: string;
|
||||
city: string;
|
||||
country: 'Russia' | 'Other';
|
||||
details: {
|
||||
inn: string;
|
||||
ogrn: string;
|
||||
};
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
individual_data?: {
|
||||
birthdate: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
initial: string;
|
||||
minimum: string;
|
||||
organization_data?: {
|
||||
bank_account: {
|
||||
account_number: string;
|
||||
bank_name: string;
|
||||
card_number?: string;
|
||||
currency: 'RUB' | 'Other';
|
||||
details: {
|
||||
bik: string;
|
||||
corr: string;
|
||||
kpp: string;
|
||||
};
|
||||
};
|
||||
city: string;
|
||||
country: 'Russia' | 'Other';
|
||||
details: {
|
||||
inn: string;
|
||||
ogrn: string;
|
||||
};
|
||||
email: string;
|
||||
full_address: string;
|
||||
full_name: string;
|
||||
is_cooperative: boolean;
|
||||
phone: string;
|
||||
represented_by: {
|
||||
based_on: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
position: string;
|
||||
};
|
||||
short_name: string;
|
||||
type: 'coop' | 'ooo' | 'oao' | 'zao' | 'pao' | 'ao';
|
||||
};
|
||||
referer?: string;
|
||||
spread_initial: boolean;
|
||||
type: 'individual' | 'entrepreneur' | 'organization';
|
||||
}
|
||||
|
||||
export interface ICreateUser {
|
||||
email: string;
|
||||
entrepreneur_data?: {
|
||||
@@ -73,21 +151,13 @@ export interface ICreateUser {
|
||||
short_name: string;
|
||||
type: 'coop' | 'ooo' | 'oao' | 'zao' | 'pao' | 'ao';
|
||||
};
|
||||
password: string;
|
||||
public_key: string;
|
||||
public_key?: string;
|
||||
referer?: string;
|
||||
role: 'user' | 'chairman' | 'member';
|
||||
role: 'user';
|
||||
type: 'individual' | 'entrepreneur' | 'organization';
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface IDocument {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface IEntrepreneurData {
|
||||
bank_account: {
|
||||
account_number: string;
|
||||
@@ -125,16 +195,6 @@ export interface IIndividualData {
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export interface IJoinCooperative {
|
||||
statement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface IOrganizationData {
|
||||
bank_account: {
|
||||
account_number: string;
|
||||
@@ -169,6 +229,86 @@ export interface IOrganizationData {
|
||||
type: 'coop' | 'ooo' | 'oao' | 'zao' | 'pao' | 'ao';
|
||||
}
|
||||
|
||||
export interface RAddUser {
|
||||
body: {
|
||||
created_at: string;
|
||||
email: string;
|
||||
entrepreneur_data?: {
|
||||
bank_account: {
|
||||
account_number: string;
|
||||
bank_name: string;
|
||||
card_number?: string;
|
||||
currency: 'RUB' | 'Other';
|
||||
details: {
|
||||
bik: string;
|
||||
corr: string;
|
||||
kpp: string;
|
||||
};
|
||||
};
|
||||
birthdate: string;
|
||||
city: string;
|
||||
country: 'Russia' | 'Other';
|
||||
details: {
|
||||
inn: string;
|
||||
ogrn: string;
|
||||
};
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
individual_data?: {
|
||||
birthdate: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
full_address: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
phone: string;
|
||||
};
|
||||
initial: string;
|
||||
minimum: string;
|
||||
organization_data?: {
|
||||
bank_account: {
|
||||
account_number: string;
|
||||
bank_name: string;
|
||||
card_number?: string;
|
||||
currency: 'RUB' | 'Other';
|
||||
details: {
|
||||
bik: string;
|
||||
corr: string;
|
||||
kpp: string;
|
||||
};
|
||||
};
|
||||
city: string;
|
||||
country: 'Russia' | 'Other';
|
||||
details: {
|
||||
inn: string;
|
||||
ogrn: string;
|
||||
};
|
||||
email: string;
|
||||
full_address: string;
|
||||
full_name: string;
|
||||
is_cooperative: boolean;
|
||||
phone: string;
|
||||
represented_by: {
|
||||
based_on: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
middle_name: string;
|
||||
position: string;
|
||||
};
|
||||
short_name: string;
|
||||
type: 'coop' | 'ooo' | 'oao' | 'zao' | 'pao' | 'ao';
|
||||
};
|
||||
referer?: string;
|
||||
spread_initial: boolean;
|
||||
type: 'individual' | 'entrepreneur' | 'organization';
|
||||
};
|
||||
}
|
||||
|
||||
export interface RCreateUser {
|
||||
body: {
|
||||
email: string;
|
||||
@@ -240,10 +380,9 @@ export interface RCreateUser {
|
||||
short_name: string;
|
||||
type: 'coop' | 'ooo' | 'oao' | 'zao' | 'pao' | 'ao';
|
||||
};
|
||||
password: string;
|
||||
public_key: string;
|
||||
public_key?: string;
|
||||
referer?: string;
|
||||
role: 'user' | 'chairman' | 'member';
|
||||
role: 'user';
|
||||
type: 'individual' | 'entrepreneur' | 'organization';
|
||||
username: string;
|
||||
};
|
||||
@@ -265,22 +404,9 @@ export interface RGetUsers {
|
||||
};
|
||||
}
|
||||
|
||||
export interface RJoinCooperative {
|
||||
body: {
|
||||
statement: {
|
||||
hash: string;
|
||||
meta: object;
|
||||
public_key: string;
|
||||
signature: string;
|
||||
};
|
||||
username: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RUpdateUser {
|
||||
body?: {
|
||||
email?: string;
|
||||
password?: string;
|
||||
};
|
||||
params?: {
|
||||
username: string;
|
||||
|
||||
@@ -59,7 +59,7 @@ export interface ICreatedPayment {
|
||||
details: PaymentDetails;
|
||||
}
|
||||
|
||||
export type IGetResponse<T> = Cooperative.Documents.IGetResponse<T>;
|
||||
export type IGetResponse<T> = Cooperative.Document.IGetResponse<T>;
|
||||
|
||||
export interface IGetActions<T> {
|
||||
results: IAction[];
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import * as Joi from 'joi';
|
||||
|
||||
export const IGenerate = Joi.object({
|
||||
code: Joi.string().required(),
|
||||
action: Joi.string().required(),
|
||||
registry_id: Joi.number().required(),
|
||||
coopname: Joi.string().required(),
|
||||
username: Joi.string().required(),
|
||||
generator: Joi.string().optional(),
|
||||
@@ -11,6 +10,7 @@ export const IGenerate = Joi.object({
|
||||
created_at: Joi.string().optional(),
|
||||
block_num: Joi.number().optional(),
|
||||
timezone: Joi.string().optional(),
|
||||
links: Joi.array().items(Joi.string()).default([]),
|
||||
}).unknown(true);
|
||||
|
||||
export const RGenerate = Joi.object({
|
||||
|
||||
@@ -5,3 +5,5 @@ export * as orderValidation from './payment.validation';
|
||||
export * as coopValidation from './coop.validation';
|
||||
export * as customValidation from './custom.validation';
|
||||
export * as notifyValidation from './notify.validation';
|
||||
export * as systemValidation from './system.validation';
|
||||
export * as participantValidation from './participant.validation';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as Joi from 'joi';
|
||||
|
||||
export const IDocument = Joi.object().keys({
|
||||
hash: Joi.string().required(),
|
||||
signature: Joi.string().required(),
|
||||
public_key: Joi.string().required(),
|
||||
meta: Joi.object().required(),
|
||||
});
|
||||
|
||||
export const IJoinCooperative = Joi.object({
|
||||
username: Joi.string().required(),
|
||||
statement: IDocument.required(),
|
||||
wallet_agreement: IDocument.required(),
|
||||
signature_agreement: IDocument.required(),
|
||||
privacy_agreement: IDocument.required(),
|
||||
user_agreement: IDocument.required(),
|
||||
});
|
||||
|
||||
export const RJoinCooperative = Joi.object({
|
||||
body: IJoinCooperative.required(),
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import * as Joi from 'joi';
|
||||
import { IIndividualData } from './user.validation';
|
||||
|
||||
export const IInstall = Joi.array().items(
|
||||
Joi.object({
|
||||
role: Joi.string().required().valid('chairman', 'member'),
|
||||
individual_data: IIndividualData.required(),
|
||||
})
|
||||
);
|
||||
|
||||
export const RInstall = Joi.object({
|
||||
body: IInstall.required(),
|
||||
});
|
||||
|
||||
export const ISetVars = Joi.object({
|
||||
coopname: Joi.string().required(),
|
||||
full_abbr: Joi.string().required(),
|
||||
full_abbr_genitive: Joi.string().required(),
|
||||
full_abbr_dative: Joi.string().required(),
|
||||
short_abbr: Joi.string().required(),
|
||||
website: Joi.string().required(),
|
||||
name: Joi.string().required(),
|
||||
confidential_link: Joi.string().required(),
|
||||
confidential_email: Joi.string().required(),
|
||||
contact_email: Joi.string().required(),
|
||||
wallet_agreement: Joi.object({
|
||||
protocol_number: Joi.string().required(),
|
||||
protocol_day_month_year: Joi.string().required(),
|
||||
}).required(),
|
||||
signature_agreement: Joi.object({
|
||||
protocol_number: Joi.string().required(),
|
||||
protocol_day_month_year: Joi.string().required(),
|
||||
}).required(),
|
||||
privacy_agreement: Joi.object({
|
||||
protocol_number: Joi.string().required(),
|
||||
protocol_day_month_year: Joi.string().required(),
|
||||
}).required(),
|
||||
user_agreement: Joi.object({
|
||||
protocol_number: Joi.string().required(),
|
||||
protocol_day_month_year: Joi.string().required(),
|
||||
}).required(),
|
||||
}).unknown(true);
|
||||
|
||||
export const RSetVars = Joi.object({
|
||||
body: ISetVars.required(),
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as Joi from 'joi';
|
||||
import { password, objectId } from './custom.validation';
|
||||
import { password } from './custom.validation';
|
||||
import { IBankAccount } from './payment.validation';
|
||||
|
||||
export const IIndividualData = Joi.object({
|
||||
@@ -57,9 +57,8 @@ export const IEntrepreneurData = Joi.object({
|
||||
|
||||
export const ICreateUser = Joi.object({
|
||||
email: Joi.string().required().email(),
|
||||
password: Joi.string().required().custom(password),
|
||||
role: Joi.string().required().valid('user', 'chairman', 'member'),
|
||||
public_key: Joi.string().required(),
|
||||
role: Joi.string().required().valid('user'),
|
||||
public_key: Joi.string().optional(),
|
||||
username: Joi.string().required().length(12),
|
||||
referer: Joi.string().length(12).allow('').optional(),
|
||||
type: Joi.string().required().valid('individual', 'entrepreneur', 'organization'),
|
||||
@@ -68,11 +67,23 @@ export const ICreateUser = Joi.object({
|
||||
entrepreneur_data: IEntrepreneurData.optional(),
|
||||
});
|
||||
|
||||
export const IDocument = Joi.object().keys({
|
||||
hash: Joi.string().required(),
|
||||
signature: Joi.string().required(),
|
||||
public_key: Joi.string().required(),
|
||||
meta: Joi.object().required(),
|
||||
export const IAddUser = Joi.object({
|
||||
email: Joi.string().required().email(),
|
||||
referer: Joi.string().length(12).allow('').optional(),
|
||||
type: Joi.string().required().valid('individual', 'entrepreneur', 'organization'),
|
||||
individual_data: IIndividualData.optional(),
|
||||
organization_data: IOrganizationData.optional(),
|
||||
entrepreneur_data: IEntrepreneurData.optional(),
|
||||
|
||||
spread_initial: Joi.boolean().required(),
|
||||
|
||||
created_at: Joi.string().required(),
|
||||
initial: Joi.string().required(),
|
||||
minimum: Joi.string().required(),
|
||||
});
|
||||
|
||||
export const RAddUser = Joi.object({
|
||||
body: IAddUser.required(),
|
||||
});
|
||||
|
||||
// API
|
||||
@@ -104,20 +115,10 @@ export const RUpdateUser = Joi.object({
|
||||
body: Joi.object()
|
||||
.keys({
|
||||
email: Joi.string().email(),
|
||||
password: Joi.string().custom(password),
|
||||
})
|
||||
.min(1),
|
||||
});
|
||||
|
||||
export const IJoinCooperative = Joi.object({
|
||||
username: Joi.string().required(),
|
||||
statement: IDocument.required(),
|
||||
});
|
||||
|
||||
export const RJoinCooperative = Joi.object({
|
||||
body: IJoinCooperative.required(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import mongoose from 'mongoose';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import faker from 'faker';
|
||||
import User from '../../src/models/user.model';
|
||||
import { generateUsername } from '../utils/generateUsername';
|
||||
import { Cooperative } from 'cooptypes';
|
||||
import { ICreateUser } from '../../src/types';
|
||||
|
||||
const password = 'password1';
|
||||
const email1 = faker.internet.email().toLowerCase();
|
||||
|
||||
export const participantOne: ICreateUser = {
|
||||
email: email1,
|
||||
password,
|
||||
username: generateUsername(),
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
role: 'user',
|
||||
|
||||
+1
-10
@@ -7,10 +7,6 @@ import { Cooperative } from 'cooptypes';
|
||||
import { ICreateUser } from '../../src/types';
|
||||
import { ObjectId } from 'mongodb';
|
||||
|
||||
const password = 'password1';
|
||||
const salt = bcrypt.genSaltSync(8);
|
||||
const hashedPassword = bcrypt.hashSync(password, salt);
|
||||
|
||||
const generateRandomId = () => new mongoose.Types.ObjectId();
|
||||
|
||||
type testUser = Omit<IUser, 'getPrivateData' | 'isPasswordMatch' | 'private_data'> & {
|
||||
@@ -33,7 +29,6 @@ const adminUsername = generateUsername();
|
||||
export const admin: testUser = {
|
||||
_id: generateRandomId(),
|
||||
email: email1,
|
||||
password,
|
||||
status: 'active',
|
||||
has_account: false,
|
||||
message: '',
|
||||
@@ -68,7 +63,6 @@ const usernameOne = generateUsername();
|
||||
export const userOne: testUser = {
|
||||
_id: generateRandomId(),
|
||||
email: email2,
|
||||
password,
|
||||
has_account: false,
|
||||
status: 'active',
|
||||
message: '',
|
||||
@@ -104,7 +98,6 @@ export const userTwo: testUser = {
|
||||
_id: generateRandomId(),
|
||||
email: email3,
|
||||
has_account: false,
|
||||
password,
|
||||
status: 'active',
|
||||
message: '',
|
||||
is_registered: true,
|
||||
@@ -138,7 +131,6 @@ export const chairman: testUser = {
|
||||
_id: generateRandomId(),
|
||||
email: email4,
|
||||
has_account: false,
|
||||
password,
|
||||
status: 'active',
|
||||
message: '',
|
||||
is_registered: true,
|
||||
@@ -171,7 +163,6 @@ export const chairman: testUser = {
|
||||
export const voskhod: testUser = {
|
||||
_id: generateRandomId(),
|
||||
email: email5,
|
||||
password,
|
||||
has_account: false,
|
||||
status: 'active',
|
||||
message: '',
|
||||
@@ -259,7 +250,7 @@ export const insertUsers = async (users: testUser[]) => {
|
||||
for (const user of users) {
|
||||
const { type, individual_data, organization_data, entrepreneur_data, block_num, ...rest } = user;
|
||||
|
||||
await User.insertMany([{ ...rest, type, password: hashedPassword }]);
|
||||
await User.insertMany([{ ...rest, type }]);
|
||||
|
||||
if (type === 'individual' && individual_data) {
|
||||
await insertPrivateIndividualUserData({
|
||||
|
||||
@@ -29,7 +29,6 @@ describe('Auth routes', () => {
|
||||
|
||||
newUser = {
|
||||
email,
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
username: generateUsername(),
|
||||
@@ -50,8 +49,6 @@ describe('Auth routes', () => {
|
||||
test('should return 201 and successfully register user if request data is ok', async () => {
|
||||
const res = await request(app).post('/v1/users').send(newUser).expect(httpStatus.CREATED);
|
||||
|
||||
expect(res.body.user).not.toHaveProperty('password');
|
||||
|
||||
expect(res.body.user).toEqual({
|
||||
id: expect.anything(),
|
||||
email: newUser.email,
|
||||
@@ -76,7 +73,6 @@ describe('Auth routes', () => {
|
||||
|
||||
expect(dbUser).toBeDefined();
|
||||
|
||||
expect(dbUser?.password).not.toBe(newUser.password);
|
||||
expect(dbUser).toMatchObject({ email: newUser.email, role: 'user', is_email_verified: false });
|
||||
|
||||
expect(res.body.tokens).toEqual({
|
||||
@@ -97,26 +93,10 @@ describe('Auth routes', () => {
|
||||
|
||||
await request(app).post('/v1/users').send(newUser).expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 error if password length is less than 8 characters', async () => {
|
||||
newUser.password = 'passwo1';
|
||||
|
||||
await request(app).post('/v1/users').send(newUser).expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 error if password does not contain both letters and numbers', async () => {
|
||||
newUser.password = 'password';
|
||||
|
||||
await request(app).post('/v1/users').send(newUser).expect(httpStatus.BAD_REQUEST);
|
||||
|
||||
newUser.password = '11111111';
|
||||
|
||||
await request(app).post('/v1/users').send(newUser).expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /v1/auth/login', () => {
|
||||
test('should return 200 and login user if email and password match', async () => {
|
||||
test('should return 200 and login user if email and signature match', async () => {
|
||||
await insertUsers([userOne]);
|
||||
|
||||
const now = (await getBlockchainInfo()).head_block_time;
|
||||
@@ -154,10 +134,16 @@ describe('Auth routes', () => {
|
||||
test('should return 401 error if there are no users with that email', async () => {
|
||||
const now = (await getBlockchainInfo()).head_block_time;
|
||||
|
||||
const privateKey = PrivateKey.fromString('5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3');
|
||||
|
||||
const bytes = Bytes.fromString(now, 'utf8');
|
||||
const checksum = Checksum256.hash(bytes);
|
||||
const signature = privateKey.signDigest(checksum);
|
||||
|
||||
const loginCredentials = {
|
||||
now,
|
||||
email: userOne.email,
|
||||
signature: userOne.password,
|
||||
signature,
|
||||
};
|
||||
|
||||
const res = await request(app).post('/v1/auth/login').send(loginCredentials).expect(httpStatus.UNAUTHORIZED);
|
||||
@@ -166,7 +152,9 @@ describe('Auth routes', () => {
|
||||
});
|
||||
|
||||
// test('should return 401 error if signature is wrong', async () => {
|
||||
|
||||
// Восстановить проверку. Необходимо подложить аккаунт тестового юзера в коде вместо обращения к блокчейну.
|
||||
|
||||
// await insertUsers([userOne]);
|
||||
// const now = (await getBlockchainInfo()).head_block_time;
|
||||
// const privateKey = PrivateKey.fromString('5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3');
|
||||
@@ -288,14 +276,14 @@ describe('Auth routes', () => {
|
||||
jest.spyOn(emailService.transport, 'sendMail').mockResolvedValue();
|
||||
});
|
||||
|
||||
test('should return 204 and send reset password email to the user', async () => {
|
||||
test('should return 204 and send reset key email to the user', async () => {
|
||||
await insertUsers([userOne]);
|
||||
const sendResetPasswordEmailSpy = jest.spyOn(emailService, 'sendResetPasswordEmail');
|
||||
const sendResetKeyEmailSpy = jest.spyOn(emailService, 'sendResetKeyEmail');
|
||||
|
||||
await request(app).post('/v1/auth/lost-key').send({ email: userOne.email }).expect(httpStatus.NO_CONTENT);
|
||||
|
||||
expect(sendResetPasswordEmailSpy).toHaveBeenCalledWith(userOne.email, expect.any(String));
|
||||
const resetKeyToken = sendResetPasswordEmailSpy.mock.calls[0][1];
|
||||
expect(sendResetKeyEmailSpy).toHaveBeenCalledWith(userOne.email, expect.any(String));
|
||||
const resetKeyToken = sendResetKeyEmailSpy.mock.calls[0][1];
|
||||
const dbResetPasswordTokenDoc = await Token.findOne({ token: resetKeyToken, user: userOne._id.toString() });
|
||||
expect(dbResetPasswordTokenDoc).toBeDefined();
|
||||
});
|
||||
@@ -314,13 +302,15 @@ describe('Auth routes', () => {
|
||||
});
|
||||
|
||||
describe('POST /v1/auth/reset-key', () => {
|
||||
test('should return 204 and reset the password', async () => {
|
||||
test('should return 204 and reset the key', async () => {
|
||||
await insertUsers([userOne]);
|
||||
const expires = moment().add(config.jwt.resetPasswordExpirationMinutes, 'minutes');
|
||||
const resetKeyToken = tokenService.generateToken(userOne._id, expires, tokenTypes.RESET_PASSWORD);
|
||||
await tokenService.saveToken(resetKeyToken, userOne._id, expires, tokenTypes.RESET_PASSWORD);
|
||||
|
||||
const res = await request(app).post('/v1/auth/reset-key').send({ token: resetKeyToken, password: 'password2' });
|
||||
const res = await request(app)
|
||||
.post('/v1/auth/reset-key')
|
||||
.send({ token: resetKeyToken, public_key: userOne.public_key });
|
||||
|
||||
expect(res.status).toBe(httpStatus.NO_CONTENT);
|
||||
|
||||
@@ -328,9 +318,6 @@ describe('Auth routes', () => {
|
||||
expect(dbUser).not.toBeUndefined();
|
||||
|
||||
if (dbUser) {
|
||||
const isPasswordMatch = await bcrypt.compare('password2', dbUser.password);
|
||||
expect(isPasswordMatch).toBe(true);
|
||||
|
||||
const dbResetPasswordTokenCount = await Token.countDocuments({
|
||||
user: userOne._id.toString(),
|
||||
type: tokenTypes.RESET_PASSWORD,
|
||||
@@ -339,13 +326,16 @@ describe('Auth routes', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('should return 400 if reset password token is missing', async () => {
|
||||
test('should return 400 if reset key token is missing', async () => {
|
||||
await insertUsers([userOne]);
|
||||
|
||||
await request(app).post('/v1/auth/reset-key').send({ password: 'password2' }).expect(httpStatus.BAD_REQUEST);
|
||||
await request(app)
|
||||
.post('/v1/auth/reset-key')
|
||||
.send({ public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV' })
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 401 if reset password token is blacklisted', async () => {
|
||||
test('should return 401 if reset key token is blacklisted', async () => {
|
||||
await insertUsers([userOne]);
|
||||
const expires = moment().add(config.jwt.resetPasswordExpirationMinutes, 'minutes');
|
||||
const resetKeyToken = tokenService.generateToken(userOne._id, expires, tokenTypes.RESET_PASSWORD);
|
||||
@@ -357,7 +347,7 @@ describe('Auth routes', () => {
|
||||
.expect(httpStatus.UNAUTHORIZED);
|
||||
});
|
||||
|
||||
test('should return 401 if reset password token is expired', async () => {
|
||||
test('should return 401 if reset key token is expired', async () => {
|
||||
await insertUsers([userOne]);
|
||||
const expires = moment().subtract(1, 'minutes');
|
||||
const resetKeyToken = tokenService.generateToken(userOne._id, expires, tokenTypes.RESET_PASSWORD);
|
||||
@@ -379,30 +369,6 @@ describe('Auth routes', () => {
|
||||
.send({ token: resetKeyToken, public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV' })
|
||||
.expect(httpStatus.UNAUTHORIZED);
|
||||
});
|
||||
|
||||
test('should return 400 if password is missing or invalid', async () => {
|
||||
await insertUsers([userOne]);
|
||||
const expires = moment().add(config.jwt.resetPasswordExpirationMinutes, 'minutes');
|
||||
const resetKeyToken = tokenService.generateToken(userOne._id, expires, tokenTypes.RESET_PASSWORD);
|
||||
await tokenService.saveToken(resetKeyToken, userOne._id, expires, tokenTypes.RESET_PASSWORD);
|
||||
|
||||
await request(app).post('/v1/auth/reset-key').send({ token: resetKeyToken }).expect(httpStatus.BAD_REQUEST);
|
||||
|
||||
await request(app)
|
||||
.post('/v1/auth/reset-key')
|
||||
.send({ token: resetKeyToken, public_key: 'stort' })
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
|
||||
await request(app)
|
||||
.post('/v1/auth/reset-key')
|
||||
.send({ token: resetKeyToken, public_key: 'password' })
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
|
||||
await request(app)
|
||||
.post('/v1/auth/reset-key')
|
||||
.send({ token: resetKeyToken, public_key: '11111111' })
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /v1/auth/send-verification-email', () => {
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('Проверка получения документов', () => {
|
||||
skip_save: false,
|
||||
};
|
||||
|
||||
let res = await request(app)
|
||||
const res = await request(app)
|
||||
.post('/v1/documents/generate')
|
||||
.set('Authorization', `Bearer ${registeredUser.body.tokens.access.token}`)
|
||||
.send(options);
|
||||
|
||||
@@ -26,7 +26,6 @@ describe('Проверка данных', () => {
|
||||
const email = faker.internet.email().toLowerCase();
|
||||
newUser = {
|
||||
email: email,
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
username: generateUsername(),
|
||||
@@ -51,7 +50,6 @@ describe('Проверка данных', () => {
|
||||
const email = faker.internet.email().toLowerCase();
|
||||
newUser = {
|
||||
email: email,
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
username: generateUsername(),
|
||||
|
||||
@@ -67,7 +67,6 @@ describe('Проверка получения документов', () => {
|
||||
const email = faker.internet.email().toLowerCase();
|
||||
const newUser = {
|
||||
email: email,
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
username: generateUsername(),
|
||||
|
||||
@@ -4,10 +4,10 @@ import app from '../../src/app';
|
||||
import { setupTestDB } from '../utils/setupTestDB';
|
||||
import { User } from '../../src/models';
|
||||
import { userOne, userTwo, admin, insertUsers } from '../fixtures/user.fixture';
|
||||
import { userOneAccessToken, adminAccessToken } from '../fixtures/token.fixture';
|
||||
import { userOneAccessToken, adminAccessToken, userTwoAccessToken } from '../fixtures/token.fixture';
|
||||
import request from 'supertest';
|
||||
import { generateUsername } from '../utils/generateUsername';
|
||||
import { IDocument, IIndividualData, IJoinCooperative } from '../../src/types';
|
||||
import { IIndividualData } from '../../src/types';
|
||||
|
||||
setupTestDB();
|
||||
|
||||
@@ -19,7 +19,6 @@ describe('User routes', () => {
|
||||
const email = faker.internet.email().toLowerCase();
|
||||
newUser = {
|
||||
email: email,
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
username: generateUsername(),
|
||||
@@ -51,11 +50,9 @@ describe('User routes', () => {
|
||||
expect(res.body.user).toBeDefined();
|
||||
expect(res.body.tokens).toBeDefined();
|
||||
|
||||
expect(res.body.user).not.toHaveProperty('password');
|
||||
|
||||
const dbUser = await User.findOne({ username: newUser.username });
|
||||
expect(dbUser).toBeDefined();
|
||||
expect(dbUser?.password).not.toBe(newUser.password);
|
||||
|
||||
const privateData = (await dbUser?.getPrivateData()) as IIndividualData;
|
||||
expect(privateData).toBeDefined();
|
||||
|
||||
@@ -65,23 +62,15 @@ describe('User routes', () => {
|
||||
expect(dbUser?.toObject()).toMatchObject({ email: newUser.email, role: newUser.role, is_email_verified: false });
|
||||
});
|
||||
|
||||
test('should be able to create an admin as well', async () => {
|
||||
test('should not be able to create an admin as well', async () => {
|
||||
await insertUsers([admin]);
|
||||
newUser.role = 'member';
|
||||
|
||||
const res = await request(app)
|
||||
await request(app)
|
||||
.post('/v1/users')
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(newUser)
|
||||
.expect(httpStatus.CREATED);
|
||||
|
||||
expect(res.body.user).toBeDefined();
|
||||
expect(res.body.tokens).toBeDefined();
|
||||
|
||||
expect(res.body.user.role).toBe('member');
|
||||
|
||||
const dbUser = await User.findOne({ username: newUser.username });
|
||||
expect(dbUser?.role).toBe('member');
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('успешная регистрация без токена доступа', async () => {
|
||||
@@ -122,36 +111,6 @@ describe('User routes', () => {
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 error if password length is less than 8 characters', async () => {
|
||||
await insertUsers([admin]);
|
||||
newUser.password = 'passwo1';
|
||||
|
||||
await request(app)
|
||||
.post('/v1/users')
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(newUser)
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 error if password does not contain both letters and numbers', async () => {
|
||||
await insertUsers([admin]);
|
||||
newUser.password = 'password';
|
||||
|
||||
await request(app)
|
||||
.post('/v1/users')
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(newUser)
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
|
||||
newUser.password = '1111111';
|
||||
|
||||
await request(app)
|
||||
.post('/v1/users')
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(newUser)
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 error if role is neither user nor admin', async () => {
|
||||
await insertUsers([admin]);
|
||||
newUser.role = 'invalid';
|
||||
@@ -164,6 +123,71 @@ describe('User routes', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /v1/users/add', () => {
|
||||
let newUser;
|
||||
|
||||
beforeEach(() => {
|
||||
const email = faker.internet.email().toLowerCase();
|
||||
newUser = {
|
||||
email: email,
|
||||
referer: '',
|
||||
type: 'individual',
|
||||
individual_data: {
|
||||
first_name: faker.name.firstName(),
|
||||
last_name: faker.name.lastName(),
|
||||
middle_name: '',
|
||||
birthdate: '2023-04-01',
|
||||
phone: '+1234567890',
|
||||
email: email,
|
||||
full_address: 'Russia, Moscow, Tverskaya street, 10',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
test('should return 201 and successfully add new user if data is ok', async () => {
|
||||
await insertUsers([admin]);
|
||||
|
||||
const res = await request(app).post('/v1/users/add').set('Authorization', `Bearer ${adminAccessToken}`).send(newUser);
|
||||
|
||||
// if (res.status !== httpStatus.CREATED) {
|
||||
// console.error(res.body); // Выводит тело ответа, если статус не CREATED
|
||||
// }
|
||||
|
||||
expect(res.status).toBe(httpStatus.CREATED);
|
||||
|
||||
expect(res.body.user).toBeDefined();
|
||||
expect(res.body.user.username).toBeDefined();
|
||||
|
||||
const dbUser = await User.findOne({ username: res.body.user.username });
|
||||
expect(dbUser).toBeDefined();
|
||||
|
||||
const privateData = (await dbUser?.getPrivateData()) as IIndividualData;
|
||||
expect(privateData).toBeDefined();
|
||||
|
||||
expect(privateData.first_name).toEqual(newUser.individual_data?.first_name);
|
||||
expect(privateData.last_name).toEqual(newUser.individual_data?.last_name);
|
||||
|
||||
expect(dbUser?.toObject()).toMatchObject({ email: newUser.email, role: 'user', is_email_verified: false });
|
||||
});
|
||||
|
||||
test('should return 403 if service user is not admin but data new user is ok', async () => {
|
||||
await insertUsers([userTwo]);
|
||||
|
||||
const res = await request(app)
|
||||
.post('/v1/users/add')
|
||||
.set('Authorization', `Bearer ${userTwoAccessToken}`)
|
||||
.send(newUser);
|
||||
|
||||
expect(res.status).toBe(httpStatus.FORBIDDEN);
|
||||
});
|
||||
|
||||
test('should return 401 if service user is not have access token', async () => {
|
||||
const res = await request(app).post('/v1/users/add').send(newUser);
|
||||
|
||||
expect(res.status).toBe(httpStatus.UNAUTHORIZED);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /v1/users', () => {
|
||||
test('should return 200 and apply the default query options', async () => {
|
||||
await insertUsers([userOne, userTwo, admin]);
|
||||
@@ -513,7 +537,6 @@ describe('User routes', () => {
|
||||
await insertUsers([userOne]);
|
||||
const updateBody = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'newPassword1',
|
||||
};
|
||||
|
||||
const res = await request(app)
|
||||
@@ -528,7 +551,6 @@ describe('User routes', () => {
|
||||
await insertUsers([userOne, admin]);
|
||||
const updateBody = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'newPassword1',
|
||||
};
|
||||
|
||||
const res = await request(app)
|
||||
@@ -542,7 +564,6 @@ describe('User routes', () => {
|
||||
|
||||
const dbUser = await User.findById(userOne._id);
|
||||
expect(dbUser).toBeDefined();
|
||||
expect(dbUser?.password).not.toBe(updateBody.password);
|
||||
expect(dbUser).toMatchObject({ email: updateBody.email, role: 'user' });
|
||||
});
|
||||
|
||||
@@ -550,7 +571,6 @@ describe('User routes', () => {
|
||||
await insertUsers([userOne]);
|
||||
const updateBody = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'newPassword1',
|
||||
};
|
||||
|
||||
await request(app).patch(`/v1/users/${userOne.username}`).send(updateBody).expect(httpStatus.UNAUTHORIZED);
|
||||
@@ -560,7 +580,6 @@ describe('User routes', () => {
|
||||
await insertUsers([userOne, userTwo]);
|
||||
const updateBody = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'newPassword1',
|
||||
};
|
||||
|
||||
await request(app)
|
||||
@@ -574,7 +593,6 @@ describe('User routes', () => {
|
||||
await insertUsers([userOne, admin]);
|
||||
const updateBody = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'newPassword1',
|
||||
};
|
||||
|
||||
await request(app)
|
||||
@@ -588,7 +606,6 @@ describe('User routes', () => {
|
||||
await insertUsers([admin]);
|
||||
const updateBody = {
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'newPassword1',
|
||||
};
|
||||
|
||||
await request(app)
|
||||
@@ -600,7 +617,7 @@ describe('User routes', () => {
|
||||
|
||||
test('should return 400 if email is invalid', async () => {
|
||||
await insertUsers([userOne, admin]);
|
||||
const updateBody = { email: 'invalidEmail', password: 'GoodPassword!23' };
|
||||
const updateBody = { email: 'invalidEmail' };
|
||||
|
||||
await request(app)
|
||||
.patch(`/v1/users/${userOne.username}`)
|
||||
@@ -611,7 +628,7 @@ describe('User routes', () => {
|
||||
|
||||
test('should return 400 if email is already taken', async () => {
|
||||
await insertUsers([userOne, userTwo, admin]);
|
||||
const updateBody = { email: userTwo.email, password: 'GoodPassword!23' };
|
||||
const updateBody = { email: userTwo.email };
|
||||
|
||||
await request(app)
|
||||
.patch(`/v1/users/${userOne.username}`)
|
||||
@@ -620,41 +637,9 @@ describe('User routes', () => {
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 if password length is less than 8 characters', async () => {
|
||||
await insertUsers([userOne, admin]);
|
||||
const updateBody = { password: 'passwo1' };
|
||||
|
||||
await request(app)
|
||||
.patch(`/v1/users/${userOne.username}`)
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(updateBody)
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
test('should return 400 if password does not contain both letters and numbers', async () => {
|
||||
await insertUsers([userOne, admin]);
|
||||
const updateBody = { password: 'password' };
|
||||
|
||||
await request(app)
|
||||
.patch(`/v1/users/${userOne.username}`)
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(updateBody)
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
|
||||
updateBody.password = '11111111';
|
||||
|
||||
await request(app)
|
||||
.patch(`/v1/users/${userOne.username}`)
|
||||
.set('Authorization', `Bearer ${adminAccessToken}`)
|
||||
.send(updateBody)
|
||||
.expect(httpStatus.BAD_REQUEST);
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
test('should return 400 if email is my email then taken', async () => {
|
||||
await insertUsers([userOne, admin]);
|
||||
const updateBody = { email: userOne.email, password: 'veryStrongPassword!2' };
|
||||
const updateBody = { email: userOne.email };
|
||||
|
||||
await request(app)
|
||||
.patch(`/v1/users/${userOne.username}`)
|
||||
|
||||
@@ -10,7 +10,6 @@ describe('User model', () => {
|
||||
newUser = {
|
||||
name: faker.name.findName(),
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
type: 'individual',
|
||||
@@ -27,36 +26,9 @@ describe('User model', () => {
|
||||
await expect(new User(newUser).validate()).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should throw a validation error if password length is less than 8 characters', async () => {
|
||||
newUser.password = 'passwo1';
|
||||
await expect(new User(newUser).validate()).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should throw a validation error if password does not contain numbers', async () => {
|
||||
newUser.password = 'password';
|
||||
await expect(new User(newUser).validate()).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should throw a validation error if password does not contain letters', async () => {
|
||||
newUser.password = '11111111';
|
||||
await expect(new User(newUser).validate()).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should throw a validation error if role is unknown', async () => {
|
||||
newUser.role = 'invalid';
|
||||
await expect(new User(newUser).validate()).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('User toJSON()', () => {
|
||||
test('should not return user password when toJSON is called', () => {
|
||||
const newUser = {
|
||||
name: faker.name.findName(),
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: 'password1',
|
||||
role: 'user',
|
||||
};
|
||||
expect(new User(newUser).toJSON()).not.toHaveProperty('password');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.0.78](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.77...coopdoc-generator-ts@1.0.78) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopdoc-generator-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.77](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.76...coopdoc-generator-ts@1.0.77) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopdoc-generator-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.76](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.75...coopdoc-generator-ts@1.0.76) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopdoc-generator-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.75](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.75-alpha.1...coopdoc-generator-ts@1.0.75) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopdoc-generator-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.74](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.73...coopdoc-generator-ts@1.0.74) (2024-08-13)
|
||||
|
||||
**Note:** Version bump only for package coopdoc-generator-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.73](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.73-alpha.0...coopdoc-generator-ts@1.0.73) (2024-08-05)
|
||||
|
||||
**Note:** Version bump only for package coopdoc-generator-ts
|
||||
|
||||
@@ -3,6 +3,11 @@ import { defineBuildConfig } from 'unbuild'
|
||||
export default defineBuildConfig({
|
||||
entries: [
|
||||
'src/index',
|
||||
// {
|
||||
// input: 'src/Templates/index',
|
||||
// outDir: 'dist',
|
||||
// name: 'Templates',
|
||||
// },
|
||||
],
|
||||
declaration: true,
|
||||
clean: false,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "coopdoc-generator-ts",
|
||||
"type": "module",
|
||||
"version": "1.0.73",
|
||||
"private": true,
|
||||
"version": "1.0.11-alpha.0",
|
||||
"private": false,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "",
|
||||
"author": "Alex Ant <chairman.voskhod@gmail.com>",
|
||||
@@ -17,6 +17,7 @@
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
@@ -49,8 +50,7 @@
|
||||
"ajv-formats": "^3.0.1",
|
||||
"ajv-i18n": "^4.2.0",
|
||||
"axios": "^1.7.2",
|
||||
"cooparser-ts": "workspace:*",
|
||||
"cooptypes": "workspace:*",
|
||||
"cooptypes": "^1.0.22-alpha.6",
|
||||
"dotenv": "^16.4.5",
|
||||
"eosjs-ecc": "^4.0.7",
|
||||
"handlebars": "^4.7.8",
|
||||
@@ -90,5 +90,6 @@
|
||||
"tar@<6.2.1": ">=6.2.1",
|
||||
"vite@>=5.1.0 <=5.1.6": ">=5.1.7"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitHead": "39ad600d008966ddb7f73587987905c47958e4b3"
|
||||
}
|
||||
|
||||
-7455
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
import { DraftContract } from 'cooptypes'
|
||||
import { WalletAgreement } from '../templates'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type { IGeneratedDocument, IMetaDocument, ITemplate } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
|
||||
export { WalletAgreement as Template } from '../templates'
|
||||
|
||||
export class Factory extends DocFactory<WalletAgreement.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(options: WalletAgreement.Action): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<WalletAgreement.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = WalletAgreement.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(DraftContract.contractName.production, WalletAgreement.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const meta: IMetaDocument = await super.getMeta({ title: template.title, ...options })
|
||||
const coop = await super.getCooperative(options.coopname, options.block_num)
|
||||
const vars = await super.getVars(options.coopname, options.block_num)
|
||||
|
||||
const combinedData: WalletAgreement.Model = {
|
||||
meta,
|
||||
coop,
|
||||
vars,
|
||||
}
|
||||
|
||||
await super.validate(combinedData, template.model)
|
||||
const translation = template.translations[meta.lang]
|
||||
|
||||
const document: IGeneratedDocument = await super.generatePDF(null, template.context, combinedData, translation, meta)
|
||||
await super.saveDraft(document)
|
||||
return document
|
||||
}
|
||||
}
|
||||
+15
-13
@@ -1,26 +1,25 @@
|
||||
import type { IJoinCoopAction } from '../Templates/100.ParticipantApplication'
|
||||
import { DraftContract } from 'cooptypes'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type { IGeneratedDocument, IMetaDocument, ITemplate } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
import { ParticipantApplicationTemplate } from '../Templates/100.ParticipantApplication'
|
||||
import DataService from '../Services/Databazor/DataService'
|
||||
import type { IGenerateJoinCoop } from '../Interfaces/Actions'
|
||||
import { ParticipantApplication } from '../templates'
|
||||
|
||||
export const registry_id = 100
|
||||
export { ParticipantApplication as Template } from '../templates'
|
||||
|
||||
export class JoinCoopTemplateFactory extends DocFactory {
|
||||
export class Factory extends DocFactory<ParticipantApplication.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(options: IGenerateJoinCoop): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<IJoinCoopAction>
|
||||
async generateDocument(options: ParticipantApplication.Action): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<ParticipantApplication.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = ParticipantApplicationTemplate
|
||||
template = ParticipantApplication.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(registry_id, options.block_num)
|
||||
template = await this.getTemplate(DraftContract.contractName.production, ParticipantApplication.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const user = await super.getUser(options.username, options.block_num)
|
||||
@@ -32,8 +31,11 @@ export class JoinCoopTemplateFactory extends DocFactory {
|
||||
const coop = await super.getCooperative(options.coopname, options.block_num)
|
||||
|
||||
let { signature, ...modifiedOptions } = options
|
||||
const meta: IMetaDocument = await super.getMeta({ title: template.title, ...modifiedOptions }) // Генерируем мета-данные
|
||||
|
||||
const meta: IMetaDocument = await super.getMeta({ registry_id, title: template.title, ...modifiedOptions }) // Генерируем мета-данные
|
||||
console.log('generator options: ', options)
|
||||
|
||||
console.log('generator meta: ', meta)
|
||||
|
||||
interface SignatureData {
|
||||
username: string
|
||||
@@ -41,7 +43,7 @@ export class JoinCoopTemplateFactory extends DocFactory {
|
||||
signature: string
|
||||
}
|
||||
|
||||
const data_service = new DataService<SignatureData>(this.storage, 'SignatureData')
|
||||
const data_service = new DataService<SignatureData>(this.storage, 'signatures')
|
||||
|
||||
// пропуск сохранения необходим при вступлении для того, чтобы подготовить документ только для отображения без сохранения
|
||||
if (!options.skip_save) {
|
||||
@@ -59,12 +61,12 @@ export class JoinCoopTemplateFactory extends DocFactory {
|
||||
}
|
||||
else {
|
||||
// если подпись указана - сохраняем в хранилище
|
||||
const data_service = new DataService<SignatureData>(this.storage, 'SignatureData')
|
||||
const data_service = new DataService<SignatureData>(this.storage, 'signatures')
|
||||
await data_service.save({ username: options.username, block_num: meta.block_num, signature })
|
||||
}
|
||||
}
|
||||
|
||||
const combinedData: IJoinCoopAction = { ...userData, meta, coop, type: user.type, signature }
|
||||
const combinedData: ParticipantApplication.Model = { ...userData, meta, coop, type: user.type, signature }
|
||||
|
||||
// валидируем скомбинированные данные
|
||||
await super.validate(combinedData, template.model)
|
||||
@@ -0,0 +1,44 @@
|
||||
import { DraftContract } from 'cooptypes'
|
||||
import { RegulationElectronicSignature } from '../templates'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type { IGeneratedDocument, IMetaDocument, ITemplate } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
|
||||
export { RegulationElectronicSignature as Template } from '../templates'
|
||||
|
||||
export class Factory extends DocFactory<RegulationElectronicSignature.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(options: RegulationElectronicSignature.Action): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<RegulationElectronicSignature.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = RegulationElectronicSignature.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(DraftContract.contractName.production, RegulationElectronicSignature.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const meta: IMetaDocument = await super.getMeta({ title: template.title, ...options })
|
||||
const coop = await super.getCooperative(options.coopname, options.block_num)
|
||||
const vars = await super.getVars(options.coopname, options.block_num)
|
||||
|
||||
const combinedData: RegulationElectronicSignature.Model = {
|
||||
meta,
|
||||
coop,
|
||||
vars,
|
||||
}
|
||||
|
||||
await super.validate(combinedData, template.model)
|
||||
|
||||
const translation = template.translations[meta.lang]
|
||||
|
||||
const document: IGeneratedDocument = await super.generatePDF(null, template.context, combinedData, translation, meta)
|
||||
|
||||
await super.saveDraft(document)
|
||||
|
||||
return document
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { DraftContract } from 'cooptypes'
|
||||
import { PrivacyPolicy } from '../templates'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type { IGeneratedDocument, IMetaDocument, ITemplate } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
|
||||
export { PrivacyPolicy as Template } from '../templates'
|
||||
|
||||
export class Factory extends DocFactory<PrivacyPolicy.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(options: PrivacyPolicy.Action): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<PrivacyPolicy.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = PrivacyPolicy.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(DraftContract.contractName.production, PrivacyPolicy.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const meta: IMetaDocument = await super.getMeta({ title: template.title, ...options })
|
||||
const coop = await super.getCooperative(options.coopname, options.block_num)
|
||||
const vars = await super.getVars(options.coopname, options.block_num)
|
||||
|
||||
const combinedData: PrivacyPolicy.Model = {
|
||||
meta,
|
||||
coop,
|
||||
vars,
|
||||
}
|
||||
|
||||
await super.validate(combinedData, template.model)
|
||||
|
||||
const translation = template.translations[meta.lang]
|
||||
|
||||
const document: IGeneratedDocument = await super.generatePDF(null, template.context, combinedData, translation, meta)
|
||||
|
||||
await super.saveDraft(document)
|
||||
|
||||
return document
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { DraftContract } from 'cooptypes'
|
||||
import { UserAgreement } from '../templates'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type { IGeneratedDocument, IMetaDocument, ITemplate } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
|
||||
export { UserAgreement as Template } from '../templates'
|
||||
|
||||
export class Factory extends DocFactory<UserAgreement.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(options: UserAgreement.Action): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<UserAgreement.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = UserAgreement.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(DraftContract.contractName.production, UserAgreement.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const meta: IMetaDocument = await super.getMeta({ title: template.title, ...options })
|
||||
const coop = await super.getCooperative(options.coopname, options.block_num)
|
||||
const vars = await super.getVars(options.coopname, options.block_num)
|
||||
const user = await super.getUser(options.username, options.block_num)
|
||||
const full_name = super.getFullName(user.data)
|
||||
|
||||
const combinedData: UserAgreement.Model = {
|
||||
meta,
|
||||
coop,
|
||||
vars,
|
||||
user: {
|
||||
full_name,
|
||||
},
|
||||
}
|
||||
|
||||
await super.validate(combinedData, template.model)
|
||||
|
||||
const translation = template.translations[meta.lang]
|
||||
|
||||
const document: IGeneratedDocument = await super.generatePDF(null, template.context, combinedData, translation, meta)
|
||||
|
||||
await super.saveDraft(document)
|
||||
|
||||
return document
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { CoopenomicsAgreement } from '../templates'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type { IGeneratedDocument, IMetaDocument, ITemplate } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
|
||||
export { CoopenomicsAgreement as Template } from '../templates'
|
||||
|
||||
export class Factory extends DocFactory<CoopenomicsAgreement.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(options: CoopenomicsAgreement.Action): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<CoopenomicsAgreement.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = CoopenomicsAgreement.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(options.coopname, CoopenomicsAgreement.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const meta: IMetaDocument = await super.getMeta({ title: template.title, ...options })
|
||||
const coop = await super.getCooperative(options.coopname, options.block_num)
|
||||
const vars = await super.getVars(options.coopname, options.block_num)
|
||||
const partner = await super.getOrganization(options.coopname, options.block_num)
|
||||
|
||||
const combinedData: CoopenomicsAgreement.Model = {
|
||||
meta,
|
||||
coop,
|
||||
vars,
|
||||
partner,
|
||||
}
|
||||
|
||||
await super.validate(combinedData, template.model)
|
||||
|
||||
const translation = template.translations[meta.lang]
|
||||
|
||||
const document: IGeneratedDocument = await super.generatePDF(null, template.context, combinedData, translation, meta)
|
||||
|
||||
await super.saveDraft(document)
|
||||
|
||||
return document
|
||||
}
|
||||
}
|
||||
+11
-13
@@ -1,32 +1,31 @@
|
||||
import type { IJoinCoopDecisionAction } from '../Templates/501.DecisionOfParticipantApplication'
|
||||
import { type Cooperative, DraftContract } from 'cooptypes'
|
||||
import { DocFactory } from '../Factory'
|
||||
import type {
|
||||
IDecisionData,
|
||||
IGeneratedDocument,
|
||||
IMetaDocument,
|
||||
ITemplate,
|
||||
} from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
import { DecisionOfParticipantApplicationTemplate } from '../Templates/501.DecisionOfParticipantApplication'
|
||||
import type { IGenerateJoinCoopDecision } from '../Interfaces/Actions'
|
||||
|
||||
export const registry_id = 501
|
||||
import { DecisionOfParticipantApplication } from '../templates'
|
||||
|
||||
export class DecisionOfJoinCoopTemplateFactory extends DocFactory {
|
||||
export { DecisionOfParticipantApplication as Template } from '../templates'
|
||||
|
||||
export class Factory extends DocFactory<DecisionOfParticipantApplication.Action> {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
super(storage)
|
||||
}
|
||||
|
||||
async generateDocument(
|
||||
options: IGenerateJoinCoopDecision,
|
||||
options: DecisionOfParticipantApplication.Action,
|
||||
): Promise<IGeneratedDocument> {
|
||||
let template: ITemplate<IJoinCoopDecisionAction>
|
||||
let template: ITemplate<DecisionOfParticipantApplication.Model>
|
||||
|
||||
if (process.env.SOURCE === 'local') {
|
||||
template = DecisionOfParticipantApplicationTemplate
|
||||
template = DecisionOfParticipantApplication.Template
|
||||
}
|
||||
else {
|
||||
template = await this.getTemplate(registry_id, options.block_num)
|
||||
template = await this.getTemplate(DraftContract.contractName.production, DecisionOfParticipantApplication.registry_id, options.block_num)
|
||||
}
|
||||
|
||||
const user = await super.getUser(options.username, options.block_num)
|
||||
@@ -39,19 +38,18 @@ export class DecisionOfJoinCoopTemplateFactory extends DocFactory {
|
||||
|
||||
// TODO необходимо строго типизировать мета-данные документов друг под друга!
|
||||
const meta: IMetaDocument = await super.getMeta({
|
||||
registry_id,
|
||||
title: template.title,
|
||||
...options,
|
||||
}) // Генерируем мета-данные
|
||||
|
||||
const decision: IDecisionData = await super.getDecision(
|
||||
const decision: Cooperative.Document.IDecisionData = await super.getDecision(
|
||||
coop,
|
||||
options.coopname,
|
||||
options.decision_id,
|
||||
meta.created_at,
|
||||
)
|
||||
|
||||
const combinedData: IJoinCoopDecisionAction = {
|
||||
const combinedData: DecisionOfParticipantApplication.Model = {
|
||||
...userData,
|
||||
meta,
|
||||
coop,
|
||||
@@ -1,2 +1,8 @@
|
||||
export * as JoinCoop from './registrator.joincoop'
|
||||
export * as JoinCoopDecision from './registrator.joincoopdec'
|
||||
export * as WalletAgreement from './1.WalletAgreement'
|
||||
export * as RegulationElectronicSignature from './2.RegulationElectronicSignature'
|
||||
export * as PrivacyPolicy from './3.PrivacyPolicy'
|
||||
export * as UserAgreement from './4.UserAgreement'
|
||||
export * as CoopenomicsAgreement from './50.CoopenomicsAgreement'
|
||||
|
||||
export * as ParticipantApplication from './100.ParticipantApplication'
|
||||
export * as DecisionOfParticipantApplication from './501.DecisionOfParticipantApplication'
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { JSONSchemaType } from 'ajv'
|
||||
import moment from 'moment-timezone'
|
||||
import type { Cooperative as TCooperative } from 'cooptypes'
|
||||
import { DraftContract, SovietContract } from 'cooptypes'
|
||||
import type { ICombinedData, IGeneratedDocument, IMetaDocument, IMetaDocumentPartial, ITemplate, ITranslations, externalDataTypes } from '../Interfaces'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
import { Individual, Organization } from '../Models'
|
||||
import type { IDecisionData, IGenerate } from '../Interfaces/Documents'
|
||||
import { type IVars, Individual, Organization, Vars } from '../Models'
|
||||
import type { IGenerate } from '../Interfaces/Documents'
|
||||
import { PDFService } from '../Services/Generator'
|
||||
import packageJson from '../../package.json'
|
||||
import { Validator } from '../Services/Validator'
|
||||
@@ -14,11 +15,12 @@ import { Entrepreneur } from '../Models/Entrepreneur'
|
||||
import { getFetch } from '../Utils/getFetch'
|
||||
import { getEnvVar } from '../config'
|
||||
import { getCurrentBlock } from '../Utils/getCurrentBlock'
|
||||
import type { IOrganizationData } from '..'
|
||||
|
||||
const packageVersion = packageJson.version
|
||||
|
||||
export abstract class DocFactory {
|
||||
abstract generateDocument(options: IGenerate): Promise<IGeneratedDocument>
|
||||
export abstract class DocFactory<T extends IGenerate> {
|
||||
abstract generateDocument(options: T): Promise<IGeneratedDocument>
|
||||
|
||||
public storage: MongoDBConnector
|
||||
|
||||
@@ -30,6 +32,16 @@ export abstract class DocFactory {
|
||||
return new Validator(schema, combinedData).validate()
|
||||
}
|
||||
|
||||
async getOrganization(username: string, block_num?: number): Promise<IOrganizationData> {
|
||||
const block_filter = block_num ? { block_num: { $lte: block_num } } : {}
|
||||
|
||||
const organization = await new Organization(this.storage).getOne({ username, ...block_filter })
|
||||
if (!organization)
|
||||
throw new Error('Организация не найдена')
|
||||
|
||||
return organization
|
||||
}
|
||||
|
||||
async getUser(username: string, block_num?: number): Promise<{ type: string, data: externalDataTypes }> {
|
||||
const block_filter = block_num ? { block_num: { $lte: block_num } } : {}
|
||||
|
||||
@@ -77,12 +89,22 @@ export abstract class DocFactory {
|
||||
return coop
|
||||
}
|
||||
|
||||
async getDecision(coop: CooperativeData, coopname: string, decision_id: number, created_at: string): Promise<IDecisionData> {
|
||||
async getVars(coopname: string, block_num?: number): Promise<IVars> {
|
||||
const block_filter = block_num ? { block_num: { $lte: block_num } } : {}
|
||||
|
||||
const vars = await new Vars(this.storage).getOne({ coopname, ...block_filter })
|
||||
|
||||
if (!vars)
|
||||
throw new Error('Переменные кооператива не найдены')
|
||||
return vars
|
||||
}
|
||||
|
||||
async getDecision(coop: CooperativeData, coopname: string, decision_id: number, created_at: string): Promise<TCooperative.Document.IDecisionData> {
|
||||
const votes_for_actions = (await getFetch(`${getEnvVar('SIMPLE_EXPLORER_API')}/get-actions`, new URLSearchParams({
|
||||
filter: JSON.stringify({
|
||||
'account': process.env.SOVIET_CONTRACT,
|
||||
'account': SovietContract.contractName.production,
|
||||
'name': SovietContract.Actions.Decisions.VoteFor.actionName,
|
||||
'receiver': process.env.SOVIET_CONTRACT,
|
||||
'receiver': SovietContract.contractName.production,
|
||||
'data.decision_id': String(decision_id),
|
||||
'data.coopname': coopname,
|
||||
}),
|
||||
@@ -93,9 +115,9 @@ export abstract class DocFactory {
|
||||
|
||||
const votes_against_actions = (await getFetch(`${getEnvVar('SIMPLE_EXPLORER_API')}/get-actions`, new URLSearchParams({
|
||||
filter: JSON.stringify({
|
||||
'account': process.env.SOVIET_CONTRACT,
|
||||
'account': SovietContract.contractName.production,
|
||||
'name': SovietContract.Actions.Decisions.VoteAgainst.actionName,
|
||||
'receiver': process.env.SOVIET_CONTRACT,
|
||||
'receiver': SovietContract.contractName.production,
|
||||
'data.decision_id': String(decision_id),
|
||||
'data.coopname': coopname,
|
||||
}),
|
||||
@@ -123,13 +145,13 @@ export abstract class DocFactory {
|
||||
}
|
||||
}
|
||||
|
||||
async getTemplate<T>(registry_id: number, block_num?: number): Promise<ITemplate<T>> {
|
||||
async getTemplate<T>(scope: string, registry_id: number, block_num?: number): Promise<ITemplate<T>> {
|
||||
const block_filter = block_num ? { block_num: { $lte: block_num } } : {}
|
||||
|
||||
const templateResponse = await getFetch(`${getEnvVar('SIMPLE_EXPLORER_API')}/get-tables`, new URLSearchParams({
|
||||
filter: JSON.stringify({
|
||||
'code': DraftContract.contractName.production,
|
||||
'scope': DraftContract.contractName.production,
|
||||
'scope': scope,
|
||||
'table': DraftContract.Tables.Drafts.tableName,
|
||||
'value.registry_id': String(registry_id),
|
||||
...block_filter,
|
||||
@@ -144,9 +166,9 @@ export abstract class DocFactory {
|
||||
const translationsResponse = await getFetch(`${getEnvVar('SIMPLE_EXPLORER_API')}/get-tables`, new URLSearchParams({
|
||||
filter: JSON.stringify({
|
||||
'code': DraftContract.contractName.production,
|
||||
'scope': DraftContract.contractName.production,
|
||||
'scope': scope,
|
||||
'table': 'translations',
|
||||
'value.draft_id': String(draft.id),
|
||||
'value.draft_id': String(draft.registry_id),
|
||||
...block_filter,
|
||||
}),
|
||||
}))
|
||||
@@ -170,7 +192,7 @@ export abstract class DocFactory {
|
||||
}
|
||||
|
||||
async generatePDF(
|
||||
data: externalDataTypes,
|
||||
data: externalDataTypes | null,
|
||||
context: string,
|
||||
vars: ICombinedData,
|
||||
translation: ITranslations,
|
||||
@@ -185,13 +207,14 @@ export abstract class DocFactory {
|
||||
return document
|
||||
}
|
||||
|
||||
getFullName(data: externalDataTypes): string {
|
||||
if ('first_name' in data)
|
||||
return `${data.last_name} ${data.first_name} ${data.middle_name}`
|
||||
|
||||
if ('represented_by' in data)
|
||||
return `${data.represented_by.last_name} ${data.represented_by.first_name} ${data.represented_by.middle_name}`
|
||||
getFullName(data: externalDataTypes | null): string {
|
||||
if (data) {
|
||||
if ('first_name' in data)
|
||||
return `${data.last_name} ${data.first_name} ${data.middle_name}`
|
||||
|
||||
if ('represented_by' in data)
|
||||
return `${data.represented_by.last_name} ${data.represented_by.first_name} ${data.represented_by.middle_name}`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -200,12 +223,11 @@ export abstract class DocFactory {
|
||||
}
|
||||
|
||||
async getMeta<T extends IMetaDocumentPartial>({
|
||||
code,
|
||||
action,
|
||||
title,
|
||||
username,
|
||||
coopname,
|
||||
registry_id,
|
||||
links = [],
|
||||
lang = 'ru',
|
||||
generator = 'coopjs',
|
||||
version = packageVersion, // TODO перенести в .env
|
||||
@@ -219,8 +241,8 @@ export abstract class DocFactory {
|
||||
if (!title)
|
||||
throw new Error('Заголовок документа должен быть установлен')
|
||||
|
||||
if (!code || !action)
|
||||
throw new Error('Параметры действия должны быть переданы')
|
||||
if (!registry_id)
|
||||
throw new Error('Параметр номера документа в реестре должен быть передан')
|
||||
|
||||
if (created_at)
|
||||
dateWithTimezone = moment.tz(created_at, 'DD.MM.YYYY HH:mm', timezone).format('DD.MM.YYYY HH:mm').toString()
|
||||
@@ -231,12 +253,11 @@ export abstract class DocFactory {
|
||||
block_num = await getCurrentBlock()
|
||||
|
||||
return {
|
||||
code,
|
||||
action,
|
||||
title,
|
||||
lang,
|
||||
registry_id,
|
||||
generator,
|
||||
links,
|
||||
version,
|
||||
coopname,
|
||||
username,
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import type { Cooperative } from 'cooptypes'
|
||||
|
||||
export type IGenerateJoinCoopDecision = Cooperative.Documents.IGenerateJoinCoopDecision
|
||||
export type IGenerateJoinCoop = Cooperative.Documents.IGenerateJoinCoop
|
||||
export type IGenerateJoinCoopDecision = Cooperative.Document.IGenerateJoinCoopDecision
|
||||
|
||||
/**
|
||||
* Интерфейс генерации заявления на вступление в кооператив
|
||||
*/
|
||||
export interface IGenerateJoinCoop extends IGenerate {
|
||||
signature: string
|
||||
skip_save: boolean
|
||||
}
|
||||
|
||||
export type IGenerateAgreement = Cooperative.Document.IGenerateAgreement
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import type { JSONSchemaType } from 'ajv'
|
||||
import type { Cooperative } from 'cooptypes'
|
||||
import type { DocumentsMappingByActionAndCode } from '../Templates/registry'
|
||||
import type { Registry } from '../templates/registry'
|
||||
import type { CooperativeData } from '../Models/Cooperative'
|
||||
import type { ExternalEntrepreneurData, ExternalIndividualData, ExternalOrganizationData } from '../Models'
|
||||
|
||||
// Определение базового интерфейса для мета-информации
|
||||
export type IMetaDocument = Cooperative.Documents.IMetaDocument
|
||||
|
||||
export interface IDecisionData {
|
||||
id: number
|
||||
date: string
|
||||
time: string
|
||||
votes_for: number
|
||||
votes_against: number
|
||||
votes_abstained: number
|
||||
voters_percent: number
|
||||
}
|
||||
export type IMetaDocument = Cooperative.Document.IMetaDocument
|
||||
|
||||
export interface IGeneratedDocument {
|
||||
full_title?: string
|
||||
@@ -43,11 +33,11 @@ export interface ICombinedData {
|
||||
individual?: ExternalIndividualData
|
||||
organization?: ExternalOrganizationData
|
||||
entrepreneur?: ExternalEntrepreneurData
|
||||
coop: CooperativeData
|
||||
coop?: CooperativeData
|
||||
meta: IMetaDocument
|
||||
}
|
||||
|
||||
export type Actions = keyof DocumentsMappingByActionAndCode
|
||||
export type Numbers = keyof typeof Registry
|
||||
export type LangType = 'ru'
|
||||
|
||||
export interface IMetaDocumentPartial extends Partial<IMetaDocument> {
|
||||
@@ -57,10 +47,4 @@ export interface IMetaDocumentPartial extends Partial<IMetaDocument> {
|
||||
title: string
|
||||
}
|
||||
|
||||
export interface IGenerate extends Omit<Partial<IMetaDocument>, 'registry_id' | 'title'> {
|
||||
code: string
|
||||
action: string
|
||||
coopname: string
|
||||
username: string
|
||||
[key: string]: any
|
||||
}
|
||||
export type IGenerate = Cooperative.Document.IGenerate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Document } from 'mongodb'
|
||||
import type { ExternalEntrepreneurData, ExternalIndividualData, ExternalOrganizationData, InternalEntrepreneurData, InternalIndividualData, InternalOrganizationData } from '../Models'
|
||||
import type { ExternalEntrepreneurData, ExternalIndividualData, ExternalOrganizationData, IVars, InternalEntrepreneurData, InternalIndividualData, InternalOrganizationData } from '../Models'
|
||||
import type { PaymentData } from '../Models/PaymentMethod'
|
||||
import type { IGeneratedDocument } from './Documents'
|
||||
import type { IPaymentData } from './BankAccounts'
|
||||
@@ -34,6 +34,6 @@ export interface IBCState {
|
||||
export interface IFilterDocuments extends Document, IGeneratedDocument {
|
||||
}
|
||||
|
||||
export type internalFilterTypes = InternalIndividualData | InternalEntrepreneurData | InternalOrganizationData | IPaymentData
|
||||
export type externalDataTypes = ExternalIndividualData | ExternalEntrepreneurData | ExternalOrganizationData | PaymentData
|
||||
export type externalDataTypesArrays = ExternalIndividualData[] | ExternalEntrepreneurData[] | ExternalOrganizationData[] | PaymentData[]
|
||||
export type internalFilterTypes = InternalIndividualData | InternalEntrepreneurData | InternalOrganizationData | IPaymentData | IVars
|
||||
export type externalDataTypes = ExternalIndividualData | ExternalEntrepreneurData | ExternalOrganizationData | PaymentData | IVars
|
||||
export type externalDataTypesArrays = ExternalIndividualData[] | ExternalEntrepreneurData[] | ExternalOrganizationData[] | PaymentData[] | IVars[]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './Documents'
|
||||
export * from './BankAccounts'
|
||||
export * from './Storage'
|
||||
export * from './Actions'
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import type { JSONSchemaType } from 'ajv'
|
||||
import { RegistratorContract, SovietContract } from 'cooptypes'
|
||||
import type { Cooperative as CooperativeApi } from 'cooptypes'
|
||||
import { type ValidateResult, Validator } from '../Services/Validator'
|
||||
import DataService from '../Services/Databazor/DataService'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
import { individualSchema } from '../Schema/IndividualSchema'
|
||||
import { getFetch } from '../Utils/getFetch'
|
||||
import { getEnvVar } from '../config'
|
||||
import { organizationSchema } from '../Schema'
|
||||
import { CooperativeSchema } from '../Schema/CooperativeSchema'
|
||||
import { Organization } from './Organization'
|
||||
|
||||
import type { ExternalIndividualData } from './Individual'
|
||||
@@ -16,27 +14,6 @@ import { Individual } from './Individual'
|
||||
export type CooperativeData = CooperativeApi.Model.ICooperativeData
|
||||
export type MembersData = CooperativeApi.Model.MembersData
|
||||
|
||||
export const CooperativeSchema: JSONSchemaType<CooperativeData> = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
is_branched: { type: 'boolean' },
|
||||
registration: { type: 'string' },
|
||||
initial: { type: 'string' },
|
||||
minimum: { type: 'string' },
|
||||
org_registration: { type: 'string' },
|
||||
org_initial: { type: 'string' },
|
||||
org_minimum: { type: 'string' },
|
||||
totalMembers: { type: 'number' },
|
||||
members: {
|
||||
type: 'array',
|
||||
items: individualSchema,
|
||||
},
|
||||
...organizationSchema.properties,
|
||||
},
|
||||
required: [...organizationSchema.required, 'is_branched', 'registration', 'initial', 'minimum', 'org_registration', 'org_initial', 'org_minimum', 'members', 'totalMembers'],
|
||||
additionalProperties: true,
|
||||
}
|
||||
|
||||
export class Cooperative {
|
||||
cooperative: CooperativeData | null
|
||||
db: MongoDBConnector
|
||||
@@ -46,7 +23,7 @@ export class Cooperative {
|
||||
constructor(storage: MongoDBConnector) {
|
||||
this.db = storage
|
||||
this.cooperative = null
|
||||
this.data_service = new DataService<CooperativeData>(storage, 'CooperativeData')
|
||||
this.data_service = new DataService<CooperativeData>(storage, 'cooperatives')
|
||||
}
|
||||
|
||||
async getOne(username: string, block_num?: number): Promise<CooperativeData> {
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
export interface Document {
|
||||
import type { IMetaDocument } from '../Interfaces'
|
||||
|
||||
export interface Document {
|
||||
full_title?: string
|
||||
html: string
|
||||
hash: string
|
||||
meta: IMetaDocument
|
||||
binary: Uint8Array
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export class Entrepreneur {
|
||||
constructor(storage: MongoDBConnector, data?: ExternalEntrepreneurData) {
|
||||
this.db = storage
|
||||
this.entrepreneur = data
|
||||
this.data_service = new DataService<InternalEntrepreneurData>(storage, 'EntrepreneurData')
|
||||
this.data_service = new DataService<InternalEntrepreneurData>(storage, 'entrepreneurs')
|
||||
}
|
||||
|
||||
validate(): ValidateResult {
|
||||
@@ -74,7 +74,7 @@ export class Entrepreneur {
|
||||
return entr as ExternalEntrepreneurData
|
||||
}
|
||||
|
||||
async getMany(filter: Filter<InternalEntrepreneurData>): Promise<Cooperative.Documents.IGetResponse<ExternalEntrepreneurData>> {
|
||||
async getMany(filter: Filter<InternalEntrepreneurData>): Promise<Cooperative.Document.IGetResponse<ExternalEntrepreneurData>> {
|
||||
const response = await this.data_service.getMany({ deleted: false, ...filter }, 'username')
|
||||
const entrepreneurs = response.results
|
||||
const blockFilter = filter.block_num ? { block_num: filter.block_num } : {}
|
||||
@@ -83,7 +83,7 @@ export class Entrepreneur {
|
||||
entr.bank_account = (await (new PaymentMethod(this.db).getOne({ ...blockFilter, username: entr.username, method_type: 'bank_transfer', is_default: true })))?.data as IBankAccount
|
||||
}
|
||||
|
||||
const result: Cooperative.Documents.IGetResponse<ExternalEntrepreneurData> = {
|
||||
const result: Cooperative.Document.IGetResponse<ExternalEntrepreneurData> = {
|
||||
results: entrepreneurs as ExternalEntrepreneurData[],
|
||||
page: response.page,
|
||||
limit: response.limit,
|
||||
|
||||
@@ -16,7 +16,7 @@ export class Individual {
|
||||
|
||||
constructor(storage: MongoDBConnector, data?: ExternalIndividualData) {
|
||||
this.individual = data
|
||||
this.data_service = new DataService<InternalIndividualData>(storage, 'IndividualData')
|
||||
this.data_service = new DataService<InternalIndividualData>(storage, 'individuals')
|
||||
}
|
||||
|
||||
validate(): ValidateResult {
|
||||
@@ -44,7 +44,7 @@ export class Individual {
|
||||
return this.data_service.getOne(filter)
|
||||
}
|
||||
|
||||
async getMany(filter: Filter<InternalIndividualData>): Promise<Cooperative.Documents.IGetResponse<ExternalIndividualData>> {
|
||||
async getMany(filter: Filter<InternalIndividualData>): Promise<Cooperative.Document.IGetResponse<ExternalIndividualData>> {
|
||||
return this.data_service.getMany(filter, 'username')
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export class Organization {
|
||||
constructor(storage: MongoDBConnector, data?: ExternalOrganizationData) {
|
||||
this.db = storage
|
||||
this.organization = data
|
||||
this.data_service = new DataService<InternalOrganizationData>(storage, 'OrgData')
|
||||
this.data_service = new DataService<InternalOrganizationData>(storage, 'organizations')
|
||||
}
|
||||
|
||||
validate(): ValidateResult {
|
||||
@@ -75,7 +75,7 @@ export class Organization {
|
||||
return org as ExternalOrganizationData
|
||||
}
|
||||
|
||||
async getMany(filter: Filter<InternalOrganizationData>): Promise<Cooperative.Documents.IGetResponse<ExternalOrganizationData>> {
|
||||
async getMany(filter: Filter<InternalOrganizationData>): Promise<Cooperative.Document.IGetResponse<ExternalOrganizationData>> {
|
||||
const response = (await this.data_service.getMany({ deleted: false, ...filter }, 'username'))
|
||||
const orgs = response.results
|
||||
const blockFilter = filter.block_num ? { block_num: filter.block_num } : {}
|
||||
@@ -84,7 +84,7 @@ export class Organization {
|
||||
org.bank_account = (await (new PaymentMethod(this.db).getOne({ ...blockFilter, username: org.username, method_type: 'bank_transfer', is_default: true })))?.data as IBankAccount
|
||||
}
|
||||
|
||||
const result: Cooperative.Documents.IGetResponse<ExternalOrganizationData> = {
|
||||
const result: Cooperative.Document.IGetResponse<ExternalOrganizationData> = {
|
||||
results: orgs as ExternalOrganizationData[],
|
||||
page: response.page,
|
||||
limit: response.limit,
|
||||
|
||||
@@ -18,7 +18,7 @@ export class PaymentMethod {
|
||||
constructor(storage: MongoDBConnector, data?: PaymentData) {
|
||||
this.db = storage
|
||||
this.paymentMethod = data
|
||||
this.data_service = new DataService(storage, 'PaymentData')
|
||||
this.data_service = new DataService(storage, 'paymentMethods')
|
||||
}
|
||||
|
||||
validate(): ValidateResult {
|
||||
@@ -41,7 +41,7 @@ export class PaymentMethod {
|
||||
return this.data_service.getOne(filter)
|
||||
}
|
||||
|
||||
async getMany(filter: Filter<PaymentData>): Promise<Cooperative.Documents.IGetResponse<PaymentData>> {
|
||||
async getMany(filter: Filter<PaymentData>): Promise<Cooperative.Document.IGetResponse<PaymentData>> {
|
||||
return this.data_service.getMany({ deleted: false, ...filter }, ['username', 'method_id'])
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { Cooperative } from 'cooptypes'
|
||||
import type { Filter, InsertOneResult, UpdateResult } from 'mongodb'
|
||||
import type { IMetaDocument } from '../Interfaces'
|
||||
import DataService from '../Services/Databazor/DataService'
|
||||
import { type ValidateResult, Validator } from '../Services/Validator'
|
||||
import { VarsSchema } from '../Schema'
|
||||
import type { MongoDBConnector } from '../Services/Databazor'
|
||||
import { getCurrentBlock } from '../Utils/getCurrentBlock'
|
||||
|
||||
export type IVars = Cooperative.Model.IVars
|
||||
|
||||
export class Vars {
|
||||
data?: IVars
|
||||
private data_service: DataService<IVars>
|
||||
|
||||
constructor(storage: MongoDBConnector, data?: IVars) {
|
||||
this.data = data
|
||||
this.data_service = new DataService<IVars>(storage, 'vars')
|
||||
}
|
||||
|
||||
validate(): ValidateResult {
|
||||
return new Validator(VarsSchema, this.data).validate()
|
||||
}
|
||||
|
||||
async save(): Promise<InsertOneResult<IVars>> {
|
||||
await this.validate()
|
||||
|
||||
if (!this.data)
|
||||
throw new Error('Данные переменных не предоставлены для сохранения')
|
||||
|
||||
const currentBlock = await getCurrentBlock()
|
||||
|
||||
const covar: IVars = {
|
||||
...this.data,
|
||||
deleted: false,
|
||||
block_num: currentBlock,
|
||||
}
|
||||
|
||||
return await this.data_service.save(covar)
|
||||
}
|
||||
|
||||
async getOne(filter: Filter<IVars>): Promise<IVars | null> {
|
||||
return this.data_service.getOne(filter)
|
||||
}
|
||||
|
||||
async getMany(filter: Filter<IVars>): Promise<Cooperative.Document.IGetResponse<IVars>> {
|
||||
return this.data_service.getMany(filter, 'coopname') // группировка по coopname
|
||||
}
|
||||
|
||||
async getHistory(filter: Filter<IVars>): Promise<IVars[]> {
|
||||
return this.data_service.getHistory(filter)
|
||||
}
|
||||
|
||||
async del(filter: Filter<IVars>): Promise<UpdateResult> {
|
||||
return this.data_service.updateMany(filter, { deleted: true })
|
||||
}
|
||||
}
|
||||
@@ -2,3 +2,6 @@ export * from './Individual'
|
||||
export * from './Organization'
|
||||
export * from './Entrepreneur'
|
||||
export * from './Cooperative'
|
||||
export * from './Document'
|
||||
export * from './PaymentMethod'
|
||||
export * from './Vars'
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { JSONSchemaType } from 'ajv'
|
||||
import type { CooperativeData } from '../Models/Cooperative'
|
||||
import { memberSchema } from './MemberSchema'
|
||||
import { individualSchema, organizationSchema } from '.'
|
||||
|
||||
export const CooperativeSchema: JSONSchemaType<CooperativeData> = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
is_branched: { type: 'boolean' },
|
||||
registration: { type: 'string' },
|
||||
initial: { type: 'string' },
|
||||
minimum: { type: 'string' },
|
||||
org_registration: { type: 'string' },
|
||||
org_initial: { type: 'string' },
|
||||
org_minimum: { type: 'string' },
|
||||
totalMembers: { type: 'number' },
|
||||
chairman: {
|
||||
type: 'object',
|
||||
properties: individualSchema.properties,
|
||||
required: individualSchema.required,
|
||||
},
|
||||
members: {
|
||||
type: 'array',
|
||||
items: memberSchema,
|
||||
},
|
||||
...organizationSchema.properties,
|
||||
},
|
||||
required: [...organizationSchema.required, 'is_branched', 'registration', 'initial', 'minimum', 'org_registration', 'org_initial', 'org_minimum', 'members', 'totalMembers', 'chairman'],
|
||||
additionalProperties: true,
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { JSONSchemaType } from 'ajv'
|
||||
import type { IDecisionData } from '../Interfaces'
|
||||
import type { Cooperative } from 'cooptypes'
|
||||
|
||||
export const decisionSchema: JSONSchemaType<IDecisionData> = {
|
||||
export const decisionSchema: JSONSchemaType<Cooperative.Document.IDecisionData> = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number' },
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user