feat: vote for super admin role (#56)
[WIP] solve this ticket: https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=29580&t=k&c=e2ed47d1b61a467bba6cbdd734665bdd
This commit is contained in:
commit
77f24af33c
185
package-lock.json
generated
185
package-lock.json
generated
@ -19,7 +19,7 @@
|
||||
"cron": "^2.3.1",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.57",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.66",
|
||||
"module-alias": "^2.2.2",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"next": "^13.1.5",
|
||||
@ -1061,14 +1061,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.10.tgz",
|
||||
"integrity": "sha512-3G1yD/XKTSLdihyDSa8JEsaWOELY+OWe08o0LUYzfuHp1zHDA8SObQlzKt+v+wrkkPcnPweoLH1ImZeUa0A1NQ=="
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.12.tgz",
|
||||
"integrity": "sha512-RmHanbV21saP/6OEPBJ7yJMuys68cIf8OBBWd7+uj40LdpmswVAwe1uzeuFyUsd6SfeITWT3XnQfn6wULeKwDQ=="
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.10.tgz",
|
||||
"integrity": "sha512-4bsdfKmmg7mgFGph0UorD1xWfZ5jZEw4kKRHYEeTK9bT1QnMbPVPlVXQRIiFPrhoDQnZUoa6duuPUJIEGLV1Jg==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.12.tgz",
|
||||
"integrity": "sha512-deUrbCXTMZ6ZhbOoloqecnUeNpUOupi8SE2tx4jPfNS9uyUR9zK4iXBvH65opVcA/9F5I/p8vDXSYbUlbmBjZg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1081,9 +1081,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.10.tgz",
|
||||
"integrity": "sha512-ngXhUBbcZIWZWqNbQSNxQrB9T1V+wgfCzAor2olYuo/YpaL6mUYNUEgeBMhr8qwV0ARSgKaOp35lRvB7EmCRBg==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.12.tgz",
|
||||
"integrity": "sha512-WRvH7RxgRHlC1yb5oG0ZLx8F7uci9AivM5/HGGv9ZyG2Als8Ij64GC3d+mQ5sJhWjusyU6T6V1WKTUoTmOB0zQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1096,9 +1096,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.10.tgz",
|
||||
"integrity": "sha512-SjCZZCOmHD4uyM75MVArSAmF5Y+IJSGroPRj2v9/jnBT36SYFTORN8Ag/lhw81W9EeexKY/CUg2e9mdebZOwsg==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.12.tgz",
|
||||
"integrity": "sha512-YEKracAWuxp54tKiAvvq73PUs9lok57cc8meYRibTWe/VdPB2vLgkTVWFcw31YDuRXdEhdX0fWS6Q+ESBhnEig==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1111,9 +1111,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.10.tgz",
|
||||
"integrity": "sha512-F+VlcWijX5qteoYIOxNiBbNE8ruaWuRlcYyIRK10CugqI/BIeCDzEDyrHIHY8AWwbkTwe6GRHabMdE688Rqq4Q==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.12.tgz",
|
||||
"integrity": "sha512-LhJR7/RAjdHJ2Isl2pgc/JaoxNk0KtBgkVpiDJPVExVWA1c6gzY57+3zWuxuyWzTG+fhLZo2Y80pLXgIJv7g3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1126,9 +1126,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.10.tgz",
|
||||
"integrity": "sha512-WDv1YtAV07nhfy3i1visr5p/tjiH6CeXp4wX78lzP1jI07t4PnHHG1WEDFOduXh3WT4hG6yN82EQBQHDi7hBrQ==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.12.tgz",
|
||||
"integrity": "sha512-1DWLL/B9nBNiQRng+1aqs3OaZcxC16Nf+mOnpcrZZSdyKHek3WQh6j/fkbukObgNGwmCoVevLUa/p3UFTTqgqg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1141,9 +1141,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.10.tgz",
|
||||
"integrity": "sha512-zFkzqc737xr6qoBgDa3AwC7jPQzGLjDlkNmt/ljvQJ/Veri5ECdHjZCUuiTUfVjshNIIpki6FuP0RaQYK9iCRg==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.12.tgz",
|
||||
"integrity": "sha512-kEAJmgYFhp0VL+eRWmUkVxLVunn7oL9Mdue/FS8yzRBVj7Z0AnIrHpTIeIUl1bbdQq1VaoOztnKicAjfkLTRCQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1156,9 +1156,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.10.tgz",
|
||||
"integrity": "sha512-IboRS8IWz5mWfnjAdCekkl8s0B7ijpWeDwK2O8CdgZkoCDY0ZQHBSGiJ2KViAG6+BJVfLvcP+a2fh6cdyBr9QQ==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.12.tgz",
|
||||
"integrity": "sha512-GMLuL/loR6yIIRTnPRY6UGbLL9MBdw2anxkOnANxvLvsml4F0HNIgvnU3Ej4BjbqMTNjD4hcPFdlEow4XHPdZA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1171,9 +1171,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.10.tgz",
|
||||
"integrity": "sha512-bSA+4j8jY4EEiwD/M2bol4uVEu1lBlgsGdvM+mmBm/BbqofNBfaZ2qwSbwE2OwbAmzNdVJRFRXQZ0dkjopTRaQ==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.12.tgz",
|
||||
"integrity": "sha512-PhgNqN2Vnkm7XaMdRmmX0ZSwZXQAtamBVSa9A/V1dfKQCV1rjIZeiy/dbBnVYGdj63ANfsOR/30XpxP71W0eww==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@ -1186,9 +1186,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.10.tgz",
|
||||
"integrity": "sha512-g2+tU63yTWmcVQKDGY0MV1PjjqgZtwM4rB1oVVi/v0brdZAcrcTV+04agKzWtvWroyFz6IqtT0MoZJA7PNyLVw==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.12.tgz",
|
||||
"integrity": "sha512-Z+56e/Ljt0bUs+T+jPjhFyxYBcdY2RIq9ELFU+qAMQMteHo7ymbV7CKmlcX59RI9C4YzN8PgMgLyAoi916b5HA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1493,9 +1493,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.0.tgz",
|
||||
"integrity": "sha512-GXZxEtOxYGFchyUzxvKI14iff9KZ2DI+A6a37o6EQevtg6uO9t+aUZKcaC1Te5Ng1OnLM7K9NVVj+FbecD9cJg=="
|
||||
"version": "18.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.1.tgz",
|
||||
"integrity": "sha512-xlR1jahfizdplZYRU59JlUx9uzF1ARa8jbhM11ccpCJya8kvos5jwdm2ZAgxSCwOl0fq21svP18EVwPBXMQudw=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.4",
|
||||
@ -2049,9 +2049,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001516",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz",
|
||||
"integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==",
|
||||
"version": "1.0.30001517",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz",
|
||||
"integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@ -2335,9 +2335,9 @@
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
|
||||
},
|
||||
"node_modules/cron": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-2.3.1.tgz",
|
||||
"integrity": "sha512-1eRRlIT0UfIqauwbG9pkg3J6CX9A6My2ytJWqAXoK0T9oJnUZTzGBNPxao0zjodIbPgf8UQWjE62BMb9eVllSQ==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-2.4.0.tgz",
|
||||
"integrity": "sha512-Cx77ic1TyIAtUggr0oAhtS8MLzPBUqGNIvdDM7jE3oFIxfe8LXWI9q3iQN/H2CebAiMir53LQKWOhEKnzkJTAQ==",
|
||||
"dependencies": {
|
||||
"luxon": "^3.2.1"
|
||||
}
|
||||
@ -2467,9 +2467,9 @@
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.461",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.461.tgz",
|
||||
"integrity": "sha512-1JkvV2sgEGTDXjdsaQCeSwYYuhLRphRpc+g6EHTFELJXEiznLt3/0pZ9JuAOQ5p2rI3YxKTbivtvajirIfhrEQ==",
|
||||
"version": "1.4.473",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.473.tgz",
|
||||
"integrity": "sha512-aVfC8+440vGfl06l8HKKn8/PD5jRfSnLkTTD65EFvU46igbpQRri1gxSzW9/+TeUlwYzrXk1sw867T96zlyECA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
@ -3193,17 +3193,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-lib-report": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
||||
"integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
|
||||
"integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"make-dir": "^3.0.0",
|
||||
"make-dir": "^4.0.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-lib-source-maps": {
|
||||
@ -3244,9 +3244,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/istanbul-reports": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
|
||||
"integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz",
|
||||
"integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"html-escaper": "^2.0.0",
|
||||
@ -3972,7 +3972,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/le-coffre-resources": {
|
||||
"resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#dffc2429ba6ceb4129deb56e308962799b9b572c",
|
||||
"resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#e7916d516fe434c93ef13e765d8d63a7ce3c56b2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"class-transformer": "^0.5.1",
|
||||
@ -3990,9 +3990,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/libphonenumber-js": {
|
||||
"version": "1.10.37",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.37.tgz",
|
||||
"integrity": "sha512-Z10PCaOCiAxbUxLyR31DNeeNugSVP6iv/m7UrSKS5JHziEMApJtgku4e9Q69pzzSC9LnQiM09sqsGf2ticZnMw=="
|
||||
"version": "1.10.38",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.38.tgz",
|
||||
"integrity": "sha512-4NjVXVUmpZ9Zsqq6FXa2+MKI+KAI3tOqA0pxXgXGluhpj4ge5didmbWJpMBqGB3AVGv1SnEtKdGTbxjSEG1kCQ=="
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
@ -4066,20 +4066,53 @@
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
|
||||
"integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"semver": "^6.0.0"
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
@ -4386,11 +4419,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-13.4.10.tgz",
|
||||
"integrity": "sha512-4ep6aKxVTQ7rkUW2fBLhpBr/5oceCuf4KmlUpvG/aXuDTIf9mexNSpabUD6RWPspu6wiJJvozZREhXhueYO36A==",
|
||||
"version": "13.4.12",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-13.4.12.tgz",
|
||||
"integrity": "sha512-eHfnru9x6NRmTMcjQp6Nz0J4XH9OubmzOa7CkWL+AUrUxpibub3vWwttjduu9No16dug1kq04hiUUpo7J3m3Xw==",
|
||||
"dependencies": {
|
||||
"@next/env": "13.4.10",
|
||||
"@next/env": "13.4.12",
|
||||
"@swc/helpers": "0.5.1",
|
||||
"busboy": "1.6.0",
|
||||
"caniuse-lite": "^1.0.30001406",
|
||||
@ -4406,15 +4439,15 @@
|
||||
"node": ">=16.8.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "13.4.10",
|
||||
"@next/swc-darwin-x64": "13.4.10",
|
||||
"@next/swc-linux-arm64-gnu": "13.4.10",
|
||||
"@next/swc-linux-arm64-musl": "13.4.10",
|
||||
"@next/swc-linux-x64-gnu": "13.4.10",
|
||||
"@next/swc-linux-x64-musl": "13.4.10",
|
||||
"@next/swc-win32-arm64-msvc": "13.4.10",
|
||||
"@next/swc-win32-ia32-msvc": "13.4.10",
|
||||
"@next/swc-win32-x64-msvc": "13.4.10"
|
||||
"@next/swc-darwin-arm64": "13.4.12",
|
||||
"@next/swc-darwin-x64": "13.4.12",
|
||||
"@next/swc-linux-arm64-gnu": "13.4.12",
|
||||
"@next/swc-linux-arm64-musl": "13.4.12",
|
||||
"@next/swc-linux-x64-gnu": "13.4.12",
|
||||
"@next/swc-linux-x64-musl": "13.4.12",
|
||||
"@next/swc-win32-arm64-msvc": "13.4.12",
|
||||
"@next/swc-win32-ia32-msvc": "13.4.12",
|
||||
"@next/swc-win32-x64-msvc": "13.4.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
@ -5661,9 +5694,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
|
||||
"integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA=="
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
|
||||
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
|
||||
},
|
||||
"node_modules/type-detect": {
|
||||
"version": "4.0.8",
|
||||
|
@ -52,7 +52,7 @@
|
||||
"cron": "^2.3.1",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.63",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.66",
|
||||
"module-alias": "^2.2.2",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"next": "^13.1.5",
|
||||
|
76
src/app/api/super-admin/AppointmentsController.ts
Normal file
76
src/app/api/super-admin/AppointmentsController.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { Response, Request } from "express";
|
||||
import { Controller, Get } from "@ControllerPattern/index";
|
||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||
import AppointmentsService from "@Services/super-admin/AppointmentsService/AppointmentsService";
|
||||
import { Service } from "typedi";
|
||||
import { Appointment } from "le-coffre-resources/dist/SuperAdmin";
|
||||
import authHandler from "@App/middlewares/AuthHandler";
|
||||
|
||||
@Controller()
|
||||
@Service()
|
||||
export default class AppointmentsController extends ApiController {
|
||||
constructor(private appointmentsService: AppointmentsService) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Get all appointments
|
||||
*/
|
||||
@Get("/api/v1/super-admin/appointments", [authHandler])
|
||||
protected async get(req: Request, response: Response) {
|
||||
try {
|
||||
//get query
|
||||
let query;
|
||||
if (req.query["q"]) {
|
||||
query = JSON.parse(req.query["q"] as string);
|
||||
}
|
||||
|
||||
//call service to get prisma entity
|
||||
const appointmentsEntities = await this.appointmentsService.get(query);
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const appointments = Appointment.hydrateArray<Appointment>(appointmentsEntities, { strategy: "excludeAll" });
|
||||
|
||||
//success
|
||||
this.httpSuccess(response, appointments);
|
||||
} catch (error) {
|
||||
this.httpInternalError(response, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Get a specific appointment by uid
|
||||
*/
|
||||
@Get("/api/v1/super-admin/appointments/:uid", [authHandler])
|
||||
protected async getOneByUid(req: Request, response: Response) {
|
||||
try {
|
||||
const uid = req.params["uid"];
|
||||
if (!uid) {
|
||||
this.httpBadRequest(response, "No uid provided");
|
||||
return;
|
||||
}
|
||||
|
||||
let query;
|
||||
if (req.query["q"]) {
|
||||
query = JSON.parse(req.query["q"] as string);
|
||||
}
|
||||
|
||||
const appointmentEntity = await this.appointmentsService.getByUid(uid, query);
|
||||
|
||||
if (!appointmentEntity) {
|
||||
this.httpNotFoundRequest(response, "appointment not found");
|
||||
return;
|
||||
}
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const appointment = Appointment.hydrate<Appointment>(appointmentEntity, { strategy: "excludeAll" });
|
||||
|
||||
//success
|
||||
this.httpSuccess(response, appointment);
|
||||
} catch (error) {
|
||||
this.httpInternalError(response, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
94
src/app/api/super-admin/LiveVoteController.ts
Normal file
94
src/app/api/super-admin/LiveVoteController.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import authHandler from "@App/middlewares/AuthHandler";
|
||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||
import { Controller, Post } from "@ControllerPattern/index";
|
||||
import { EAppointmentStatus } from "@prisma/client";
|
||||
import AppointmentService from "@Services/super-admin/AppointmentsService/AppointmentsService";
|
||||
import LiveVoteService from "@Services/super-admin/LiveVoteService/LiveVoteService";
|
||||
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
||||
import VotesService from "@Services/super-admin/VotesService/VotesService";
|
||||
import { validateOrReject } from "class-validator";
|
||||
import { Request, Response } from "express";
|
||||
import { Vote } from "le-coffre-resources/dist/SuperAdmin";
|
||||
import { Service } from "typedi";
|
||||
|
||||
@Controller()
|
||||
@Service()
|
||||
export default class LiveVoteController extends ApiController {
|
||||
constructor(
|
||||
private liveVoteService: LiveVoteService,
|
||||
private votesService: VotesService,
|
||||
private usersService: UsersService,
|
||||
private appointmentService: AppointmentService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Create a new vote
|
||||
*/
|
||||
@Post("/api/v1/super-admin/live-votes", [authHandler])
|
||||
protected async post(req: Request, response: Response) {
|
||||
try {
|
||||
const userId = req.body.user.userId;
|
||||
//init IUser resource with request body values
|
||||
const voteEntity = Vote.hydrate<Vote>(req.body);
|
||||
//validate user
|
||||
await validateOrReject(voteEntity, { groups: ["createVote"] });
|
||||
|
||||
let voteFound = [];
|
||||
if (voteEntity.appointment.uid) {
|
||||
const appointment = await this.appointmentService.getByUid(voteEntity.appointment.uid);
|
||||
if (!appointment) {
|
||||
this.httpNotFoundRequest(response, "Appointment not found");
|
||||
return;
|
||||
}
|
||||
if (appointment.status === EAppointmentStatus.CLOSED) {
|
||||
this.httpBadRequest(response, "Appointment is closed");
|
||||
return;
|
||||
}
|
||||
voteFound = await this.votesService.get({
|
||||
where: { AND: [{ appointment: { uid: voteEntity.appointment.uid } }, { voter: { uid: userId } }] },
|
||||
});
|
||||
} else {
|
||||
voteFound = await this.votesService.get({
|
||||
where: {
|
||||
AND: [
|
||||
{
|
||||
appointment: {
|
||||
AND: [{ user_uid: voteEntity.appointment.targeted_user.uid }, { status: EAppointmentStatus.OPEN }],
|
||||
},
|
||||
},
|
||||
{ voter: { uid: userId } },
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (voteFound.length) {
|
||||
this.httpBadRequest(response, "Voter already voted for this appointment");
|
||||
return;
|
||||
}
|
||||
|
||||
const voter = await this.usersService.getByUid(userId);
|
||||
|
||||
voteEntity.voter = voter!;
|
||||
//call service to get prisma entity
|
||||
const voteEntityCreated = await this.liveVoteService.create(voteEntity);
|
||||
|
||||
if (!voteEntityCreated) {
|
||||
this.httpBadRequest(response, "Appointment choice is not valid");
|
||||
return;
|
||||
}
|
||||
//Hydrate ressource with prisma entity
|
||||
const vote = Vote.hydrate<Vote>(voteEntityCreated, {
|
||||
strategy: "excludeAll",
|
||||
});
|
||||
|
||||
//success
|
||||
this.httpCreated(response, vote);
|
||||
} catch (error) {
|
||||
this.httpInternalError(response, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -90,12 +90,13 @@ export default class UsersController extends ApiController {
|
||||
protected async put(req: Request, response: Response) {
|
||||
try {
|
||||
const uid = req.params["uid"];
|
||||
|
||||
if (!uid) {
|
||||
this.httpBadRequest(response, "No uid provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const userFound = await this.usersService.getByUid(uid);
|
||||
const userFound = await this.usersService.getByUid(uid, {role: true, votes: true});
|
||||
|
||||
if (!userFound) {
|
||||
this.httpNotFoundRequest(response, "user not found");
|
||||
@ -104,12 +105,13 @@ export default class UsersController extends ApiController {
|
||||
|
||||
//init IUser resource with request body values
|
||||
const userEntity = User.hydrate<User>(req.body);
|
||||
const userFoundEntity = User.hydrate<User>(userFound, { strategy: "excludeAll" });
|
||||
|
||||
//validate user
|
||||
await validateOrReject(userEntity, { groups: ["updateUser"] });
|
||||
|
||||
|
||||
//call service to get prisma entity
|
||||
const userEntityUpdated = await this.usersService.update(uid, userEntity);
|
||||
const userEntityUpdated = await this.usersService.update(uid, userFoundEntity);
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const user = User.hydrate<User>(userEntityUpdated, {
|
||||
|
110
src/app/api/super-admin/VotesController.ts
Normal file
110
src/app/api/super-admin/VotesController.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { Response, Request } from "express";
|
||||
import { Controller, Delete, Get } from "@ControllerPattern/index";
|
||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||
import VotesService from "@Services/super-admin/VotesService/VotesService";
|
||||
import { Service } from "typedi";
|
||||
import { Vote } from "le-coffre-resources/dist/SuperAdmin";
|
||||
import authHandler from "@App/middlewares/AuthHandler";
|
||||
import { Votes } from "@prisma/client";
|
||||
|
||||
@Controller()
|
||||
@Service()
|
||||
export default class VotesController extends ApiController {
|
||||
constructor(private votesService: VotesService) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Get all votes
|
||||
*/
|
||||
@Get("/api/v1/super-admin/votes", [authHandler])
|
||||
protected async get(req: Request, response: Response) {
|
||||
try {
|
||||
//get query
|
||||
let query;
|
||||
if (req.query["q"]) {
|
||||
query = JSON.parse(req.query["q"] as string);
|
||||
}
|
||||
|
||||
//call service to get prisma entity
|
||||
const votesEntities = await this.votesService.get(query);
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const votes = Vote.hydrateArray<Vote>(votesEntities, { strategy: "excludeAll" });
|
||||
|
||||
//success
|
||||
this.httpSuccess(response, votes);
|
||||
} catch (error) {
|
||||
this.httpInternalError(response, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Get a specific vote by uid
|
||||
*/
|
||||
@Get("/api/v1/super-admin/votes/:uid", [authHandler])
|
||||
protected async getOneByUid(req: Request, response: Response) {
|
||||
try {
|
||||
const uid = req.params["uid"];
|
||||
if (!uid) {
|
||||
this.httpBadRequest(response, "No uid provided");
|
||||
return;
|
||||
}
|
||||
|
||||
let query;
|
||||
if (req.query["q"]) {
|
||||
query = JSON.parse(req.query["q"] as string);
|
||||
}
|
||||
|
||||
const voteEntity = await this.votesService.getByUid(uid, query);
|
||||
|
||||
if (!voteEntity) {
|
||||
this.httpNotFoundRequest(response, "vote not found");
|
||||
return;
|
||||
}
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const vote = Vote.hydrate<Vote>(voteEntity, { strategy: "excludeAll" });
|
||||
|
||||
//success
|
||||
this.httpSuccess(response, vote);
|
||||
} catch (error) {
|
||||
this.httpInternalError(response, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Delete a specific folder
|
||||
*/
|
||||
@Delete("/api/v1/super-admin/votes/:uid", [authHandler])
|
||||
protected async delete(req: Request, response: Response) {
|
||||
try {
|
||||
const uid = req.params["uid"];
|
||||
if (!uid) {
|
||||
this.httpBadRequest(response, "No uid provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const voteFound = await this.votesService.getByUid(uid);
|
||||
|
||||
if (!voteFound) {
|
||||
this.httpNotFoundRequest(response, "vote not found");
|
||||
return;
|
||||
}
|
||||
|
||||
//call service to get prisma entity
|
||||
const votetEntity: Votes = await this.votesService.delete(uid);
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const vote = Vote.hydrate<Vote>(votetEntity, { strategy: "excludeAll" });
|
||||
|
||||
//success
|
||||
this.httpSuccess(response, vote);
|
||||
} catch (error) {
|
||||
this.httpInternalError(response, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -40,6 +40,9 @@ import RolesControllerNotary from "./api/notary/RolesController";
|
||||
import OfficeRolesControllerNotary from "./api/notary/OfficeRolesController";
|
||||
import FilesControllerCustomer from "./api/customer/FilesController";
|
||||
import DocumentsControllerCustomer from "./api/customer/DocumentsController";
|
||||
import AppointmentsController from "./api/super-admin/AppointmentsController";
|
||||
import VotesController from "./api/super-admin/VotesController";
|
||||
import LiveVoteController from "./api/super-admin/LiveVoteController";
|
||||
|
||||
|
||||
/**
|
||||
@ -56,6 +59,9 @@ export default {
|
||||
Container.get(DeedTypesControllerSuperAdmin);
|
||||
Container.get(DocumentsControllerSuperAdmin);
|
||||
Container.get(DocumentTypesControllerSuperAdmin);
|
||||
Container.get(AppointmentsController);
|
||||
Container.get(VotesController);
|
||||
Container.get(LiveVoteController);
|
||||
Container.get(IdNotUserController);
|
||||
Container.get(FranceConnectCustomerController);
|
||||
Container.get(FilesControllerSuperAdmin);
|
||||
|
@ -0,0 +1,38 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_contact_uid_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_office_role_uid_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_office_uid_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_roles_uid_fkey";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "votes" (
|
||||
"uid" TEXT NOT NULL,
|
||||
"user_uid" VARCHAR(255) NOT NULL,
|
||||
"voters" TEXT[],
|
||||
|
||||
CONSTRAINT "votes_pkey" PRIMARY KEY ("uid")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "votes_uid_key" ON "votes"("uid");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_contact_uid_fkey" FOREIGN KEY ("contact_uid") REFERENCES "contacts"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_office_role_uid_fkey" FOREIGN KEY ("office_role_uid") REFERENCES "office_roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "votes" ADD CONSTRAINT "votes_user_uid_fkey" FOREIGN KEY ("user_uid") REFERENCES "users"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `user_uid` on the `votes` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `voters` on the `votes` table. All the data in the column will be lost.
|
||||
- Added the required column `appointment_uid` to the `votes` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `voter_uid` to the `votes` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "EVote" AS ENUM ('NOMINATE', 'DISMISS');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "EAppointmentStatus" AS ENUM ('OPEN', 'CLOSED');
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "votes" DROP CONSTRAINT "votes_user_uid_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "votes" DROP COLUMN "user_uid",
|
||||
DROP COLUMN "voters",
|
||||
ADD COLUMN "appointment_uid" VARCHAR(255) NOT NULL,
|
||||
ADD COLUMN "choice" "EVote" NOT NULL DEFAULT 'NOMINATE',
|
||||
ADD COLUMN "voter_uid" VARCHAR(255) NOT NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "appointments" (
|
||||
"uid" TEXT NOT NULL,
|
||||
"user_uid" VARCHAR(255) NOT NULL,
|
||||
"status" "EAppointmentStatus" NOT NULL DEFAULT 'OPEN',
|
||||
|
||||
CONSTRAINT "appointments_pkey" PRIMARY KEY ("uid")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "appointments_uid_key" ON "appointments"("uid");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "appointments" ADD CONSTRAINT "appointments_user_uid_fkey" FOREIGN KEY ("user_uid") REFERENCES "users"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "votes" ADD CONSTRAINT "votes_appointment_uid_fkey" FOREIGN KEY ("appointment_uid") REFERENCES "appointments"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "votes" ADD CONSTRAINT "votes_voter_uid_fkey" FOREIGN KEY ("voter_uid") REFERENCES "users"("uid") ON DELETE RESTRICT ON UPDATE CASCADE;
|
@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `choice` on the `votes` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "appointments" ADD COLUMN "choice" "EVote" NOT NULL DEFAULT 'NOMINATE';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "votes" DROP COLUMN "choice";
|
@ -0,0 +1,8 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[user_uid,choice,status]` on the table `appointments` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "appointments_user_uid_choice_status_key" ON "appointments"("user_uid", "choice", "status");
|
@ -65,6 +65,8 @@ model Users {
|
||||
office_uid String @db.VarChar(255)
|
||||
notifications Notifications[] @relation("UserHasNotifications")
|
||||
office_folders OfficeFolders[] @relation("OfficeFolderHasStakeholders")
|
||||
appointment Appointments[]
|
||||
votes Votes[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
@ -287,6 +289,28 @@ model Emails {
|
||||
@@map("email")
|
||||
}
|
||||
|
||||
model Appointments {
|
||||
uid String @id @unique @default(uuid())
|
||||
user Users @relation(fields: [user_uid], references: [uid], onDelete: Cascade)
|
||||
user_uid String @db.VarChar(255)
|
||||
choice EVote @default(NOMINATE)
|
||||
status EAppointmentStatus @default(OPEN)
|
||||
votes Votes[]
|
||||
|
||||
@@unique([user_uid, choice, status])
|
||||
@@map("appointments")
|
||||
}
|
||||
|
||||
model Votes {
|
||||
uid String @id @unique @default(uuid())
|
||||
appointment Appointments @relation(fields: [appointment_uid], references: [uid], onDelete: Cascade)
|
||||
appointment_uid String @db.VarChar(255)
|
||||
voter Users @relation(fields: [voter_uid], references: [uid])
|
||||
voter_uid String @db.VarChar(255)
|
||||
|
||||
@@map("votes")
|
||||
}
|
||||
|
||||
enum ECivility {
|
||||
MALE
|
||||
FEMALE
|
||||
@ -321,3 +345,13 @@ enum EDocumentStatus {
|
||||
ANCHORED
|
||||
REFUSED
|
||||
}
|
||||
|
||||
enum EVote {
|
||||
NOMINATE
|
||||
DISMISS
|
||||
}
|
||||
|
||||
enum EAppointmentStatus {
|
||||
OPEN
|
||||
CLOSED
|
||||
}
|
||||
|
@ -1,18 +1,7 @@
|
||||
import { ECivility, ECustomerStatus, EFolderStatus, EOfficeStatus, Prisma, PrismaClient } from "@prisma/client";
|
||||
import User, { Address, Contact, Customer, Deed, DeedType, DocumentType, Office, OfficeFolder, OfficeRole, Role, Rule } from "le-coffre-resources/dist/SuperAdmin";
|
||||
|
||||
import "module-alias/register";
|
||||
import { EFolderStatus, EOfficeStatus, ECivility, ECustomerStatus, PrismaClient, Prisma } from "@prisma/client";
|
||||
import User, {
|
||||
Address,
|
||||
Contact,
|
||||
Customer,
|
||||
Deed,
|
||||
DeedType,
|
||||
Office,
|
||||
OfficeFolder,
|
||||
OfficeRole,
|
||||
Role,
|
||||
Rule,
|
||||
DocumentType,
|
||||
} from "le-coffre-resources/dist/SuperAdmin";
|
||||
|
||||
export default async function main() {
|
||||
try{
|
||||
@ -605,7 +594,7 @@ export default async function main() {
|
||||
updated_at: new Date(),
|
||||
},
|
||||
{
|
||||
name: "PUT deedtypes",
|
||||
name: "PUT deed-types",
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
},
|
||||
@ -665,7 +654,7 @@ export default async function main() {
|
||||
updated_at: new Date(),
|
||||
},
|
||||
{
|
||||
name: "POST deedtypes",
|
||||
name: "POST deed-types",
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
},
|
||||
@ -862,26 +851,19 @@ export default async function main() {
|
||||
rules: rules.slice(0, 40),
|
||||
},
|
||||
{
|
||||
name: "notary",
|
||||
name: "Notaire",
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
office: offices[0]!,
|
||||
rules: rules.slice(0, 33),
|
||||
},
|
||||
{
|
||||
name: "deputy",
|
||||
name: "Collaborateur",
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
office: offices[0]!,
|
||||
rules: rules.slice(0, 22),
|
||||
},
|
||||
{
|
||||
name: "listener",
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
office: offices[0]!,
|
||||
rules: rules.slice(0, 11),
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
const users: User[] = [
|
||||
|
76
src/common/repositories/AppointmentsRepository.ts
Normal file
76
src/common/repositories/AppointmentsRepository.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import Database from "@Common/databases/database";
|
||||
import BaseRepository from "@Repositories/BaseRepository";
|
||||
import { Service } from "typedi";
|
||||
import { Appointments, EAppointmentStatus, Prisma } from "@prisma/client";
|
||||
|
||||
@Service()
|
||||
export default class AppointmentsRepository extends BaseRepository {
|
||||
constructor(private database: Database) {
|
||||
super();
|
||||
}
|
||||
protected get model() {
|
||||
return this.database.getClient().appointments;
|
||||
}
|
||||
protected get instanceDb() {
|
||||
return this.database.getClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find many appointments
|
||||
*/
|
||||
public async findMany(query: Prisma.AppointmentsFindManyArgs) {
|
||||
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||
return this.model.findMany(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Update data of a appointment
|
||||
*/
|
||||
public async update(uid: string, status: EAppointmentStatus): Promise<Appointments> {
|
||||
const updateArgs: Prisma.AppointmentsUpdateArgs = {
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
data: {
|
||||
status: status,
|
||||
},
|
||||
};
|
||||
|
||||
return this.model.update(updateArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find one appointment
|
||||
*/
|
||||
public async findOneByUid(uid: string, query?: Prisma.AppointmentsInclude) {
|
||||
return this.model.findUnique({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
include: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find one appointment with votes
|
||||
*/
|
||||
public async findOneByUidWithVotes(uid: string) {
|
||||
return this.model.findUnique({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
include: {votes: true},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : delete a appointment
|
||||
*/
|
||||
public async delete(uid: string): Promise<Appointments> {
|
||||
return this.model.delete({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ import Database from "@Common/databases/database";
|
||||
import BaseRepository from "@Repositories/BaseRepository";
|
||||
import { Service } from "typedi";
|
||||
import { ECivility, Prisma, Users } from "@prisma/client";
|
||||
import User from "le-coffre-resources/dist/SuperAdmin";
|
||||
import User, { Role } from "le-coffre-resources/dist/SuperAdmin";
|
||||
|
||||
@Service()
|
||||
export default class UsersRepository extends BaseRepository {
|
||||
@ -196,6 +196,18 @@ export default class UsersRepository extends BaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find one user with office
|
||||
*/
|
||||
public async findOneByUidWithRole(uid: string): Promise<((Users & {role: Role} )| null)> {
|
||||
return this.model.findUnique({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
include: { role: true },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find one user
|
||||
*/
|
||||
|
89
src/common/repositories/VotesRepository.ts
Normal file
89
src/common/repositories/VotesRepository.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import Database from "@Common/databases/database";
|
||||
import { EAppointmentStatus, EVote, Prisma, Votes } from "@prisma/client";
|
||||
import BaseRepository from "@Repositories/BaseRepository";
|
||||
import { Vote } from "le-coffre-resources/dist/SuperAdmin";
|
||||
import { Service } from "typedi";
|
||||
|
||||
@Service()
|
||||
export default class VotesRepository extends BaseRepository {
|
||||
constructor(private database: Database) {
|
||||
super();
|
||||
}
|
||||
protected get model() {
|
||||
return this.database.getClient().votes;
|
||||
}
|
||||
protected get instanceDb() {
|
||||
return this.database.getClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find many votes
|
||||
*/
|
||||
public async findMany(query: Prisma.VotesFindManyArgs) {
|
||||
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||
return this.model.findMany(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Create new vote
|
||||
*/
|
||||
public async create(vote: Vote): Promise<Votes> {
|
||||
let whereArg: Prisma.AppointmentsWhereUniqueInput;
|
||||
if(vote.appointment.targeted_user.uid) {
|
||||
whereArg = {
|
||||
user_uid_choice_status: {
|
||||
user_uid: vote.appointment.targeted_user.uid,
|
||||
choice: EVote[vote.appointment.choice as keyof typeof EVote],
|
||||
status: EAppointmentStatus.OPEN,
|
||||
}
|
||||
};
|
||||
} else {
|
||||
whereArg = {
|
||||
uid: vote.appointment.uid,
|
||||
};
|
||||
}
|
||||
const createArgs: Prisma.VotesCreateArgs = {
|
||||
data: {
|
||||
appointment: {
|
||||
connectOrCreate: {
|
||||
where: whereArg,
|
||||
create: {
|
||||
choice: EVote[vote.appointment.choice as keyof typeof EVote],
|
||||
user_uid: vote.appointment.targeted_user.uid!,
|
||||
}
|
||||
},
|
||||
},
|
||||
voter: {
|
||||
connect: {
|
||||
uid: vote.voter.uid,
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
return this.model.create({...createArgs, include: {appointment: {include: {votes: true}}}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find one vote
|
||||
*/
|
||||
public async findOneByUid(uid: string, query?: Prisma.VotesInclude): Promise<Votes | null> {
|
||||
return this.model.findUnique({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
include: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : delete a vote
|
||||
*/
|
||||
public async delete(uid: string): Promise<Votes> {
|
||||
return this.model.delete({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import BaseService from "@Services/BaseService";
|
||||
import { Service } from "typedi";
|
||||
import AppointmentsRepository from "@Repositories/AppointmentsRepository";
|
||||
import { Prisma, Appointments, EAppointmentStatus } from "@prisma/client";
|
||||
|
||||
@Service()
|
||||
export default class AppointmentService extends BaseService {
|
||||
constructor(private appointmentRepository: AppointmentsRepository) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get all appointments
|
||||
* @throws {Error} If appointments cannot be get
|
||||
*/
|
||||
public get(query: Prisma.AppointmentsFindManyArgs) {
|
||||
return this.appointmentRepository.findMany(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Modify a appointment
|
||||
* @throws {Error} If appointment cannot be modified
|
||||
*/
|
||||
public async update(uid: string, status: EAppointmentStatus): Promise<Appointments> {
|
||||
return this.appointmentRepository.update(uid, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get a appointment by uid
|
||||
* @throws {Error} If appointment cannot be get by uid
|
||||
*/
|
||||
public getByUid(uid: string, query?: Prisma.AppointmentsInclude): Promise<Appointments | null> {
|
||||
return this.appointmentRepository.findOneByUid(uid, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get a appointment by uid
|
||||
* @throws {Error} If appointment cannot be get by uid
|
||||
*/
|
||||
public getByUidWithVotes(uid: string) {
|
||||
return this.appointmentRepository.findOneByUidWithVotes(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : delete a appointment by uid
|
||||
* @throws {Error} If appointment cannot be get by uid
|
||||
*/
|
||||
public delete(uid: string) {
|
||||
return this.appointmentRepository.delete(uid);
|
||||
}
|
||||
|
||||
|
||||
}
|
97
src/services/super-admin/LiveVoteService/LiveVoteService.ts
Normal file
97
src/services/super-admin/LiveVoteService/LiveVoteService.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import BaseService from "@Services/BaseService";
|
||||
import { Service } from "typedi";
|
||||
import User, { Appointment, Role, Vote } from "le-coffre-resources/dist/SuperAdmin";
|
||||
import VotesRepository from "@Repositories/VotesRepository";
|
||||
import { Appointments, EAppointmentStatus, EVote, Votes } from "@prisma/client";
|
||||
import AppointmentService from "../AppointmentsService/AppointmentsService";
|
||||
import UsersService from "../UsersService/UsersService";
|
||||
import RolesService from "../RolesService/RolesService";
|
||||
|
||||
@Service()
|
||||
export default class LiveVoteService extends BaseService {
|
||||
constructor(
|
||||
private voteRepository: VotesRepository,
|
||||
private appointmentService: AppointmentService,
|
||||
private userService: UsersService,
|
||||
private roleService: RolesService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public async verifyVoterChoice(vote: Vote): Promise<boolean> {
|
||||
const userWithRole = await this.userService.getByUidWithRole(vote.appointment.targeted_user.uid!);
|
||||
if (userWithRole!.role.name === "super-admin" && vote.appointment.choice === EVote.DISMISS) {
|
||||
return true;
|
||||
}
|
||||
if (userWithRole!.role.name !== "super-admin" && vote.appointment.choice === EVote.NOMINATE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async getAppointmentWithVotes(vote: Vote): Promise<Appointments | null> {
|
||||
if (vote.appointment.uid) {
|
||||
return this.appointmentService.getByUidWithVotes(vote.appointment.uid);
|
||||
}
|
||||
const appointmentByUser = await this.appointmentService.get({
|
||||
where: {
|
||||
AND: [
|
||||
{ user_uid: vote.appointment.targeted_user.uid },
|
||||
{ status: EAppointmentStatus.OPEN },
|
||||
{ choice: EVote[vote.appointment.choice as keyof typeof EVote] },
|
||||
],
|
||||
},
|
||||
include: { votes: true },
|
||||
});
|
||||
if (appointmentByUser.length >= 1) {
|
||||
return this.appointmentService.getByUidWithVotes(appointmentByUser[0]!.uid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async closeVote(appointment: Appointments, vote: Votes) {
|
||||
await this.appointmentService.update(vote.appointment_uid, EAppointmentStatus.CLOSED);
|
||||
const user = await this.userService.getByUid(appointment.user_uid, { role: true });
|
||||
const userEntity = User.hydrate<User>(user!, { strategy: "excludeAll" });
|
||||
|
||||
return await this.updateRole(appointment, userEntity, vote);
|
||||
}
|
||||
|
||||
private async updateRole(appointment: Appointments, userEntity: User, vote: Votes) {
|
||||
if (appointment.choice === EVote.DISMISS) {
|
||||
const roles = await this.roleService.get({ where: { name: "default" } });
|
||||
const roleEntity = Role.hydrate<Role>(roles[0]!, { strategy: "excludeAll" });
|
||||
userEntity.role = roleEntity;
|
||||
await this.userService.update(appointment!.user_uid, userEntity);
|
||||
return vote;
|
||||
} else if (appointment.choice === EVote.NOMINATE) {
|
||||
const roles = await this.roleService.get({ where: { name: "super-admin" } });
|
||||
const roleEntity = Role.hydrate<Role>(roles[0]!, { strategy: "excludeAll" });
|
||||
userEntity!.role = roleEntity;
|
||||
await this.userService.update(appointment!.user_uid, userEntity);
|
||||
return vote;
|
||||
}
|
||||
return vote;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Create a vote
|
||||
* @throws {Error} If vote couldn't be created
|
||||
*/
|
||||
public async create(vote: Vote): Promise<Votes | null> {
|
||||
const appointment = await this.getAppointmentWithVotes(vote);
|
||||
|
||||
if (appointment) {
|
||||
const appointmentEntity = Appointment.hydrate<Appointment>(appointment, { strategy: "excludeAll" });
|
||||
if (appointmentEntity?.votes && appointmentEntity.votes.length >= 2) {
|
||||
const voteCreated = await this.voteRepository.create(vote);
|
||||
return this.closeVote(appointment, voteCreated);
|
||||
}
|
||||
}
|
||||
|
||||
const approvedChoice = await this.verifyVoterChoice(vote);
|
||||
if(!approvedChoice) return null;
|
||||
|
||||
return this.voteRepository.create(vote);
|
||||
}
|
||||
}
|
@ -51,6 +51,14 @@ export default class UsersService extends BaseService {
|
||||
return this.userRepository.findOneByUidWithOffice(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get a user by uid with role
|
||||
* @throws {Error} If user cannot be get by uid
|
||||
*/
|
||||
public getByUidWithRole(uid: string) {
|
||||
return this.userRepository.findOneByUidWithRole(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get a user by uid
|
||||
* @throws {Error} If user cannot be get by uid
|
||||
|
35
src/services/super-admin/VotesService/VotesService.ts
Normal file
35
src/services/super-admin/VotesService/VotesService.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import BaseService from "@Services/BaseService";
|
||||
import { Service } from "typedi";
|
||||
import VotesRepository from "@Repositories/VotesRepository";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
@Service()
|
||||
export default class VoteService extends BaseService {
|
||||
constructor(private voteRepository: VotesRepository) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get all votes
|
||||
* @throws {Error} If votes cannot be get
|
||||
*/
|
||||
public get(query: Prisma.VotesFindManyArgs) {
|
||||
return this.voteRepository.findMany(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get a vote by uid
|
||||
* @throws {Error} If vote cannot be get by uid
|
||||
*/
|
||||
public getByUid(uid: string, query?: Prisma.VotesInclude) {
|
||||
return this.voteRepository.findOneByUid(uid, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : delete a vote by uid
|
||||
* @throws {Error} If vote cannot be get by uid
|
||||
*/
|
||||
public delete(uid: string) {
|
||||
return this.voteRepository.delete(uid);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user