diff --git a/.circleci/config.yml b/.circleci/config.yml index a634f6f7..fdc87482 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,8 +21,8 @@ jobs: version: 20.10.12 docker_layer_caching: true - run: docker login rg.fr-par.scw.cloud/lecoffre -u nologin -p $SCW_SECRET_KEY - - run: docker build --tag rg.fr-par.scw.cloud/lecoffre/back:$TAG . - - run: docker push rg.fr-par.scw.cloud/lecoffre/back:$TAG + - run: docker build --tag rg.fr-par.scw.cloud/lecoffre/back:${CIRCLE_SHA1:0:7} . + - run: docker push rg.fr-par.scw.cloud/lecoffre/back:${CIRCLE_SHA1:0:7} deploy-docker-image: @@ -34,6 +34,10 @@ jobs: - image: cimg/base:stable environment: TAG: << pipeline.git.tag >> + parameters: + env: + type: string + default: stg steps: - checkout - kubernetes/install-kubeconfig: @@ -43,78 +47,63 @@ jobs: name: Deploy command: > helm upgrade - lecoffre-back devops/ -i -f devops/values.yaml - -n lecoffre + lecoffre-back devops/ -i -f devops/<>.values.yaml + -n lecoffre-<> --create-namespace --set lecoffreBack.image.repository='rg.fr-par.scw.cloud/lecoffre/back' - --set lecoffreBack.image.tag=$TAG + --set lecoffreBack.image.tag=${CIRCLE_SHA1:0:7} + --set lecoffreCron.image.repository='rg.fr-par.scw.cloud/lecoffre/back' + --set lecoffreCron.image.tag=${CIRCLE_SHA1:0:7} + workflows: version: 2 - build-and-deploy-stg: + build-and-register-stg: jobs: - build-push-docker-image: filters: - tags: - only: /^v.*/ branches: - ignore: /.*/ - context: - - staging + only: staging - deploy-docker-image: env: stg requires: - build-push-docker-image context: - - staging + - sc-shared-prd filters: - tags: - only: /^v.*/ branches: - ignore: /.*/ + only: staging - build-and-deploy-ppd: + build-and-register-ppd: jobs: - build-push-docker-image: filters: - tags: - only: /^v.*/ branches: - ignore: /.*/ - context: - - production + only: preprod - deploy-docker-image: env: ppd requires: - build-push-docker-image context: - - production + - sc-shared-prd filters: - tags: - only: /^v.*/ branches: - ignore: /.*/ + only: preprod - - # build-and-deploy-prod: - # jobs: - # - build-push-docker-image: - # filters: - # tags: - # only: /^v.*/ - # branches: - # ignore: /.*/ - # context: - # - production - # - deploy-docker-image: - # requires: - # - build-push-docker-image - # context: - # - production - # filters: - # tags: - # only: /^v.*/ - # branches: - # ignore: /.*/ + build-and-register-prd: + jobs: + - build-push-docker-image: + filters: + branches: + only: main + - deploy-docker-image: + env: prd + requires: + - build-push-docker-image + context: + - sc-shared-prd + filters: + branches: + only: main diff --git a/.gitignore b/.gitignore index e505544c..5d7e9ac1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ dist # dependencies /node_modules +package-lock.json # envs .env diff --git a/Dockerfile b/Dockerfile index 178e062e..85e1458c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,5 +42,5 @@ COPY --from=builder --chown=lecoffreuser leCoffre/src/common/databases ./src/com USER lecoffreuser -CMD ["npm", "run", "start"] +CMD ["npm", "run", "api:start"] EXPOSE 3001 \ No newline at end of file diff --git a/Dockerfile-Cron b/Dockerfile-Cron new file mode 100644 index 00000000..3dbfefe4 --- /dev/null +++ b/Dockerfile-Cron @@ -0,0 +1,46 @@ +# Install dependencies only when needed +FROM node:19-alpine AS deps + +WORKDIR leCoffre + +RUN npm install -D prisma@4.11.0 +COPY package.json ./ + +RUN apk update && apk add openssh-client git + +COPY id_rsa /root/.ssh/id_rsa +RUN chmod 600 ~/.ssh/id_rsa +RUN eval "$(ssh-agent -s)" && ssh-add /root/.ssh/id_rsa +RUN ssh-keyscan github.com smart-chain-fr/leCoffre-resources.git >> /root/.ssh/known_hosts + +RUN npm install --frozen-lockfile + +# Rebuild the source code only when needed +FROM node:19-alpine AS builder + +WORKDIR leCoffre + +COPY --from=deps leCoffre/node_modules ./node_modules +COPY --from=deps leCoffre/package.json package.json +COPY tsconfig.json tsconfig.json +COPY src src + +RUN npx prisma generate +RUN npm run build + +# Production image, copy all the files and run next +FROM node:19-alpine AS production + +WORKDIR leCoffre + +RUN adduser -D lecoffreuser --uid 10000 && chown -R lecoffreuser . + +COPY --from=builder --chown=lecoffreuser leCoffre/node_modules ./node_modules +COPY --from=builder --chown=lecoffreuser leCoffre/dist dist +COPY --from=builder --chown=lecoffreuser leCoffre/package.json ./package.json +COPY --from=builder --chown=lecoffreuser leCoffre/src/common/databases ./src/common/databases + +USER lecoffreuser + +CMD ["npm", "run", "cron"] +EXPOSE 3001 \ No newline at end of file diff --git a/devops/Chart.yaml b/devops/Chart.yaml index 208511fb..91793269 100644 --- a/devops/Chart.yaml +++ b/devops/Chart.yaml @@ -21,5 +21,5 @@ version: 0.0.1 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: 0.5.6 +appVersion: 0.5.7 diff --git a/devops/ppd.values.yaml b/devops/ppd.values.yaml index 95794f2e..ba5c13a9 100644 --- a/devops/ppd.values.yaml +++ b/devops/ppd.values.yaml @@ -1,24 +1,11 @@ -dockerPullSecret: secret/data/minteed-ppd/config/dockerpullsecret +dockerPullSecret: docker-pull-secret -namespace: lecoffre +scwSecretKey: AgCgjF5QEzxT3GYTS5B6cmQ0e+0/qFWzKaUDSi+Vjc7RoameuvaIJvTXMBkS3he1oy1ulbB34v6vpZI2kxnGNqERA/U5BaYDAyfKSBwMAy4br7HVKhhuwkoF5qoG5JzJXseSmqB1U9vncVIGOZWzJc1Y4/eGlWcvLcLyfw2z/WEpyeNiWJfEhTYpJOB7gv0XnRb2U/JM3jRy1QgEUIk1WR6kgBalF+xaczPQ6uKh+PR2pqkbZa3WaKUrddmzNsgEz4d8PZMWt8IBwR2JOQEHUqCd34p/pJNyLdUgcdDhg02DKwn1oRoAxKTbAio/a7WrMbodjCb3TNWIYGal5mFmItZ7Ok/EBmUf4E85eOkTR+j8ynuuiexld3Q5Kw3o8LsHjgzVL9uP+T2rYaKkjtVt+YQRX1U8l9CrsdUEz0/wEBA0jwCWMfnh1qhD5pM/xwwjsEEAcK4rYV+Q7iAgGZZvZBCQ5aEHzrtn5D95tr1GZCV2hmrW6Seu+LKKLVBS1JmsuEsOuhudYsEK9m2RYVcxbjuS5eokKEjNrGobf2oB8rhBByavfw1JTBixR5JrI8lcYlnCa+oEhxXKJY+4Fx5SAB4YaLCMSo5vw6zsFQ3WKQzlEmCFt+EnapS+a+MGrdlwq07OHTDpvgk/1z39hopoCuhhKckGGfErLXsTYQvDOkFu+EPzgY7m7qDw/d9pSiht5tuSOkAqeOgm7tpNkUufZhaXmP+1aT7i+H5gq1JILGAmXzTI5Wc= lecoffreBack: serviceAccountName: lecoffre-back-sa - command: "'sh', '-c', '. /vault/secrets/envs-api && npm run api:start'" - vault: - role : custom_lecoffre-back_injector_rol - server: https://vault-ppd.smart-chain.fr - annotations: - vault.hashicorp.com/agent-pre-populate-only: "true" - vault.hashicorp.com/agent-inject: "true" - vault.hashicorp.com/agent-inject-secret-envs-api: secret/data/lecoffre-back-ppd/config/envs-api - vault.hashicorp.com/role: custom_lecoffre-back_injector_rol - vault.hashicorp.com/agent-inject-template-envs-api: | - {{ with secret "secret/data/lecoffre-back-ppd/config/envs-api" }} - {{ range $k, $v := .Data.data }} - export {{ $k }}="{{ $v }}" - {{ end }} - {{ end }} + command: "'sh', '-c', 'export $(xargs =6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { - "version": "7.21.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", - "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", + "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-compilation-targets": "^7.22.10", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.10", + "@babel/parser": "^7.22.10", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.10", + "@babel/types": "^7.22.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -143,12 +222,12 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", - "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", + "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", "dev": true, "dependencies": { - "@babel/types": "^7.21.5", + "@babel/types": "^7.22.10", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -158,16 +237,78 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", - "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", + "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.21.5", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -176,153 +317,88 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz", - "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz", - "integrity": "sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", - "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@babel/types": "^7.21.5" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", - "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", - "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", + "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.10", + "@babel/types": "^7.22.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", + "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -401,9 +477,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz", - "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", + "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -473,12 +549,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -575,12 +651,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -590,33 +666,33 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", - "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", + "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.5", - "@babel/types": "^7.21.5", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.10", + "@babel/types": "^7.22.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -648,13 +724,13 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz", - "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", + "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.21.5", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -713,16 +789,16 @@ } }, "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.2.tgz", + "integrity": "sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2", "slash": "^3.0.0" }, "engines": { @@ -730,16 +806,16 @@ } }, "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.2.tgz", + "integrity": "sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg==", "dev": true, "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/console": "^29.6.2", + "@jest/reporters": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", @@ -747,20 +823,20 @@ "exit": "^0.1.2", "graceful-fs": "^4.2.9", "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", + "jest-config": "^29.6.2", + "jest-haste-map": "^29.6.2", + "jest-message-util": "^29.6.2", "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", + "jest-resolve": "^29.6.2", + "jest-resolve-dependencies": "^29.6.2", + "jest-runner": "^29.6.2", + "jest-runtime": "^29.6.2", + "jest-snapshot": "^29.6.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", + "jest-watcher": "^29.6.2", "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", + "pretty-format": "^29.6.2", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -777,37 +853,37 @@ } }, "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.2.tgz", + "integrity": "sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/fake-timers": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", - "jest-mock": "^29.5.0" + "jest-mock": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.2.tgz", + "integrity": "sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg==", "dev": true, "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" + "expect": "^29.6.2", + "jest-snapshot": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.2.tgz", + "integrity": "sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg==", "dev": true, "dependencies": { "jest-get-type": "^29.4.3" @@ -817,49 +893,49 @@ } }, "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.2.tgz", + "integrity": "sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" + "jest-message-util": "^29.6.2", + "jest-mock": "^29.6.2", + "jest-util": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.2.tgz", + "integrity": "sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw==", "dev": true, "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" + "@jest/environment": "^29.6.2", + "@jest/expect": "^29.6.2", + "@jest/types": "^29.6.1", + "jest-mock": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.2.tgz", + "integrity": "sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", + "@jest/console": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", + "@jridgewell/trace-mapping": "^0.3.18", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -871,9 +947,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2", + "jest-worker": "^29.6.2", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -892,24 +968,24 @@ } }, "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "version": "29.6.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", + "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.25.16" + "@sinclair/typebox": "^0.27.8" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "version": "29.6.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.0.tgz", + "integrity": "sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", + "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", "graceful-fs": "^4.2.9" }, @@ -918,13 +994,13 @@ } }, "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.2.tgz", + "integrity": "sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw==", "dev": true, "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/console": "^29.6.2", + "@jest/types": "^29.6.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -933,14 +1009,14 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz", + "integrity": "sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw==", "dev": true, "dependencies": { - "@jest/test-result": "^29.5.0", + "@jest/test-result": "^29.6.2", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", + "jest-haste-map": "^29.6.2", "slash": "^3.0.0" }, "engines": { @@ -948,22 +1024,22 @@ } }, "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.2.tgz", + "integrity": "sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", + "@jest/types": "^29.6.1", + "@jridgewell/trace-mapping": "^0.3.18", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", + "jest-haste-map": "^29.6.2", "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", + "jest-util": "^29.6.2", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -974,12 +1050,12 @@ } }, "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "version": "29.6.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.1.tgz", + "integrity": "sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.3", + "@jest/schemas": "^29.6.0", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -1005,9 +1081,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "engines": { "node": ">=6.0.0" } @@ -1027,30 +1103,35 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "node_modules/@mailchimp/mailchimp_transactional": { + "version": "1.0.50", + "resolved": "https://registry.npmjs.org/@mailchimp/mailchimp_transactional/-/mailchimp_transactional-1.0.50.tgz", + "integrity": "sha512-SaNFseFPSDQlOYM9JTyYY6wauMu6qJ8eExo+jssFyb20ZaVvxKX1eTb3Gm5aW/4aWuxn6nofU+02sCk51//wdw==", + "dependencies": { + "axios": "^0.21.1" + }, + "engines": { + "node": ">=10.0.0" + } }, "node_modules/@next/env": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.1.tgz", - "integrity": "sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg==" + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.16.tgz", + "integrity": "sha512-pCU0sJBqdfKP9mwDadxvZd+eLz3fZrTlmmDHY12Hdpl3DD0vy8ou5HWKVfG0zZS6tqhL4wnQqRbspdY5nqa7MA==" }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz", - "integrity": "sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.16.tgz", + "integrity": "sha512-Rl6i1uUq0ciRa3VfEpw6GnWAJTSKo9oM2OrkGXPsm7rMxdd2FR5NkKc0C9xzFCI4+QtmBviWBdF2m3ur3Nqstw==", "cpu": [ "arm64" ], @@ -1063,9 +1144,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz", - "integrity": "sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.16.tgz", + "integrity": "sha512-o1vIKYbZORyDmTrPV1hApt9NLyWrS5vr2p5hhLGpOnkBY1cz6DAXjv8Lgan8t6X87+83F0EUDlu7klN8ieZ06A==", "cpu": [ "x64" ], @@ -1078,9 +1159,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz", - "integrity": "sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.16.tgz", + "integrity": "sha512-JRyAl8lCfyTng4zoOmE6hNI2f1MFUr7JyTYCHl1RxX42H4a5LMwJhDVQ7a9tmDZ/yj+0hpBn+Aan+d6lA3v0UQ==", "cpu": [ "arm64" ], @@ -1093,9 +1174,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz", - "integrity": "sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.16.tgz", + "integrity": "sha512-9gqVqNzUMWbUDgDiND18xoUqhwSm2gmksqXgCU0qaOKt6oAjWz8cWYjgpPVD0WICKFylEY/gvPEP1fMZDVFZ/g==", "cpu": [ "arm64" ], @@ -1108,9 +1189,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz", - "integrity": "sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.16.tgz", + "integrity": "sha512-KcQGwchAKmZVPa8i5PLTxvTs1/rcFnSltfpTm803Tr/BtBV3AxCkHLfhtoyVtVzx/kl/oue8oS+DSmbepQKwhw==", "cpu": [ "x64" ], @@ -1123,9 +1204,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz", - "integrity": "sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.16.tgz", + "integrity": "sha512-2RbMZNxYnJmW8EPHVBsGZPq5zqWAyBOc/YFxq/jIQ/Yn3RMFZ1dZVCjtIcsiaKmgh7mjA/W0ApbumutHNxRqqQ==", "cpu": [ "x64" ], @@ -1138,9 +1219,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz", - "integrity": "sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.16.tgz", + "integrity": "sha512-thDcGonELN7edUKzjzlHrdoKkm7y8IAdItQpRvvMxNUXa4d9r0ElofhTZj5emR7AiXft17hpen+QAkcWpqG7Jg==", "cpu": [ "arm64" ], @@ -1153,9 +1234,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz", - "integrity": "sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.16.tgz", + "integrity": "sha512-f7SE1Mo4JAchUWl0LQsbtySR9xCa+x55C0taetjUApKtcLR3AgAjASrrP+oE1inmLmw573qRnE1eZN8YJfEBQw==", "cpu": [ "ia32" ], @@ -1168,9 +1249,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz", - "integrity": "sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.16.tgz", + "integrity": "sha512-WamDZm1M/OEM4QLce3lOmD1XdLEl37zYZwlmOLhmF7qYJ2G6oYm9+ejZVv+LakQIsIuXhSpVlOvrxIAHqwRkPQ==", "cpu": [ "x64" ], @@ -1194,12 +1275,12 @@ } }, "node_modules/@prisma/client": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.14.0.tgz", - "integrity": "sha512-MK/XaA2sFdfaOa7I9MjNKz6dxeIEdeZlnpNRoF2w3JuRLlFJLkpp6cD3yaqw2nUUhbrn3Iqe3ZpVV+VuGGil7Q==", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.2.tgz", + "integrity": "sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==", "hasInstallScript": true, "dependencies": { - "@prisma/engines-version": "4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c" + "@prisma/engines-version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81" }, "engines": { "node": ">=14.17" @@ -1214,39 +1295,39 @@ } }, "node_modules/@prisma/engines": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.14.0.tgz", - "integrity": "sha512-PDNlhP/1vyTgmNyiucGqGCdXIp7HIkkvKO50si3y3PcceeHvqtiKPaH1iJdz63jCWMVMbj2MElSxXPOeBvEVIQ==", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.2.tgz", + "integrity": "sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==", "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { - "version": "4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c.tgz", - "integrity": "sha512-3jum8/YSudeSN0zGW5qkpz+wAN2V/NYCQ+BPjvHYDfWatLWlQkqy99toX0GysDeaUoBIJg1vaz2yKqiA3CFcQw==" + "version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81.tgz", + "integrity": "sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==" }, "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^2.0.0" + "@sinonjs/commons": "^3.0.0" } }, "node_modules/@swc/helpers": { @@ -1273,14 +1354,14 @@ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" }, "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" }, "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -1310,12 +1391,12 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.5.tgz", - "integrity": "sha512-enCvTL8m/EHS/zIvJno9nE+ndYPh1/oNFzRYRmtUqJICG2VnCSBzMLW5VN2KCQU91f23tsNKR8v7VJJQMatl7Q==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", "dev": true, "dependencies": { - "@babel/types": "^7.3.0" + "@babel/types": "^7.20.7" } }, "node_modules/@types/body-parser": { @@ -1346,6 +1427,16 @@ "@types/node": "*" } }, + "node_modules/@types/cron": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.4.0.tgz", + "integrity": "sha512-5bBaAkqvSFBX8JMi/xCofNzG5E594TNsApMz68dLd/sQYz/HGQqgcxGHTRjOvD4G3Y+YF1Oo3S7QdCvKt1KAJQ==", + "deprecated": "This is a stub types definition. cron provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "cron": "*" + } + }, "node_modules/@types/express": { "version": "4.17.17", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", @@ -1359,9 +1450,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.34", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", - "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", "dev": true, "dependencies": { "@types/node": "*", @@ -1379,6 +1470,12 @@ "@types/node": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==", + "dev": true + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -1404,9 +1501,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.1.tgz", - "integrity": "sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==", + "version": "29.5.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.3.tgz", + "integrity": "sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1422,12 +1519,27 @@ "@types/node": "*" } }, + "node_modules/@types/mailchimp__mailchimp_transactional": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mailchimp__mailchimp_transactional/-/mailchimp__mailchimp_transactional-1.0.5.tgz", + "integrity": "sha512-5LYI3dZcyVBtg+lNxhKBHrHnNeAVvlpPM0kO6FZcjrrMALK7wistwvqI8PAns2mnveC67OSN43y6wQkK6KeTNQ==", + "dev": true, + "dependencies": { + "axios": "^0.21.1" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "node_modules/@types/module-alias": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/module-alias/-/module-alias-2.0.2.tgz", + "integrity": "sha512-Oeo5NEjAceFgN8OzGiLXPswgv2GBmrDGuTnLS0sQ8g4Mq5sB5c97Hu5B+n9Gu/j+5Y+oUb4TSawHXkZ8MENGyw==", + "dev": true + }, "node_modules/@types/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", @@ -1438,9 +1550,33 @@ } }, "node_modules/@types/node": { - "version": "18.16.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.7.tgz", - "integrity": "sha512-MFg7ua/bRtnA1hYE3pVyWxGd/r7aMqjNOdHvlSsXV3n8iaeGKkOaPzpJh6/ovf4bEXWcojkeMJpTsq3mzXW4IQ==" + "version": "18.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.5.tgz", + "integrity": "sha512-xNbS75FxH6P4UXTPUJp/zNPq6/xsfdJKussCWNOnz4aULWIRwMgP1LgaB5RiBnMX1DPCYenuqGZfnIAx5mbFLA==" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } }, "node_modules/@types/node-schedule": { "version": "2.1.0", @@ -1451,12 +1587,6 @@ "@types/node": "*" } }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -1480,11 +1610,12 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", "dev": true, "dependencies": { + "@types/http-errors": "*", "@types/mime": "*", "@types/node": "*" } @@ -1496,15 +1627,15 @@ "dev": true }, "node_modules/@types/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", + "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", "dev": true }, "node_modules/@types/validator": { - "version": "13.7.17", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.17.tgz", - "integrity": "sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ==" + "version": "13.11.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.1.tgz", + "integrity": "sha512-d/MUkJYdOeKycmm75Arql4M5+UuXmf4cHdHKsyw1GcvnNgL6s77UkgSgJ8TE/rI5PYsnwYq5jkcWBLuN/MpQ1A==" }, "node_modules/@types/yargs": { "version": "17.0.24", @@ -1540,9 +1671,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "bin": { "acorn": "bin/acorn" }, @@ -1648,12 +1779,12 @@ } }, "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.2.tgz", + "integrity": "sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A==", "dev": true, "dependencies": { - "@jest/transform": "^29.5.0", + "@jest/transform": "^29.6.2", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.5.0", @@ -1826,9 +1957,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "funding": [ { @@ -1838,13 +1969,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -1965,9 +2100,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001486", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001486.tgz", - "integrity": "sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg==", + "version": "1.0.30001521", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001521.tgz", + "integrity": "sha512-fnx1grfpEOvDGH+V17eccmNjucGUnCbP6KL+l5KqBIerp26WK/+RQ7CIDE37KGJjaPyqWXXlFUyKiWmvdNNKmQ==", "funding": [ { "type": "opencollective", @@ -2068,9 +2203,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, "node_modules/class-is": { @@ -2136,9 +2271,9 @@ } }, "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, "node_modules/color-convert": { @@ -2250,10 +2385,18 @@ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, + "node_modules/cron": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.4.1.tgz", + "integrity": "sha512-ty0hUSPuENwDtIShDFxUxWEIsqiu2vhoFtt6Vwrbg4lHGtJX2/cV2p0hH6/qaEM9Pj+i6mQoau48BO5wBpkP4w==", + "dependencies": { + "luxon": "^3.2.1" + } + }, "node_modules/cron-parser": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.8.1.tgz", - "integrity": "sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", "dependencies": { "luxon": "^3.2.1" }, @@ -2284,10 +2427,18 @@ } }, "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } }, "node_modules/deepmerge": { "version": "4.3.1", @@ -2350,12 +2501,15 @@ } }, "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, "node_modules/ecdsa-sig-formatter": { @@ -2372,9 +2526,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.391", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.391.tgz", - "integrity": "sha512-GqydVV1+kUWY5qlEzaw34/hyWTApuQrHiGrcGA2Kk/56nEK44i+YUW45VH43JuZT0Oo7uY8aVtpPhBBZXEWtSA==", + "version": "1.4.492", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.492.tgz", + "integrity": "sha512-36K9b/6skMVwAIEsC7GiQ8I8N3soCALVSHqWHzNDtGemAcI9Xu8hP02cywWM0A794rTHm0b0zHPeLJHtgFVamQ==", "dev": true }, "node_modules/emittery": { @@ -2489,16 +2643,17 @@ } }, "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.2.tgz", + "integrity": "sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.5.0", + "@jest/expect-utils": "^29.6.2", + "@types/node": "*", "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" + "jest-matcher-utils": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2694,12 +2849,13 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { @@ -2759,6 +2915,11 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2771,8 +2932,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has": { "version": "1.0.3", @@ -2794,6 +2954,17 @@ "node": ">=8" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -2949,9 +3120,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3081,17 +3252,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": { @@ -3132,9 +3303,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", @@ -3145,15 +3316,15 @@ } }, "node_modules/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.2.tgz", + "integrity": "sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==", "dev": true, "dependencies": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/core": "^29.6.2", + "@jest/types": "^29.6.1", "import-local": "^3.0.2", - "jest-cli": "^29.5.0" + "jest-cli": "^29.6.2" }, "bin": { "jest": "bin/jest.js" @@ -3184,28 +3355,28 @@ } }, "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.2.tgz", + "integrity": "sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw==", "dev": true, "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/environment": "^29.6.2", + "@jest/expect": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "dedent": "^0.7.0", + "dedent": "^1.0.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", + "jest-each": "^29.6.2", + "jest-matcher-utils": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-runtime": "^29.6.2", + "jest-snapshot": "^29.6.2", + "jest-util": "^29.6.2", "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", + "pretty-format": "^29.6.2", "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" @@ -3215,21 +3386,21 @@ } }, "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.2.tgz", + "integrity": "sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q==", "dev": true, "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/core": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/types": "^29.6.1", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", + "jest-config": "^29.6.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -3249,31 +3420,31 @@ } }, "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.2.tgz", + "integrity": "sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", + "@jest/test-sequencer": "^29.6.2", + "@jest/types": "^29.6.1", + "babel-jest": "^29.6.2", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", + "jest-circus": "^29.6.2", + "jest-environment-node": "^29.6.2", "jest-get-type": "^29.4.3", "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", + "jest-resolve": "^29.6.2", + "jest-runner": "^29.6.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", + "pretty-format": "^29.6.2", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -3294,15 +3465,15 @@ } }, "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.2.tgz", + "integrity": "sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA==", "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.4.3", "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "pretty-format": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3321,33 +3492,33 @@ } }, "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.2.tgz", + "integrity": "sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "chalk": "^4.0.0", "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" + "jest-util": "^29.6.2", + "pretty-format": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.2.tgz", + "integrity": "sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ==", "dev": true, "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/environment": "^29.6.2", + "@jest/fake-timers": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" + "jest-mock": "^29.6.2", + "jest-util": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3363,20 +3534,20 @@ } }, "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.2.tgz", + "integrity": "sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", + "jest-util": "^29.6.2", + "jest-worker": "^29.6.2", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -3388,46 +3559,46 @@ } }, "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz", + "integrity": "sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ==", "dev": true, "dependencies": { "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "pretty-format": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz", + "integrity": "sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.5.0", + "jest-diff": "^29.6.2", "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "pretty-format": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.2.tgz", + "integrity": "sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", + "pretty-format": "^29.6.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -3436,14 +3607,14 @@ } }, "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.2.tgz", + "integrity": "sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "@types/node": "*", - "jest-util": "^29.5.0" + "jest-util": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3476,17 +3647,17 @@ } }, "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.2.tgz", + "integrity": "sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", + "jest-haste-map": "^29.6.2", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" @@ -3496,43 +3667,43 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz", + "integrity": "sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w==", "dev": true, "dependencies": { "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" + "jest-snapshot": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.2.tgz", + "integrity": "sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w==", "dev": true, "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/console": "^29.6.2", + "@jest/environment": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", + "jest-environment-node": "^29.6.2", + "jest-haste-map": "^29.6.2", + "jest-leak-detector": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-resolve": "^29.6.2", + "jest-runtime": "^29.6.2", + "jest-util": "^29.6.2", + "jest-watcher": "^29.6.2", + "jest-worker": "^29.6.2", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -3541,31 +3712,31 @@ } }, "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.2.tgz", + "integrity": "sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg==", "dev": true, "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/environment": "^29.6.2", + "@jest/fake-timers": "^29.6.2", + "@jest/globals": "^29.6.2", + "@jest/source-map": "^29.6.0", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", + "jest-haste-map": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-mock": "^29.6.2", "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", + "jest-resolve": "^29.6.2", + "jest-snapshot": "^29.6.2", + "jest-util": "^29.6.2", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -3574,34 +3745,31 @@ } }, "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.2.tgz", + "integrity": "sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-jsx": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", + "@jest/expect-utils": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.5.0", + "expect": "^29.6.2", "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", + "jest-diff": "^29.6.2", "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", + "jest-matcher-utils": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2", "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" + "pretty-format": "^29.6.2", + "semver": "^7.5.3" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3620,9 +3788,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "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" @@ -3641,12 +3809,12 @@ "dev": true }, "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.2.tgz", + "integrity": "sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -3658,17 +3826,17 @@ } }, "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.2.tgz", + "integrity": "sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^29.6.1", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.5.0" + "pretty-format": "^29.6.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3687,18 +3855,18 @@ } }, "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.2.tgz", + "integrity": "sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA==", "dev": true, "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/test-result": "^29.6.2", + "@jest/types": "^29.6.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.5.0", + "jest-util": "^29.6.2", "string-length": "^4.0.1" }, "engines": { @@ -3706,13 +3874,13 @@ } }, "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz", + "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==", "dev": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.5.0", + "jest-util": "^29.6.2", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -3784,9 +3952,9 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", + "integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==", "dependencies": { "jws": "^3.2.2", "lodash": "^4.17.21", @@ -3815,9 +3983,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3862,7 +4030,7 @@ } }, "node_modules/le-coffre-resources": { - "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#467b34a484adbd6dfa3fd6082bb7677f6178da51", + "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#ad0660abcb9de6ee7f396dce9b25fa7731a8e3b8", "license": "MIT", "dependencies": { "class-transformer": "^0.5.1", @@ -3880,9 +4048,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.10.30", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.30.tgz", - "integrity": "sha512-PLGc+xfrQrkya/YK2/5X+bPpxRmyJBHM+xxz9krUdSgk4Vs2ZwxX5/Ow0lv3r9PDlDtNWb4u+it8MY5rZ0IyGw==" + "version": "1.10.41", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.41.tgz", + "integrity": "sha512-4rmmF4u4vD3eGNuuCGjCPwRwO+fIuu1WWcS7VwbPTiMFkJd8F02v8o5pY5tlYuMR+xOvJ88mtOHpkm0Tnu2LcQ==" }, "node_modules/lines-and-columns": { "version": "1.2.4", @@ -3940,9 +4108,9 @@ } }, "node_modules/luxon": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", - "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.0.tgz", + "integrity": "sha512-7eDo4Pt7aGhoCheGFIuq4Xa2fJm4ZpmldpGhjTYBNUYNCN6TIEP6v7chwwwt3KRp7YR+rghbfvjyo3V5y9hgBw==", "engines": { "node": ">=12" } @@ -3956,20 +4124,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", @@ -4095,9 +4296,9 @@ } }, "node_modules/module-alias": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", - "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==" }, "node_modules/ms": { "version": "2.0.0", @@ -4276,16 +4477,17 @@ } }, "node_modules/next": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz", - "integrity": "sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.16.tgz", + "integrity": "sha512-1xaA/5DrfpPu0eV31Iro7JfPeqO8uxQWb1zYNTe+KDKdzqkAGapLcDYHMLNKXKB7lHjZ7LfKUOf9dyuzcibrhA==", "dependencies": { - "@next/env": "13.4.1", + "@next/env": "13.4.16", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", "styled-jsx": "5.1.1", + "watchpack": "2.4.0", "zod": "3.21.4" }, "bin": { @@ -4295,20 +4497,18 @@ "node": ">=16.8.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.1", - "@next/swc-darwin-x64": "13.4.1", - "@next/swc-linux-arm64-gnu": "13.4.1", - "@next/swc-linux-arm64-musl": "13.4.1", - "@next/swc-linux-x64-gnu": "13.4.1", - "@next/swc-linux-x64-musl": "13.4.1", - "@next/swc-win32-arm64-msvc": "13.4.1", - "@next/swc-win32-ia32-msvc": "13.4.1", - "@next/swc-win32-x64-msvc": "13.4.1" + "@next/swc-darwin-arm64": "13.4.16", + "@next/swc-darwin-x64": "13.4.16", + "@next/swc-linux-arm64-gnu": "13.4.16", + "@next/swc-linux-arm64-musl": "13.4.16", + "@next/swc-linux-x64-gnu": "13.4.16", + "@next/swc-linux-x64-musl": "13.4.16", + "@next/swc-win32-arm64-msvc": "13.4.16", + "@next/swc-win32-ia32-msvc": "13.4.16", + "@next/swc-win32-x64-msvc": "13.4.16" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -4317,12 +4517,6 @@ "@opentelemetry/api": { "optional": true }, - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, "sass": { "optional": true } @@ -4339,6 +4533,25 @@ "node": ">= 8.0.0" } }, + "node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4346,9 +4559,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/node-schedule": { @@ -4417,9 +4630,9 @@ "dev": true }, "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -4666,9 +4879,9 @@ } }, "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, "engines": { "node": ">= 6" @@ -4725,12 +4938,12 @@ } }, "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", + "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.3", + "@jest/schemas": "^29.6.0", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -4751,13 +4964,13 @@ } }, "node_modules/prisma": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.14.0.tgz", - "integrity": "sha512-+5dMl1uxMQb4RepndY6AwR9xi1cDcaGFICu+ws6/Nmgt93mFPNj8tYxSfTdmfg+rkNrUId9rk/Ac2vTgLe/oXA==", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.2.tgz", + "integrity": "sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "4.14.0" + "@prisma/engines": "4.16.2" }, "bin": { "prisma": "build/index.js", @@ -4945,12 +5158,12 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -5025,9 +5238,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -5411,10 +5624,15 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-jest": { - "version": "29.1.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz", - "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -5423,7 +5641,7 @@ "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", - "semver": "7.x", + "semver": "^7.5.3", "yargs-parser": "^21.0.1" }, "bin": { @@ -5467,9 +5685,9 @@ } }, "node_modules/ts-jest/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "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" @@ -5530,9 +5748,9 @@ } }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "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", @@ -5715,9 +5933,9 @@ "dev": true }, "node_modules/validator": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", - "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==", + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", "engines": { "node": ">= 0.10" } @@ -5744,6 +5962,32 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 8f6c3f38..fd95302f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "build-db": "npx prisma migrate dev", "build": "tsc", "start": "node ./dist/entries/App.js", + "cron": "node ./dist/entries/Cron.js", "api:start": "npm run migrate && npm run start", "dev": "nodemon -V", "format": "prettier --write src", @@ -27,7 +28,8 @@ "migrate": "npx prisma migrate deploy", "docker:up:test": "docker-compose -f docker-compose-test.yml up -d", "docker:down:test": "docker-compose down", - "test": "tsc && npm run docker:up:test && npm run migrate:test && dotenv -e .env.test -- jest -i --verbose ./dist/test/* && npm run docker:down:test" + "test": "tsc && npm run docker:up:test && npm run migrate:test && dotenv -e .env.test -- jest -i --verbose ./dist/test/* && npm run docker:down:test", + "seed": "ts-node src/common/databases/seeders/seeder.ts" }, "repository": { "type": "git", @@ -40,19 +42,22 @@ }, "homepage": "https://github.com/smart-chain-fr/leCoffre-back#readme", "dependencies": { + "@mailchimp/mailchimp_transactional": "^1.0.50", "@pinata/sdk": "^2.1.0", "@prisma/client": "^4.11.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "classnames": "^2.3.2", "cors": "^2.8.5", + "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.47", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.69", "module-alias": "^2.2.2", "multer": "^1.4.5-lts.1", "next": "^13.1.5", "node-cache": "^5.1.2", + "node-fetch": "^2.6.11", "node-schedule": "^2.1.1", "prisma-query": "^2.0.0", "reflect-metadata": "^0.1.13", @@ -65,11 +70,15 @@ }, "devDependencies": { "@types/cors": "^2.8.13", + "@types/cron": "^2.0.1", "@types/express": "^4.17.16", "@types/jest": "^29.5.0", "@types/jsonwebtoken": "^9.0.1", + "@types/mailchimp__mailchimp_transactional": "^1.0.5", + "@types/module-alias": "^2.0.1", "@types/multer": "^1.4.7", "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.3", "@types/node-schedule": "^2.1.0", "@types/uuid": "^9.0.0", "dotenv": "^16.0.3", @@ -81,6 +90,6 @@ }, "prisma": { "schema": "src/common/databases/schema.prisma", - "seed": "ts-node src/common/databases/seeders/seeder2.ts" + "seed": "ts-node src/common/databases/seeders/seeder.ts" } } diff --git a/src/app/api/admin/CustomersController.ts b/src/app/api/admin/CustomersController.ts new file mode 100644 index 00000000..90e429cf --- /dev/null +++ b/src/app/api/admin/CustomersController.ts @@ -0,0 +1,146 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import CustomersService from "@Services/admin/CustomersService/CustomersService"; +import { Service } from "typedi"; +import { Customer } from "le-coffre-resources/dist/Admin"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class CustomersController extends ApiController { + constructor(private customersService: CustomersService) { + super(); + } + + /** + * @description Get all customers + */ + @Get("/api/v1/admin/customers", [authHandler, roleHandler, ruleHandler]) + 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 customersEntities = await this.customersService.get(query); + + //Hydrate ressource with prisma entity + const customers = Customer.hydrateArray(customersEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, customers); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new customer + */ + @Post("/api/v1/admin/customers", [authHandler, ruleHandler]) + protected async post(req: Request, response: Response) { + try { + //init IUser resource with request body values + const customerEntity = Customer.hydrate(req.body); + //validate user + await validateOrReject(customerEntity, { groups: ["createCustomer"], forbidUnknownValues: false }); + + //call service to get prisma entity + const customerEntityCreated = await this.customersService.create(customerEntity); + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific customer by uid + */ + @Put("/api/v1/admin/customers/:uid", [authHandler, roleHandler, ruleHandler]) + 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.customersService.getByUid(uid); + + if (!userFound) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + + //init IUser resource with request body values + const customerEntity = Customer.hydrate(req.body); + + //validate user + await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); + + //call service to get prisma entity + const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific customer by uid + */ + @Get("/api/v1/admin/customers/:uid", [authHandler, roleHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const customerEntity = await this.customersService.getByUid(uid, query); + + if (!customerEntity) { + this.httpNotFoundRequest(response, "customer not found"); + return; + } + + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/DeedTypesController.ts b/src/app/api/admin/DeedTypesController.ts new file mode 100644 index 00000000..d1273879 --- /dev/null +++ b/src/app/api/admin/DeedTypesController.ts @@ -0,0 +1,176 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import DeedTypesService from "@Services/admin/DeedTypesService/DeedTypesService"; +import { DeedTypes, Prisma } from "@prisma/client"; +import { DeedType } from "le-coffre-resources/dist/Admin"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import deedTypeHandler from "@App/middlewares/OfficeMembershipHandlers/DeedTypeHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class DeedTypesController extends ApiController { + constructor(private deedTypesService: DeedTypesService) { + super(); + } + + /** + * @description Get all deedtypes + * @returns Deedtype[] list of deedtypes + */ + @Get("/api/v1/admin/deed-types", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DeedTypesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + name: { + contains: filter, + mode: "insensitive", + } + } + }; + } + + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const deedTypeEntities: DeedTypes[] = await this.deedTypesService.get(query); + + //Hydrate ressource with prisma entity + const DeedTypes = DeedType.hydrateArray(deedTypeEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, DeedTypes); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new deedtype + * @returns Deedtype created + */ + @Post("/api/v1/admin/deed-types", [authHandler, roleHandler, ruleHandler, deedTypeHandler]) + protected async post(req: Request, response: Response) { + try { + //init DeedType resource with request body values + const deedTypeEntity = DeedType.hydrate(req.body); + + //validate deed type + await validateOrReject(deedTypeEntity, { groups: ["createDeedType"], forbidUnknownValues: false }); + const doesExist = await this.deedTypesService.get({ where: { name: deedTypeEntity.name } }); + if (doesExist.length > 0) { + this.httpBadRequest(response, "Deed type name already used"); + return; + } + + //call service to get prisma entity + const deedTypeEntityCreated = await this.deedTypesService.create(deedTypeEntity); + + //Hydrate ressource with prisma entity + const deedType = DeedType.hydrate(deedTypeEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, deedType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific deedtype by uid + * @returns Deedtype modified + */ + @Put("/api/v1/admin/deed-types/:uid", [authHandler, roleHandler, ruleHandler, deedTypeHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const deedTypeFound = await this.deedTypesService.getByUid(uid); + + if (!deedTypeFound) { + this.httpNotFoundRequest(response, "deed type not found"); + return; + } + + //init DeedType resource with request body values + const deedTypeEntity = DeedType.hydrate(req.body); + + //validate deed type + await validateOrReject(deedTypeEntity, { groups: ["updateDeedType"] }); + + //call service to get prisma entity + const deedTypeEntityUpdated = await this.deedTypesService.update(uid, deedTypeEntity); + + //Hydrate ressource with prisma entity + const deedType = DeedType.hydrate(deedTypeEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, deedType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific deedtype by uid + * @returns IDeedtype + */ + @Get("/api/v1/admin/deed-types/:uid", [authHandler, roleHandler, ruleHandler, deedTypeHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const deedTypeEntity = await this.deedTypesService.getByUid(uid, query); + + if (!deedTypeEntity) { + this.httpNotFoundRequest(response, "deed type not found"); + return; + } + + //Hydrate ressource with prisma entity + const deedType = DeedType.hydrate(deedTypeEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, deedType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/DeedsController.ts b/src/app/api/admin/DeedsController.ts new file mode 100644 index 00000000..00a2fa20 --- /dev/null +++ b/src/app/api/admin/DeedsController.ts @@ -0,0 +1,128 @@ +import { Response, Request } from "express"; +import { Controller, Get, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import DeedsService from "@Services/admin/DeedsService/DeedsService"; +import { Service } from "typedi"; +import { Deeds, Prisma } from "@prisma/client"; +import { Deed } from "le-coffre-resources/dist/Admin"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import deedHandler from "@App/middlewares/OfficeMembershipHandlers/DeedHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class DeedsController extends ApiController { + constructor(private deedsService: DeedsService) { + super(); + } + + /** + * @description Get all deeds + * @returns Deed[] list of deeds + */ + @Get("/api/v1/admin/deeds", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DeedsFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { deed_type : {office: officeWhereInput}}; + query.where.deed_type!.office = officeWhereInput; + + //call service to get prisma entity + const deedEntities: Deeds[] = await this.deedsService.get(query); + + //Hydrate ressource with prisma entity + const deeds = Deed.hydrateArray(deedEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, deeds); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific deed by uid + * @returns Deed + */ + @Get("/api/v1/admin/deeds/:uid", [authHandler, roleHandler, ruleHandler, deedHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const deedEntity = await this.deedsService.getByUid(uid, query); + + if (!deedEntity) { + this.httpNotFoundRequest(response, "deed not found"); + return; + } + + //Hydrate ressource with prisma entity + const deed = Deed.hydrate(deedEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, deed); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific deed by uid + */ + @Put("/api/v1/admin/deeds/:uid", [authHandler, roleHandler, ruleHandler, deedHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const deedFound = await this.deedsService.getByUid(uid); + + if (!deedFound) { + this.httpNotFoundRequest(response, "deed not found"); + return; + } + + //init OfficeFolder resource with request body values + const deedEntity = Deed.hydrate(req.body); + + //validate folder + await validateOrReject(deedEntity, { groups: ["updateDeed"], forbidUnknownValues: false }); + + //call service to get prisma entity + const deedEntityUpdated = await this.deedsService.update(uid, deedEntity); + + //Hydrate ressource with prisma entity + const deed = Deed.hydrate(deedEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, deed); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/DocumentTypesController.ts b/src/app/api/admin/DocumentTypesController.ts new file mode 100644 index 00000000..582cd2f2 --- /dev/null +++ b/src/app/api/admin/DocumentTypesController.ts @@ -0,0 +1,147 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import DocumentTypesService from "@Services/admin/DocumentTypesService/DocumentTypesService"; +import { DocumentTypes, Prisma } from "@prisma/client"; +import ObjectHydrate from "@Common/helpers/ObjectHydrate"; +import { DocumentType } from "le-coffre-resources/dist/Admin"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import documentTypeHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentTypeHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class DocumentTypesController extends ApiController { + constructor(private documentTypesService: DocumentTypesService) { + super(); + } + + /** + * @description Get all document-types + */ + @Get("/api/v1/admin/document-types", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DocumentTypesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const documentTypeEntities: DocumentTypes[] = await this.documentTypesService.get(query); + + //Hydrate ressource with prisma entity + const documentTypes = DocumentType.hydrateArray(documentTypeEntities, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, documentTypes); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new documentType + */ + @Post("/api/v1/admin/document-types", [authHandler, roleHandler, ruleHandler, documentTypeHandler]) + protected async post(req: Request, response: Response) { + try { + //init DocumentType resource with request body values + const documentTypeEntity = DocumentType.hydrate(req.body); + //validate user + await validateOrReject(documentTypeEntity, { groups: ["createDocumentType"], forbidUnknownValues: false }); + //call service to get prisma entity + const documentTypeEntityCreated = await this.documentTypesService.create(documentTypeEntity); + //Hydrate ressource with prisma entity + const userEntityCreated = DocumentType.hydrate(documentTypeEntityCreated, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, userEntityCreated); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific documentType by uid + */ + @Put("/api/v1/admin/document-types/:uid", [authHandler, roleHandler, ruleHandler, documentTypeHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentTypeFound = await this.documentTypesService.getByUid(uid); + + if (!documentTypeFound) { + this.httpNotFoundRequest(response, "document type not found"); + return; + } + //init DocumentType resource with request body values + const documentTypeEntity = DocumentType.hydrate(req.body); + + //validate user + await validateOrReject(documentTypeEntity, { groups: ["updateDocumentType"] }); + + //call service to get prisma entity + const documentTypeEntityUpdated = await this.documentTypesService.update(uid, documentTypeEntity); + + //Hydrate ressource with prisma entity + const documentType = DocumentType.hydrate(documentTypeEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, documentType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific documentType by uid + */ + @Get("/api/v1/admin/document-types/:uid", [authHandler, ruleHandler, documentTypeHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const documentTypeEntity = await this.documentTypesService.getByUid(uid, query); + + //Hydrate ressource with prisma entity + const user = ObjectHydrate.hydrate(new DocumentType(), documentTypeEntity!, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, user); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/DocumentsController.ts b/src/app/api/admin/DocumentsController.ts new file mode 100644 index 00000000..05a21c1e --- /dev/null +++ b/src/app/api/admin/DocumentsController.ts @@ -0,0 +1,187 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import DocumentsService from "@Services/admin/DocumentsService/DocumentsService"; +import { Documents, Prisma } from "@prisma/client"; +import { Document } from "le-coffre-resources/dist/Admin"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import documentHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class DocumentsController extends ApiController { + constructor(private documentsService: DocumentsService) { + super(); + } + + /** + * @description Get all documents + * @returns IDocument[] list of documents + */ + @Get("/api/v1/admin/documents", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DocumentsFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { document_type : {office: officeWhereInput}}; + query.where.document_type!.office = officeWhereInput; + + //call service to get prisma entity + const documentEntities = await this.documentsService.get(query); + + //Hydrate ressource with prisma entity + const documents = Document.hydrateArray(documentEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, documents); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new document + * @returns IDocument created + */ + @Post("/api/v1/admin/documents", [authHandler, roleHandler, ruleHandler, documentHandler]) + protected async post(req: Request, response: Response) { + try { + //init Document resource with request body values + const documentEntity = Document.hydrate(req.body); + + //validate document + await validateOrReject(documentEntity, { groups: ["createDocument"], forbidUnknownValues: false }); + + //call service to get prisma entity + const documentEntityCreated = await this.documentsService.create(documentEntity); + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Update a specific document + */ + @Put("/api/v1/admin/documents/:uid", [authHandler, roleHandler, ruleHandler, documentHandler]) + protected async update(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentFound = await this.documentsService.getByUid(uid); + + if (!documentFound) { + this.httpNotFoundRequest(response, "document not found"); + return; + } + + //init Document resource with request body values + const documentEntity = Document.hydrate(req.body); + + //validate document + await validateOrReject(documentEntity, { groups: ["updateDocument"] }); + + //call service to get prisma entity + const documentEntityUpdated: Documents = await this.documentsService.update(uid, documentEntity, req.body.refused_reason); + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntityUpdated, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Delete a specific document + */ + @Delete("/api/v1/admin/documents/:uid", [authHandler, roleHandler, ruleHandler, documentHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentFound = await this.documentsService.getByUid(uid); + + if (!documentFound) { + this.httpNotFoundRequest(response, "document not found"); + return; + } + + //call service to get prisma entity + const documentEntity: Documents = await this.documentsService.delete(uid); + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific document by uid + */ + @Get("/api/v1/admin/documents/:uid", [authHandler, roleHandler, ruleHandler, documentHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const documentEntity = await this.documentsService.getByUid(uid, query); + + if (!documentEntity) { + this.httpNotFoundRequest(response, "document not found"); + return; + } + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/FilesController.ts b/src/app/api/admin/FilesController.ts new file mode 100644 index 00000000..583d3ddc --- /dev/null +++ b/src/app/api/admin/FilesController.ts @@ -0,0 +1,150 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import FilesService from "@Services/common/FilesService/FilesService"; +import { Prisma } from "@prisma/client"; +import { File } from "le-coffre-resources/dist/Admin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import fileHandler from "@App/middlewares/OfficeMembershipHandlers/FileHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class FilesController extends ApiController { + constructor(private filesService: FilesService) { + super(); + } + + /** + * @description Get all Files + * @returns File[] list of Files + */ + @Get("/api/v1/admin/files", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.FilesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { document: { folder: {office: officeWhereInput}}}; + query.where.document!.folder!.office = officeWhereInput; + //call service to get prisma entity + const fileEntities = await this.filesService.get(query); + + //Hydrate ressource with prisma entity + const files = File.hydrateArray(fileEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, files); + } catch (error) { + this.httpBadRequest(response, error); + return; + } + } + + /** + * @description Get a specific File by uid + */ + @Get("/api/v1/admin/files/download/:uid", [authHandler, roleHandler, ruleHandler, fileHandler]) + protected async download(req: Request, response: Response) { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "uid not found"); + return; + } + try { + const fileInfo = await this.filesService.download(uid); + + if (!fileInfo) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + response.setHeader("Content-Type", fileInfo.file.mimetype); + response.setHeader("Content-Disposition", `inline; filename=${encodeURIComponent(fileInfo.file.file_name)}`); + + this.httpSuccess(response, fileInfo.buffer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Delete a specific File + */ + @Delete("/api/v1/admin/files/:uid", [authHandler, roleHandler, ruleHandler, fileHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const fileFound = await this.filesService.getByUid(uid); + + if (!fileFound) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //call service to get prisma entity + const fileEntity = await this.filesService.deleteKeyAndArchive(uid); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific File by uid + */ + @Get("/api/v1/admin/files/:uid", [authHandler, roleHandler, ruleHandler, fileHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const fileEntity = await this.filesService.getByUid(uid, query); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/OfficeFoldersController.ts b/src/app/api/admin/OfficeFoldersController.ts new file mode 100644 index 00000000..42fbdc58 --- /dev/null +++ b/src/app/api/admin/OfficeFoldersController.ts @@ -0,0 +1,215 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficeFoldersService from "@Services/admin/OfficeFoldersService/OfficeFoldersService"; +import { Service } from "typedi"; +import { OfficeFolders, Prisma } from "@prisma/client"; +import { OfficeFolder } from "le-coffre-resources/dist/Admin"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import folderHandler from "@App/middlewares/OfficeMembershipHandlers/FolderHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class OfficeFoldersController extends ApiController { + constructor(private officeFoldersService: OfficeFoldersService) { + super(); + } + + /** + * @description Get all folders + */ + @Get("/api/v1/admin/folders", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.OfficeFoldersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + OR: [ + { + name: { contains: filter, mode: "insensitive" }, + }, + { + folder_number: { contains: filter, mode: "insensitive" }, + }, + { + customers: { + some: { + contact: { + OR: [ + { first_name: { contains: filter, mode: "insensitive" } }, + { last_name: { contains: filter, mode: "insensitive" } }, + ], + }, + }, + }, + }, + ], + }, + }; + } + + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrateArray(officeFolderEntities, { + strategy: "excludeAll", + }); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new folder + */ + @Post("/api/v1/admin/folders", [authHandler, roleHandler, ruleHandler, folderHandler]) + protected async post(req: Request, response: Response) { + try { + //init OfficeFolder resource with request body values + const officeFolderRessource = OfficeFolder.hydrate(req.body); + await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); + + //call service to get prisma entity + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific folder by uid + */ + @Put("/api/v1/admin/folders/:uid", [authHandler, roleHandler, ruleHandler, folderHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeFolderFound = await this.officeFoldersService.getByUid(uid); + + if (!officeFolderFound) { + this.httpNotFoundRequest(response, "office folder not found"); + return; + } + + //init OfficeFolder resource with request body values + const officeFolderEntity = OfficeFolder.hydrate(req.body); + + //validate folder + await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); + + //call service to get prisma entity + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific folder by uid + * @returns IFolder + */ + @Get("/api/v1/admin/folders/:uid", [authHandler, roleHandler, ruleHandler, folderHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); + + if (!officeFolderEntity) { + this.httpNotFoundRequest(response, "folder not found"); + return; + } + + //Hydrate ressource with prisma entity + const officeFolder = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeFolder); + } catch (error) { + this.httpInternalError(response, error); + return; + } + this.httpSuccess(response, await this.officeFoldersService.getByUid("uid")); + } + + /** + * @description Delete a specific folder + */ + @Delete("/api/v1/admin/folders/:uid", [authHandler, roleHandler, ruleHandler, folderHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeFolderFound = await this.officeFoldersService.getByUid(uid); + + if (!officeFolderFound) { + this.httpNotFoundRequest(response, "office folder not found"); + return; + } + + //call service to get prisma entity + const officeFoldertEntity: OfficeFolders = await this.officeFoldersService.delete(uid); + + //Hydrate ressource with prisma entity + const officeFolder = OfficeFolder.hydrate(officeFoldertEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeFolder); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/OfficeRolesController.ts b/src/app/api/admin/OfficeRolesController.ts new file mode 100644 index 00000000..5c06e471 --- /dev/null +++ b/src/app/api/admin/OfficeRolesController.ts @@ -0,0 +1,167 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficeRolesService from "@Services/admin/OfficeRolesService/OfficeRolesService"; +import { Service } from "typedi"; +import { validateOrReject } from "class-validator"; +import { OfficeRole } from "le-coffre-resources/dist/Admin"; +import { Prisma } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import officeRoleHandler from "@App/middlewares/OfficeMembershipHandlers/OfficeRoleHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class OfficeRolesController extends ApiController { + constructor(private officeRolesService: OfficeRolesService) { + super(); + } + + /** + * @description Get all officeRoles + */ + @Get("/api/v1/admin/office-roles", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.OfficeRolesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if(req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + name: { + contains: filter, + mode: "insensitive", + }, + }, + } + } + + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId }; + if (!query.where) query.where = { office: officeWhereInput }; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const officeRolesEntities = await this.officeRolesService.get(query); + + //Hydrate ressource with prisma entity + const officeRoles = OfficeRole.hydrateArray(officeRolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeRoles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new officeRole + */ + @Post("/api/v1/admin/office-roles", [authHandler, roleHandler, ruleHandler, officeRoleHandler]) + protected async getAddresses(req: Request, response: Response) { + try { + //init IOfficeRole resource with request body values + const officeRoleEntity = OfficeRole.hydrate(req.body); + + //validate officeRole + await validateOrReject(officeRoleEntity, { groups: ["createOfficeRole"] }); + + //call service to get prisma entity + const officeRoleEntityCreated = await this.officeRolesService.create(officeRoleEntity); + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific officeRole by uid + */ + @Put("/api/v1/admin/office-roles/:uid", [authHandler, roleHandler, ruleHandler, officeRoleHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeRoleFound = await this.officeRolesService.getByUid(uid); + + if (!officeRoleFound) { + this.httpNotFoundRequest(response, "officeRole not found"); + return; + } + + //init IOfficeRole resource with request body values + const officeRoleEntity = OfficeRole.hydrate(req.body); + + //validate officeRole + await validateOrReject(officeRoleEntity, { groups: ["updateOfficeRole"] }); + + //call service to get prisma entity + const officeRoleEntityUpdated = await this.officeRolesService.update(officeRoleEntity); + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific officeRole by uid + */ + @Get("/api/v1/admin/office-roles/:uid", [authHandler, roleHandler, ruleHandler, officeRoleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const officeRoleEntity = await this.officeRolesService.getByUid(uid, query); + + if (!officeRoleEntity) { + this.httpNotFoundRequest(response, "officeRole not found"); + return; + } + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/OfficesController.ts b/src/app/api/admin/OfficesController.ts new file mode 100644 index 00000000..546d240f --- /dev/null +++ b/src/app/api/admin/OfficesController.ts @@ -0,0 +1,74 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficesService from "@Services/admin/OfficesService/OfficesService"; +import { Service } from "typedi"; +import { Offices } from "@prisma/client"; +import { Office as OfficeResource } from "le-coffre-resources/dist/Admin"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import authHandler from "@App/middlewares/AuthHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class OfficesController extends ApiController { + constructor(private officesService: OfficesService) { + super(); + } + /** + * @description Get all offices + */ + @Get("/api/v1/admin/offices", [authHandler, roleHandler, ruleHandler]) + 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 officesEntities: Offices[] = await this.officesService.get(query); + //Hydrate ressource with prisma entity + const offices = OfficeResource.hydrateArray(officesEntities, { strategy: "excludeAll" }); + //success + this.httpSuccess(response, offices); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific office by uid + */ + @Get("/api/v1/admin/offices/:uid", [authHandler, roleHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const officeEntity = await this.officesService.getByUid(uid, query); + + if (!officeEntity) { + this.httpNotFoundRequest(response, "office not found"); + return; + } + + //Hydrate ressource with prisma entity + const office = OfficeResource.hydrate(officeEntity, { strategy: "excludeAll" }); + //success + this.httpSuccess(response, office); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/RolesController.ts b/src/app/api/admin/RolesController.ts new file mode 100644 index 00000000..634bd92e --- /dev/null +++ b/src/app/api/admin/RolesController.ts @@ -0,0 +1,78 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RolesService from "@Services/admin/RolesService/RolesService"; +import { Service } from "typedi"; +import { Role } from "le-coffre-resources/dist/Admin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class RolesController extends ApiController { + constructor(private rolesService: RolesService) { + super(); + } + + /** + * @description Get all roles + */ + @Get("/api/v1/admin/roles", [authHandler, roleHandler, ruleHandler]) + 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 rolesEntities = await this.rolesService.get(query); + + //Hydrate ressource with prisma entity + const roles = Role.hydrateArray(rolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, roles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific role by uid + */ + @Get("/api/v1/admin/roles/:uid", [authHandler, roleHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const roleEntity = await this.rolesService.getByUid(uid, query); + + if (!roleEntity) { + this.httpNotFoundRequest(response, "role not found"); + return; + } + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/RulesController.ts b/src/app/api/admin/RulesController.ts new file mode 100644 index 00000000..55526601 --- /dev/null +++ b/src/app/api/admin/RulesController.ts @@ -0,0 +1,78 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RulesService from "@Services/admin/RulesService/RulesService"; +import { Service } from "typedi"; +import { Rule } from "le-coffre-resources/dist/Admin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class RulesController extends ApiController { + constructor(private rulesService: RulesService) { + super(); + } + + /** + * @description Get all rules + */ + @Get("/api/v1/admin/rules", [authHandler, roleHandler, ruleHandler]) + 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 rulesEntities = await this.rulesService.get(query); + + //Hydrate ressource with prisma entity + const rules = Rule.hydrateArray(rulesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rules); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific rule by uid + */ + @Get("/api/v1/admin/rules/:uid", [authHandler, roleHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const ruleEntity = await this.rulesService.getByUid(uid, query); + + if (!ruleEntity) { + this.httpNotFoundRequest(response, "rule not found"); + return; + } + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/admin/UsersController.ts b/src/app/api/admin/UsersController.ts new file mode 100644 index 00000000..cc4cde87 --- /dev/null +++ b/src/app/api/admin/UsersController.ts @@ -0,0 +1,162 @@ +import { Response, Request } from "express"; +import { Controller, Get, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import UsersService from "@Services/admin/UsersService/UsersService"; +import { Service } from "typedi"; +import User from "le-coffre-resources/dist/Admin"; +import { Prisma } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import userHandler from "@App/middlewares/OfficeMembershipHandlers/UserHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; +import RolesService from "@Services/admin/RolesService/RolesService"; +import OfficeRolesService from "@Services/admin/OfficeRolesService/OfficeRolesService"; + +@Controller() +@Service() +export default class UsersController extends ApiController { + constructor(private usersService: UsersService, private roleService: RolesService, private officeRoleService: OfficeRolesService) { + super(); + } + + /** + * @description Get all users + */ + @Get("/api/v1/admin/users", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.UsersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + contact: { + OR: [ + { first_name: { contains: filter, mode: "insensitive" } }, + { last_name: { contains: filter, mode: "insensitive" } }, + ], + }, + }, + }; + } + + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId }; + if (!query.where) query.where = { office_membership: officeWhereInput }; + query.where.office_membership = officeWhereInput; + + //call service to get prisma entity + const usersEntities = await this.usersService.get(query); + + //Hydrate ressource with prisma entity + const users = User.hydrateArray(usersEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, users); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific user by uid + */ + @Put("/api/v1/admin/users/:uid", [authHandler, roleHandler, ruleHandler]) + 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.getByUidWithRole(uid); + + if (!userFound) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + + //init IUser resource with request body values + const userEntity = User.hydrate(req.body); + + if(userEntity.role) { + const role = await this.roleService.getByUid(userEntity.role.uid!); + if(!role) { + this.httpBadRequest(response, "Role not found"); + return; + } + if (role.name === "super-admin" || userFound.role.name === "super-admin" ) { + this.httpBadRequest(response, "Cannot assign or remove super-admin role"); + return; + } + } + + if(userEntity.office_role) { + const officeRole = await this.officeRoleService.getByUid(userEntity.office_role.uid!); + if(!officeRole) { + this.httpBadRequest(response, "Office role not found"); + return; + } + if (officeRole.office_uid != userFound.office_uid) { + this.httpBadRequest(response, "Cannot assign an office role from another office"); + return; + } + } + //call service to get prisma entity + const userEntityUpdated = await this.usersService.update(uid, userEntity); + + //Hydrate ressource with prisma entity + const user = User.hydrate(userEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, user); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific user by uid + */ + @Get("/api/v1/admin/users/:uid", [authHandler, roleHandler, ruleHandler, userHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const userEntity = await this.usersService.getByUid(uid, query); + + if (!userEntity) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + + //Hydrate ressource with prisma entity + const user = User.hydrate(userEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, user); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/customer/CustomersController.ts b/src/app/api/customer/CustomersController.ts new file mode 100644 index 00000000..f958ab7e --- /dev/null +++ b/src/app/api/customer/CustomersController.ts @@ -0,0 +1,79 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import CustomersService from "@Services/customer/CustomersService/CustomersService"; +import { Service } from "typedi"; +import Customer from "le-coffre-resources/dist/Customer"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; + +@Controller() +@Service() +export default class CustomersController extends ApiController { + constructor(private customersService: CustomersService) { + super(); + } + + /** + * @description Get all customers + */ + @Get("/api/v1/customer/customers") + 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 customersEntities = await this.customersService.get(query); + + //Hydrate ressource with prisma entity + const customers = Customer.hydrateArray(customersEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, customers); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + + /** + * @description Get a specific customer by uid + */ + @Get("/api/v1/customer/customers/:uid", [authHandler, ruleHandler]) + 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 customerEntity = await this.customersService.getByUid(uid, query); + + if (!customerEntity) { + this.httpNotFoundRequest(response, "customer not found"); + return; + } + + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/customer/DocumentsController.ts b/src/app/api/customer/DocumentsController.ts index ebfccb15..a7f2b1a7 100644 --- a/src/app/api/customer/DocumentsController.ts +++ b/src/app/api/customer/DocumentsController.ts @@ -1,11 +1,12 @@ import { Response, Request } from "express"; -import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import { Controller, Get } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; import DocumentsService from "@Services/customer/DocumentsService/DocumentsService"; -import { Documents } from "@prisma/client"; +import { Documents, Prisma } from "@prisma/client"; import { Document } from "le-coffre-resources/dist/Customer"; -import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import documentHandler from "@App/middlewares/CustomerHandler/DocumentHandler"; @Controller() @Service() @@ -18,108 +19,31 @@ export default class DocumentsController extends ApiController { * @description Get all documents * @returns IDocument[] list of documents */ - @Get("/api/v1/customer/documents") + @Get("/api/v1/customer/documents", [authHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.CustomersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const customerId: string = req.body.user.customerId; + const customerWhereInput: Prisma.DocumentsWhereInput ={ depositor: { uid: customerId } }; + query.where = customerWhereInput; + //call service to get prisma entity - const prismaEntity: Documents[] = await this.documentsService.get(query); + const documentEntities: Documents[] = await this.documentsService.get(query); + //Hydrate ressource with prisma entity - const documents = Document.map(Document, prismaEntity, { strategy: "excludeAll" }); + const documents = Document.hydrateArray(documentEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, documents); } catch (error) { - this.httpBadRequest(response, error); - return; - } - } - - /** - * @description Create a new document - * @returns IDocument created - */ - @Post("/api/v1/customer/documents") - protected async post(req: Request, response: Response) { - try { - //init Document resource with request body values - const documentEntity = Document.hydrate(req.body); - - //validate document - await validateOrReject(documentEntity, { groups: ["createDocument"] }); - - //call service to get prisma entity - const prismaEntityCreated = await this.documentsService.create(documentEntity); - - //Hydrate ressource with prisma entity - const documentEntityCreated = Document.hydrate(prismaEntityCreated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, documentEntityCreated); - } catch (error) { - this.httpBadRequest(response, error); - return; - } - } - - /** - * @description Update a specific document - */ - @Put("/api/v1/customer/documents/:uid") - protected async update(req: Request, response: Response) { - try { - const uid = req.params["uid"]; - if (!uid) { - throw new Error("No uid provided"); - } - - //init Document resource with request body values - const documentEntity = new Document(); - Document.hydrate(documentEntity, req.body); - - //validate document - await validateOrReject(documentEntity, { groups: ["createDocument"] }); - - //call service to get prisma entity - const prismaEntityUpdated: Documents = await this.documentsService.update(uid, documentEntity); - - //Hydrate ressource with prisma entity - const document = Document.hydrate(prismaEntityUpdated, { strategy: "excludeAll" }); - - //success - this.httpSuccess(response, document); - } catch (error) { - this.httpBadRequest(response, error); - return; - } - } - - /** - * @description Delete a specific document - */ - @Delete("/api/v1/customer/documents/:uid") - protected async delete(req: Request, response: Response) { - try { - const uid = req.params["uid"]; - if (!uid) { - throw new Error("No uid provided"); - } - - //call service to get prisma entity - const documentEntity: Documents = await this.documentsService.delete(uid); - - //Hydrate ressource with prisma entity - const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); - - //success - this.httpSuccess(response, document); - } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response); return; } } @@ -127,22 +51,25 @@ export default class DocumentsController extends ApiController { /** * @description Get a specific document by uid */ - @Get("/api/v1/customer/documents/:uid") + @Get("/api/v1/customer/documents/:uid",[authHandler,documentHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); } - let documentEntity: Documents; - //get query - if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - documentEntity = await this.documentsService.getByUid(uid, query); - } else { - //call service to get prisma entity - documentEntity = await this.documentsService.getByUid(uid); + const documentEntity = await this.documentsService.getByUid(uid, query); + + if (!documentEntity) { + this.httpNotFoundRequest(response, "document not found"); + return; } //Hydrate ressource with prisma entity @@ -151,7 +78,7 @@ export default class DocumentsController extends ApiController { //success this.httpSuccess(response, document); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response); return; } } diff --git a/src/app/api/customer/FilesController.ts b/src/app/api/customer/FilesController.ts new file mode 100644 index 00000000..f58b3944 --- /dev/null +++ b/src/app/api/customer/FilesController.ts @@ -0,0 +1,224 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import FilesService from "@Services/common/FilesService/FilesService"; +import { Files, Prisma } from "@prisma/client"; +import { File } from "le-coffre-resources/dist/Customer"; +import { Document } from "le-coffre-resources/dist/Customer"; +import { validateOrReject } from "class-validator"; +import DocumentsService from "@Services/customer/DocumentsService/DocumentsService"; +import authHandler from "@App/middlewares/AuthHandler"; +import fileHandler from "@App/middlewares/CustomerHandler/FileHandler"; + +@Controller() +@Service() +export default class FilesController extends ApiController { + constructor(private filesService: FilesService, private documentService: DocumentsService) { + super(); + } + + /** + * @description Get all Files + * @returns File[] list of Files + */ + @Get("/api/v1/customer/files", [authHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.FilesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const customerId: string = req.body.user.customerId; + const customerWhereInput: Prisma.FilesWhereInput = { document: { depositor: { uid: customerId } } }; + query.where = customerWhereInput; + //call service to get prisma entity + const fileEntities = await this.filesService.get(query); + + //Hydrate ressource with prisma entity + const files = File.hydrateArray(fileEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, files); + } catch (error) { + this.httpBadRequest(response, error); + return; + } + } + + /** + * @description Get a specific File by uid + */ + @Get("/api/v1/customer/files/download/:uid", [authHandler, fileHandler]) + protected async download(req: Request, response: Response) { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "uid not found"); + return; + } + try { + const fileInfo = await this.filesService.download(uid); + + if (!fileInfo) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + response.setHeader("Content-Type", fileInfo.file.mimetype); + response.setHeader("Content-Disposition", `inline; filename=${encodeURIComponent(fileInfo.file.file_name)}`); + + this.httpSuccess(response, fileInfo.buffer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new File + * @returns File created + */ + @Post("/api/v1/customer/files", [authHandler, fileHandler]) + protected async post(req: Request, response: Response) { + try { + //get file + if (!req.file) throw new Error("No file provided"); + + //init File resource with request body values + const fileEntity = File.hydrate(JSON.parse(req.body["q"])); + + //validate File + await validateOrReject(fileEntity, { groups: ["createFile"] }); + + //call service to get prisma entity + const fileEntityCreated = await this.filesService.create(fileEntity, req.file); + + const document = await this.documentService.getByUid(fileEntity.document!.uid!); + + const documentToUpdate = Document.hydrate(document!); + + documentToUpdate!.document_status = "DEPOSITED"; + await this.documentService.update(document!.uid!, documentToUpdate); + + //Hydrate ressource with prisma entity + const fileEntityHydrated = File.hydrate(fileEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, fileEntityHydrated); + } catch (error) { + this.httpBadRequest(response, error); + return; + } + } + + /** + * @description Update a specific file + */ + @Put("/api/v1/customer/files/:uid", [authHandler, fileHandler]) + protected async update(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + throw new Error("No uid provided"); + } + + const fileFound = await this.filesService.getByUid(uid); + + if (!fileFound) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //init File resource with request body values + const fileEntity = File.hydrate(req.body); + + //call service to get prisma entity + const fileEntityUpdated: Files = await this.filesService.update(uid, fileEntity); + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntityUpdated, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpBadRequest(response, error); + return; + } + } + + /** + * @description Delete a specific File + */ + @Delete("/api/v1/customer/files/:uid", [authHandler, fileHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const fileFound = await this.filesService.getByUid(uid); + + if (!fileFound) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //call service to get prisma entity + const fileEntity = await this.filesService.deleteKeyAndArchive(uid); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific File by uid + */ + @Get("/api/v1/customer/files/:uid", [authHandler, fileHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const fileEntity = await this.filesService.getByUid(uid, query); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/customer/OfficeFoldersController.ts b/src/app/api/customer/OfficeFoldersController.ts new file mode 100644 index 00000000..e524b445 --- /dev/null +++ b/src/app/api/customer/OfficeFoldersController.ts @@ -0,0 +1,113 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficeFoldersService from "@Services/customer/OfficeFoldersService/OfficeFoldersService"; +import { Service } from "typedi"; +import { OfficeFolders, Prisma } from "@prisma/client"; +import { OfficeFolder } from "le-coffre-resources/dist/Customer"; +// import authHandler from "@App/middlewares/AuthHandler"; +// import ruleHandler from "@App/middlewares/RulesHandler"; +// import folderHandler from "@App/middlewares/OfficeMembershipHandlers/FolderHandler"; + +@Controller() +@Service() +export default class OfficeFoldersController extends ApiController { + constructor(private officeFoldersService: OfficeFoldersService) { + super(); + } + + /** + * @description Get all folders + */ + @Get("/api/v1/customer/folders") + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.OfficeFoldersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + OR: [ + { + name: { contains: filter, mode: "insensitive" }, + }, + { + folder_number: { contains: filter, mode: "insensitive" }, + }, + { + customers: { + some: { + contact: { + OR: [ + { first_name: { contains: filter, mode: "insensitive" } }, + { last_name: { contains: filter, mode: "insensitive" } }, + ], + }, + }, + }, + }, + ], + }, + }; + } + const officeWhereInput: Prisma.OfficesWhereInput = {}; + if (!query.where) query.where = { office: officeWhereInput }; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrateArray(officeFolderEntities, { + strategy: "excludeAll", + }); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific folder by uid + * @returns IFolder + */ + @Get("/api/v1/customer/folders/:uid") + 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 officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); + + if (!officeFolderEntity) { + this.httpNotFoundRequest(response, "folder not found"); + return; + } + + //Hydrate ressource with prisma entity + const officeFolder = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeFolder); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/franceConnect/CustomerController.ts b/src/app/api/franceConnect/CustomerController.ts new file mode 100644 index 00000000..633bed86 --- /dev/null +++ b/src/app/api/franceConnect/CustomerController.ts @@ -0,0 +1,63 @@ +import { Response, Request } from "express"; +import { Controller, Post } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import AuthService from "@Services/common/AuthService/AuthService"; +import { JwtPayload } from "jsonwebtoken"; + +@Controller() +@Service() +export default class CustomerController extends ApiController { + constructor(private authService: AuthService) { + super(); + } + + @Post("/api/v1/france-connect/customer/login/:email") + protected async login(req: Request, response: Response) { + try { + const email = req.params["email"]; + if (!email) throw new Error("email is required"); + + const payload = await this.authService.getCustomerJwtPayload(email); + const accessToken = this.authService.generateAccessToken(payload); + const refreshToken = this.authService.generateRefreshToken(payload); + //success + this.httpSuccess(response, { accessToken, refreshToken }); + } catch (error) { + this.httpInternalError(response); + return; + } + } + + @Post("/api/v1/france-connect/customer/refresh-token") + protected async refreshToken(req: Request, response: Response) { + try { + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + if (!token) { + this.httpBadRequest(response); + return; + } + + let accessToken; + this.authService.verifyRefreshToken(token, (err, customerPayload) => { + if (err) { + this.httpUnauthorized(response); + return; + } + + const customer = customerPayload as JwtPayload; + delete customer.iat; + delete customer!.exp; + accessToken = this.authService.generateAccessToken(customer); + }); + + //success + this.httpSuccess(response, accessToken); + } catch (error) { + this.httpInternalError(response); + return; + } + } +} diff --git a/src/app/api/idnot-user/UserInfoController.ts b/src/app/api/idnot-user/UserInfoController.ts deleted file mode 100644 index f3854a1d..00000000 --- a/src/app/api/idnot-user/UserInfoController.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Response, Request } from "express"; - import { Controller,Post } from "@ControllerPattern/index"; - import ApiController from "@Common/system/controller-pattern/ApiController"; - import { Service } from "typedi"; -import AuthService from "@Services/private-services/AuthService/AuthService"; -//import User from "le-coffre-resources/dist/Notary"; - - @Controller() - @Service() - export default class UserInfoController extends ApiController { - constructor(private authService: AuthService) { - super(); - } - - /** - * @description Get user created from IdNot authentification - * @returns User - */ - @Post("/api/v1/idnot-user/:code") - protected async getUserInfosFromIdnot(req: Request, response: Response) { - try { - const code = req.params["code"]; - const user = await this.authService.getUserFromIdNotTokens(code!); - //success - this.httpSuccess(response, user); - } catch (error) { - this.httpBadRequest(response, error); - return; - } - } - -} \ No newline at end of file diff --git a/src/app/api/idnot/UserController.ts b/src/app/api/idnot/UserController.ts new file mode 100644 index 00000000..b63d3fec --- /dev/null +++ b/src/app/api/idnot/UserController.ts @@ -0,0 +1,89 @@ +import { Response, Request } from "express"; +import { Controller, Post } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import AuthService from "@Services/common/AuthService/AuthService"; +import { JwtPayload } from "jsonwebtoken"; + +@Controller() +@Service() +export default class UserController extends ApiController { + constructor(private authService: AuthService) { + super(); + } + + /** + * @description Get user created from IdNot authentification + * @todo Used for test, should be removed + * @returns User + */ + @Post("/api/v1/idnot/user/:code") + protected async getUserInfosFromIdnot(req: Request, response: Response) { + console.warn("/api/v1/idnot/user/:code used for test, should be removed"); + + try { + const code = req.params["code"]; + if (!code) throw new Error("code is required"); + const token = await fetch("https://qual-connexion.idnot.fr/IdPOAuth2/token/idnot_idp_v1", { method: "POST" }); + console.log(token); + //const user = await this.authService.getUserFromIdNotTokens(code!); + //success + this.httpSuccess(response); + } catch (error) { + console.log(error); + this.httpInternalError(response); + return; + } + } + + @Post("/api/v1/idnot/user/login/:idnot") + protected async login(req: Request, response: Response) { + try { + const id = req.params["idnot"]; + if (!id) throw new Error("idnot is required"); + + const payload = await this.authService.getUserJwtPayload(id); + const accessToken = this.authService.generateAccessToken(payload); + const refreshToken = this.authService.generateRefreshToken(payload); + + //success + this.httpSuccess(response, { accessToken, refreshToken }); + } catch (error) { + console.log(error); + this.httpInternalError(response); + return; + } + } + + @Post("/api/v1/idnot/user/refresh-token") + protected async refreshToken(req: Request, response: Response) { + try { + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + if (!token) { + this.httpBadRequest(response); + return; + } + + let accessToken; + this.authService.verifyRefreshToken(token, (err, userPayload) => { + if (err) { + this.httpUnauthorized(response); + return; + } + + const user = userPayload as JwtPayload; + delete user.iat; + delete user!.exp; + accessToken = this.authService.generateAccessToken(user); + }); + + //success + this.httpSuccess(response, accessToken); + } catch (error) { + this.httpInternalError(response); + return; + } + } +} diff --git a/src/app/api/notary/CustomersController.ts b/src/app/api/notary/CustomersController.ts new file mode 100644 index 00000000..59d070c7 --- /dev/null +++ b/src/app/api/notary/CustomersController.ts @@ -0,0 +1,146 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import CustomersService from "@Services/notary/CustomersService/CustomersService"; +import { Service } from "typedi"; +import { Customer } from "le-coffre-resources/dist/Notary"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; + +@Controller() +@Service() +export default class CustomersController extends ApiController { + constructor(private customersService: CustomersService) { + super(); + } + + /** + * @description Get all customers + */ + @Get("/api/v1/notary/customers", [authHandler, ruleHandler]) + 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 customersEntities = await this.customersService.get(query); + + //Hydrate ressource with prisma entity + const customers = Customer.hydrateArray(customersEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, customers); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new customer + */ + @Post("/api/v1/notary/customers", [authHandler, ruleHandler]) + protected async post(req: Request, response: Response) { + try { + //init IUser resource with request body values + const customerEntity = Customer.hydrate(req.body); + //validate user + await validateOrReject(customerEntity, { groups: ["createCustomer"], forbidUnknownValues: false }); + + //call service to get prisma entity + const customerEntityCreated = await this.customersService.create(customerEntity); + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific customer by uid + */ + @Put("/api/v1/notary/customers/:uid", [authHandler, ruleHandler]) + 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.customersService.getByUid(uid); + + if (!userFound) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + + //init IUser resource with request body values + const customerEntity = Customer.hydrate(req.body); + + //validate user + await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); + + //call service to get prisma entity + const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific customer by uid + */ + @Get("/api/v1/notary/customers/:uid", [authHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const customerEntity = await this.customersService.getByUid(uid, query); + + if (!customerEntity) { + this.httpNotFoundRequest(response, "customer not found"); + return; + } + + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, customer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/DeedTypesController.ts b/src/app/api/notary/DeedTypesController.ts new file mode 100644 index 00000000..a1f44f4a --- /dev/null +++ b/src/app/api/notary/DeedTypesController.ts @@ -0,0 +1,157 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import DeedTypesService from "@Services/notary/DeedTypesService/DeedTypesService"; +import { DeedTypes, Prisma } from "@prisma/client"; +import { DeedType } from "le-coffre-resources/dist/Notary"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import deedTypeHandler from "@App/middlewares/OfficeMembershipHandlers/DeedTypeHandler"; + +@Controller() +@Service() +export default class DeedTypesController extends ApiController { + constructor(private deedTypesService: DeedTypesService) { + super(); + } + + /** + * @description Get all deedtypes + * @returns Deedtype[] list of deedtypes + */ + @Get("/api/v1/notary/deed-types", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DeedTypesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const deedTypeEntities: DeedTypes[] = await this.deedTypesService.get(query); + + //Hydrate ressource with prisma entity + const DeedTypes = DeedType.hydrateArray(deedTypeEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, DeedTypes); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new deedtype + * @returns Deedtype created + */ + @Post("/api/v1/notary/deed-types", [authHandler, ruleHandler, deedTypeHandler]) + protected async post(req: Request, response: Response) { + try { + //init DeedType resource with request body values + const deedTypeEntity = DeedType.hydrate(req.body); + + //validate deed type + await validateOrReject(deedTypeEntity, { groups: ["createDeedType"], forbidUnknownValues: false }); + + //call service to get prisma entity + const deedTypeEntityCreated = await this.deedTypesService.create(deedTypeEntity); + + //Hydrate ressource with prisma entity + const deedType = DeedType.hydrate(deedTypeEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, deedType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific deedtype by uid + * @returns Deedtype modified + */ + @Put("/api/v1/notary/deed-types/:uid", [authHandler, ruleHandler, deedTypeHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const deedTypeFound = await this.deedTypesService.getByUid(uid); + + if (!deedTypeFound) { + this.httpNotFoundRequest(response, "deed type not found"); + return; + } + + //init DeedType resource with request body values + const deedTypeEntity = DeedType.hydrate(req.body); + + //validate deed type + await validateOrReject(deedTypeEntity, { groups: ["updateDeedType"] }); + + //call service to get prisma entity + const deedTypeEntityUpdated = await this.deedTypesService.update(uid, deedTypeEntity); + + //Hydrate ressource with prisma entity + const deedType = DeedType.hydrate(deedTypeEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, deedType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific deedtype by uid + * @returns IDeedtype + */ + @Get("/api/v1/notary/deed-types/:uid", [authHandler, ruleHandler, deedTypeHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const deedTypeEntity = await this.deedTypesService.getByUid(uid, query); + + if (!deedTypeEntity) { + this.httpNotFoundRequest(response, "deed type not found"); + return; + } + + //Hydrate ressource with prisma entity + const deedType = DeedType.hydrate(deedTypeEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, deedType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/DeedsController.ts b/src/app/api/notary/DeedsController.ts new file mode 100644 index 00000000..52c664da --- /dev/null +++ b/src/app/api/notary/DeedsController.ts @@ -0,0 +1,125 @@ +import { Response, Request } from "express"; +import { Controller, Get, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import DeedsService from "@Services/notary/DeedsService/DeedsService"; +import { Service } from "typedi"; +import { Deeds, Prisma } from "@prisma/client"; +import { Deed } from "le-coffre-resources/dist/Notary"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import deedHandler from "@App/middlewares/OfficeMembershipHandlers/DeedHandler"; + +@Controller() +@Service() +export default class DeedsController extends ApiController { + constructor(private deedsService: DeedsService) { + super(); + } + + /** + * @description Get all deeds + * @returns Deed[] list of deeds + */ + @Get("/api/v1/notary/deeds", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DeedsFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { deed_type : {office: officeWhereInput}}; + query.where.deed_type!.office = officeWhereInput; + + //call service to get prisma entity + const deedEntities: Deeds[] = await this.deedsService.get(query); + + //Hydrate ressource with prisma entity + const deeds = Deed.hydrateArray(deedEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, deeds); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific deed by uid + * @returns Deed + */ + @Get("/api/v1/notary/deeds/:uid", [authHandler, ruleHandler, deedHandler]) + 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 deedEntity = await this.deedsService.getByUid(uid, query); + + if (!deedEntity) { + this.httpNotFoundRequest(response, "deed not found"); + return; + } + + //Hydrate ressource with prisma entity + const deed = Deed.hydrate(deedEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, deed); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific deed by uid + */ + @Put("/api/v1/notary/deeds/:uid", [authHandler, ruleHandler, deedHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const deedFound = await this.deedsService.getByUid(uid); + + if (!deedFound) { + this.httpNotFoundRequest(response, "deed not found"); + return; + } + + //init OfficeFolder resource with request body values + const deedEntity = Deed.hydrate(req.body); + + //validate folder + await validateOrReject(deedEntity, { groups: ["updateDeed"], forbidUnknownValues: false }); + + //call service to get prisma entity + const deedEntityUpdated = await this.deedsService.update(uid, deedEntity); + + //Hydrate ressource with prisma entity + const deed = Deed.hydrate(deedEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, deed); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/DocumentTypesController.ts b/src/app/api/notary/DocumentTypesController.ts new file mode 100644 index 00000000..6a1a81bd --- /dev/null +++ b/src/app/api/notary/DocumentTypesController.ts @@ -0,0 +1,146 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import DocumentTypesService from "@Services/notary/DocumentTypesService/DocumentTypesService"; +import { DocumentTypes, Prisma } from "@prisma/client"; +import ObjectHydrate from "@Common/helpers/ObjectHydrate"; +import { DocumentType } from "le-coffre-resources/dist/Notary"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import documentTypeHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentTypeHandler"; + +@Controller() +@Service() +export default class DocumentTypesController extends ApiController { + constructor(private documentTypesService: DocumentTypesService) { + super(); + } + + /** + * @description Get all document-types + */ + @Get("/api/v1/notary/document-types", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DocumentTypesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const documentTypeEntities: DocumentTypes[] = await this.documentTypesService.get(query); + + //Hydrate ressource with prisma entity + const documentTypes = DocumentType.hydrateArray(documentTypeEntities, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, documentTypes); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new documentType + */ + @Post("/api/v1/notary/document-types", [authHandler, ruleHandler, documentTypeHandler]) + protected async post(req: Request, response: Response) { + try { + //init DocumentType resource with request body values + const documentTypeEntity = DocumentType.hydrate(req.body); + //validate user + await validateOrReject(documentTypeEntity, { groups: ["createDocumentType"], forbidUnknownValues: false }); + //call service to get prisma entity + const documentTypeEntityCreated = await this.documentTypesService.create(documentTypeEntity); + //Hydrate ressource with prisma entity + const userEntityCreated = DocumentType.hydrate(documentTypeEntityCreated, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, userEntityCreated); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific documentType by uid + */ + @Put("/api/v1/notary/document-types/:uid", [authHandler, ruleHandler, documentTypeHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentTypeFound = await this.documentTypesService.getByUid(uid); + + if (!documentTypeFound) { + this.httpNotFoundRequest(response, "document type not found"); + return; + } + //init DocumentType resource with request body values + const documentTypeEntity = DocumentType.hydrate(req.body); + + //validate user + await validateOrReject(documentTypeEntity, { groups: ["updateDocumentType"] }); + + //call service to get prisma entity + const documentTypeEntityUpdated = await this.documentTypesService.update(uid, documentTypeEntity); + + //Hydrate ressource with prisma entity + const documentType = DocumentType.hydrate(documentTypeEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, documentType); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific documentType by uid + */ + @Get("/api/v1/notary/document-types/:uid", [authHandler, ruleHandler, documentTypeHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const documentTypeEntity = await this.documentTypesService.getByUid(uid, query); + + //Hydrate ressource with prisma entity + const user = ObjectHydrate.hydrate(new DocumentType(), documentTypeEntity!, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, user); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/DocumentsController.ts b/src/app/api/notary/DocumentsController.ts new file mode 100644 index 00000000..29fa5492 --- /dev/null +++ b/src/app/api/notary/DocumentsController.ts @@ -0,0 +1,193 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import DocumentsService from "@Services/notary/DocumentsService/DocumentsService"; +import { Documents, Prisma } from "@prisma/client"; +import { Document } from "le-coffre-resources/dist/Notary"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import documentHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentHandler"; +import EmailBuilder from "@Common/emails/EmailBuilder"; + +@Controller() +@Service() +export default class DocumentsController extends ApiController { + constructor(private documentsService: DocumentsService, private emailBuilder: EmailBuilder) { + super(); + } + + /** + * @description Get all documents + * @returns IDocument[] list of documents + */ + @Get("/api/v1/notary/documents", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.DocumentsFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { document_type : {office: officeWhereInput}}; + query.where.document_type!.office = officeWhereInput; + + //call service to get prisma entity + const documentEntities = await this.documentsService.get(query); + + //Hydrate ressource with prisma entity + const documents = Document.hydrateArray(documentEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, documents); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new document + * @returns IDocument created + */ + @Post("/api/v1/notary/documents", [authHandler, ruleHandler, documentHandler]) + protected async post(req: Request, response: Response) { + try { + //init Document resource with request body values + const documentEntity = Document.hydrate(req.body); + + //validate document + await validateOrReject(documentEntity, { groups: ["createDocument"], forbidUnknownValues: false }); + + //call service to get prisma entity + const documentEntityCreated = await this.documentsService.create(documentEntity); + + //create email for asked document + this.emailBuilder.sendDocumentEmails(documentEntityCreated); + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Update a specific document + */ + @Put("/api/v1/notary/documents/:uid", [authHandler, ruleHandler, documentHandler]) + protected async update(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentFound = await this.documentsService.getByUid(uid); + + if (!documentFound) { + this.httpNotFoundRequest(response, "document not found"); + return; + } + + //init Document resource with request body values + const documentEntity = Document.hydrate(req.body); + + //validate document + await validateOrReject(documentEntity, { groups: ["updateDocument"] }); + + //call service to get prisma entity + const documentEntityUpdated: Documents = await this.documentsService.update(uid, documentEntity, req.body.refused_reason); + + //create email for asked document + this.emailBuilder.sendDocumentEmails(documentEntityUpdated); + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntityUpdated, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Delete a specific document + */ + @Delete("/api/v1/notary/documents/:uid", [authHandler, ruleHandler, documentHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentFound = await this.documentsService.getByUid(uid); + + if (!documentFound) { + this.httpNotFoundRequest(response, "document not found"); + return; + } + + //call service to get prisma entity + const documentEntity: Documents = await this.documentsService.delete(uid); + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific document by uid + */ + @Get("/api/v1/notary/documents/:uid", [authHandler, ruleHandler, documentHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const documentEntity = await this.documentsService.getByUid(uid, query); + + if (!documentEntity) { + this.httpNotFoundRequest(response, "document not found"); + return; + } + + //Hydrate ressource with prisma entity + const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, document); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/FilesController.ts b/src/app/api/notary/FilesController.ts new file mode 100644 index 00000000..26334d08 --- /dev/null +++ b/src/app/api/notary/FilesController.ts @@ -0,0 +1,149 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import FilesService from "@Services/common/FilesService/FilesService"; +import { Prisma } from "@prisma/client"; +import { File } from "le-coffre-resources/dist/Notary"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import fileHandler from "@App/middlewares/OfficeMembershipHandlers/FileHandler"; + +@Controller() +@Service() +export default class FilesController extends ApiController { + constructor(private filesService: FilesService) { + super(); + } + + /** + * @description Get all Files + * @returns File[] list of Files + */ + @Get("/api/v1/notary/files", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.FilesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { document: { folder: {office: officeWhereInput}}}; + query.where.document!.folder!.office = officeWhereInput; + //call service to get prisma entity + const fileEntities = await this.filesService.get(query); + + //Hydrate ressource with prisma entity + const files = File.hydrateArray(fileEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, files); + } catch (error) { + this.httpBadRequest(response, error); + return; + } + } + + /** + * @description Get a specific File by uid + */ + @Get("/api/v1/notary/files/download/:uid", [authHandler, ruleHandler, fileHandler]) + protected async download(req: Request, response: Response) { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "uid not found"); + return; + } + try { + const fileInfo = await this.filesService.download(uid); + + if (!fileInfo) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + response.setHeader("Content-Type", fileInfo.file.mimetype); + response.setHeader("Content-Disposition", `inline; filename=${encodeURIComponent(fileInfo.file.file_name)}`); + + this.httpSuccess(response, fileInfo.buffer); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Delete a specific File + */ + @Delete("/api/v1/notary/files/:uid", [authHandler, ruleHandler, fileHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const fileFound = await this.filesService.getByUid(uid); + + if (!fileFound) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //call service to get prisma entity + const fileEntity = await this.filesService.deleteKeyAndArchive(uid); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific File by uid + */ + @Get("/api/v1/notary/files/:uid", [authHandler, ruleHandler, fileHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const fileEntity = await this.filesService.getByUid(uid, query); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + + //Hydrate ressource with prisma entity + const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, file); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/OfficeFoldersController.ts b/src/app/api/notary/OfficeFoldersController.ts new file mode 100644 index 00000000..af46d774 --- /dev/null +++ b/src/app/api/notary/OfficeFoldersController.ts @@ -0,0 +1,213 @@ +import { Response, Request } from "express"; +import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficeFoldersService from "@Services/notary/OfficeFoldersService/OfficeFoldersService"; +import { Service } from "typedi"; +import { OfficeFolders, Prisma } from "@prisma/client"; +import { OfficeFolder } from "le-coffre-resources/dist/Notary"; +import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import folderHandler from "@App/middlewares/OfficeMembershipHandlers/FolderHandler"; + +@Controller() +@Service() +export default class OfficeFoldersController extends ApiController { + constructor(private officeFoldersService: OfficeFoldersService) { + super(); + } + + /** + * @description Get all folders + */ + @Get("/api/v1/notary/folders", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.OfficeFoldersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + OR: [ + { + name: { contains: filter, mode: "insensitive" }, + }, + { + folder_number: { contains: filter, mode: "insensitive" }, + }, + { + customers: { + some: { + contact: { + OR: [ + { first_name: { contains: filter, mode: "insensitive" } }, + { last_name: { contains: filter, mode: "insensitive" } }, + ], + }, + }, + }, + }, + ], + }, + }; + } + + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + //call service to get prisma entity + const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrateArray(officeFolderEntities, { + strategy: "excludeAll", + }); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new folder + */ + @Post("/api/v1/notary/folders", [authHandler, ruleHandler, folderHandler]) + protected async post(req: Request, response: Response) { + try { + //init OfficeFolder resource with request body values + const officeFolderRessource = OfficeFolder.hydrate(req.body); + await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); + + //call service to get prisma entity + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific folder by uid + */ + @Put("/api/v1/notary/folders/:uid", [authHandler, ruleHandler, folderHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeFolderFound = await this.officeFoldersService.getByUid(uid); + + if (!officeFolderFound) { + this.httpNotFoundRequest(response, "office folder not found"); + return; + } + + //init OfficeFolder resource with request body values + const officeFolderEntity = OfficeFolder.hydrate(req.body); + + //validate folder + await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); + + //call service to get prisma entity + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific folder by uid + * @returns IFolder + */ + @Get("/api/v1/notary/folders/:uid", [authHandler, ruleHandler, folderHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); + + if (!officeFolderEntity) { + this.httpNotFoundRequest(response, "folder not found"); + return; + } + + //Hydrate ressource with prisma entity + const officeFolder = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeFolder); + } catch (error) { + this.httpInternalError(response, error); + return; + } + this.httpSuccess(response, await this.officeFoldersService.getByUid("uid")); + } + + /** + * @description Delete a specific folder + */ + @Delete("/api/v1/notary/folders/:uid", [authHandler, ruleHandler, folderHandler]) + protected async delete(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeFolderFound = await this.officeFoldersService.getByUid(uid); + + if (!officeFolderFound) { + this.httpNotFoundRequest(response, "office folder not found"); + return; + } + + //call service to get prisma entity + const officeFoldertEntity: OfficeFolders = await this.officeFoldersService.delete(uid); + + //Hydrate ressource with prisma entity + const officeFolder = OfficeFolder.hydrate(officeFoldertEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeFolder); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/OfficeRolesController.ts b/src/app/api/notary/OfficeRolesController.ts new file mode 100644 index 00000000..55aea36a --- /dev/null +++ b/src/app/api/notary/OfficeRolesController.ts @@ -0,0 +1,83 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficeRolesService from "@Services/notary/OfficeRolesService/OfficeRolesService"; +import { Service } from "typedi"; +import { OfficeRole } from "le-coffre-resources/dist/Notary"; +import { Prisma } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import officeRoleHandler from "@App/middlewares/OfficeMembershipHandlers/OfficeRoleHandler"; + +@Controller() +@Service() +export default class OfficeRolesController extends ApiController { + constructor(private officeRolesService: OfficeRolesService) { + super(); + } + + /** + * @description Get all officeRoles + */ + @Get("/api/v1/notary/office-roles", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.OfficeRolesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const officeRolesEntities = await this.officeRolesService.get(query); + + //Hydrate ressource with prisma entity + const officeRoles = OfficeRole.hydrateArray(officeRolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeRoles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific officeRole by uid + */ + @Get("/api/v1/notary/office-roles/:uid", [authHandler, ruleHandler, officeRoleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const officeRoleEntity = await this.officeRolesService.getByUid(uid, query); + + if (!officeRoleEntity) { + this.httpNotFoundRequest(response, "officeRole not found"); + return; + } + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/OfficesController.ts b/src/app/api/notary/OfficesController.ts new file mode 100644 index 00000000..52b8fede --- /dev/null +++ b/src/app/api/notary/OfficesController.ts @@ -0,0 +1,73 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficesService from "@Services/notary/OfficesService/OfficesService"; +import { Service } from "typedi"; +import { Offices } from "@prisma/client"; +import { Office as OfficeResource } from "le-coffre-resources/dist/Notary"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import authHandler from "@App/middlewares/AuthHandler"; + +@Controller() +@Service() +export default class OfficesController extends ApiController { + constructor(private officesService: OfficesService) { + super(); + } + /** + * @description Get all offices + */ + @Get("/api/v1/notary/offices", [authHandler, ruleHandler]) + 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 officesEntities: Offices[] = await this.officesService.get(query); + //Hydrate ressource with prisma entity + const offices = OfficeResource.hydrateArray(officesEntities, { strategy: "excludeAll" }); + //success + this.httpSuccess(response, offices); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific office by uid + */ + @Get("/api/v1/notary/offices/:uid", [authHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const officeEntity = await this.officesService.getByUid(uid, query); + + if (!officeEntity) { + this.httpNotFoundRequest(response, "office not found"); + return; + } + + //Hydrate ressource with prisma entity + const office = OfficeResource.hydrate(officeEntity, { strategy: "excludeAll" }); + //success + this.httpSuccess(response, office); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/RolesController.ts b/src/app/api/notary/RolesController.ts new file mode 100644 index 00000000..29da8bbd --- /dev/null +++ b/src/app/api/notary/RolesController.ts @@ -0,0 +1,77 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RolesService from "@Services/notary/RolesService/RolesService"; +import { Service } from "typedi"; +import { Role } from "le-coffre-resources/dist/Notary"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; + +@Controller() +@Service() +export default class RolesController extends ApiController { + constructor(private rolesService: RolesService) { + super(); + } + + /** + * @description Get all roles + */ + @Get("/api/v1/notary/roles", [authHandler, ruleHandler]) + 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 rolesEntities = await this.rolesService.get(query); + + //Hydrate ressource with prisma entity + const roles = Role.hydrateArray(rolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, roles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific role by uid + */ + @Get("/api/v1/notary/roles/:uid", [authHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const roleEntity = await this.rolesService.getByUid(uid, query); + + if (!roleEntity) { + this.httpNotFoundRequest(response, "role not found"); + return; + } + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/RulesController.ts b/src/app/api/notary/RulesController.ts new file mode 100644 index 00000000..63d29165 --- /dev/null +++ b/src/app/api/notary/RulesController.ts @@ -0,0 +1,77 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RulesService from "@Services/notary/RulesService/RulesService"; +import { Service } from "typedi"; +import { Rule } from "le-coffre-resources/dist/Notary"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; + +@Controller() +@Service() +export default class RulesController extends ApiController { + constructor(private rulesService: RulesService) { + super(); + } + + /** + * @description Get all rules + */ + @Get("/api/v1/notary/rules", [authHandler, ruleHandler]) + 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 rulesEntities = await this.rulesService.get(query); + + //Hydrate ressource with prisma entity + const rules = Rule.hydrateArray(rulesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rules); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific rule by uid + */ + @Get("/api/v1/notary/rules/:uid", [authHandler, ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const ruleEntity = await this.rulesService.getByUid(uid, query); + + if (!ruleEntity) { + this.httpNotFoundRequest(response, "rule not found"); + return; + } + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/notary/UsersController.ts b/src/app/api/notary/UsersController.ts new file mode 100644 index 00000000..49807103 --- /dev/null +++ b/src/app/api/notary/UsersController.ts @@ -0,0 +1,83 @@ +import { Response, Request } from "express"; +import { Controller, Get } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import UsersService from "@Services/notary/UsersService/UsersService"; +import { Service } from "typedi"; +import User from "le-coffre-resources/dist/Notary"; +import { Prisma } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import userHandler from "@App/middlewares/OfficeMembershipHandlers/UserHandler"; + +@Controller() +@Service() +export default class UsersController extends ApiController { + constructor(private usersService: UsersService) { + super(); + } + + /** + * @description Get all users + */ + @Get("/api/v1/notary/users", [authHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.UsersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office_membership: officeWhereInput}; + query.where.office_membership = officeWhereInput; + + //call service to get prisma entity + const usersEntities = await this.usersService.get(query); + + //Hydrate ressource with prisma entity + const users = User.hydrateArray(usersEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, users); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific user by uid + */ + @Get("/api/v1/notary/users/:uid", [authHandler, ruleHandler, userHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + //get query + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const userEntity = await this.usersService.getByUid(uid, query); + + if (!userEntity) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + + //Hydrate ressource with prisma entity + const user = User.hydrate(userEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, user); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/AppointmentsController.ts b/src/app/api/super-admin/AppointmentsController.ts new file mode 100644 index 00000000..1c3f7346 --- /dev/null +++ b/src/app/api/super-admin/AppointmentsController.ts @@ -0,0 +1,77 @@ +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"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class AppointmentsController extends ApiController { + constructor(private appointmentsService: AppointmentsService) { + super(); + } + + /** + * @description Get all appointments + */ + @Get("/api/v1/super-admin/appointments", [authHandler, roleHandler]) + 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(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, roleHandler]) + 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(appointmentEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, appointment); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/CustomersController.ts b/src/app/api/super-admin/CustomersController.ts index d283cb95..d1a15fd2 100644 --- a/src/app/api/super-admin/CustomersController.ts +++ b/src/app/api/super-admin/CustomersController.ts @@ -4,8 +4,10 @@ import ApiController from "@Common/system/controller-pattern/ApiController"; import CustomersService from "@Services/super-admin/CustomersService/CustomersService"; import { Service } from "typedi"; import { Customer } from "le-coffre-resources/dist/SuperAdmin"; -import { Customers } from "@prisma/client"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() @@ -17,22 +19,25 @@ export default class CustomersController extends ApiController { /** * @description Get all customers */ - @Get("/api/v1/super-admin/customers") + @Get("/api/v1/super-admin/customers", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } //call service to get prisma entity - const customersEntity = await this.customersService.get(query); + const customersEntities = await this.customersService.get(query); //Hydrate ressource with prisma entity - const customers = Customer.map(Customer, customersEntity, { strategy: "excludeAll" }); + const customers = Customer.hydrateArray(customersEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, customers); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -40,7 +45,7 @@ export default class CustomersController extends ApiController { /** * @description Create a new customer */ - @Post("/api/v1/super-admin/customers") + @Post("/api/v1/super-admin/customers", [authHandler, roleHandler, ruleHandler]) protected async post(req: Request, response: Response) { try { //init IUser resource with request body values @@ -49,16 +54,16 @@ export default class CustomersController extends ApiController { await validateOrReject(customerEntity, { groups: ["createCustomer"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityCreated = await this.customersService.create(customerEntity); + const customerEntityCreated = await this.customersService.create(customerEntity); //Hydrate ressource with prisma entity - const customerEntityCreated = Customer.hydrate(prismaEntityCreated, { + const customer = Customer.hydrate(customerEntityCreated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, customerEntityCreated); + this.httpCreated(response, customer); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -66,31 +71,40 @@ export default class CustomersController extends ApiController { /** * @description Modify a specific customer by uid */ - @Put("/api/v1/super-admin/customers/:uid") + @Put("/api/v1/super-admin/customers/:uid", [authHandler, roleHandler, ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } + + const userFound = await this.customersService.getByUid(uid); + + if (!userFound) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + //init IUser resource with request body values const customerEntity = Customer.hydrate(req.body); - + //validate user await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityUpdated = await this.customersService.update(uid, customerEntity); + const customerEntityUpdated = await this.customersService.update(uid, customerEntity); //Hydrate ressource with prisma entity - const customerEntityUpdated = Customer.hydrate(prismaEntityUpdated, { + const customer = Customer.hydrate(customerEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, customerEntityUpdated); + this.httpSuccess(response, customer); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -98,22 +112,25 @@ export default class CustomersController extends ApiController { /** * @description Get a specific customer by uid */ - @Get("/api/v1/super-admin/customers/:uid") + @Get("/api/v1/super-admin/customers/:uid", [authHandler, roleHandler, ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let customerEntity: Customers; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - customerEntity = await this.customersService.getByUid(uid, query); - } else { - //call service to get prisma entity - customerEntity = await this.customersService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); + } + + const customerEntity = await this.customersService.getByUid(uid, query); + + if (!customerEntity) { + this.httpNotFoundRequest(response, "customer not found"); + return; } //Hydrate ressource with prisma entity @@ -122,7 +139,7 @@ export default class CustomersController extends ApiController { //success this.httpSuccess(response, customer); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/DeedTypesController.ts b/src/app/api/super-admin/DeedTypesController.ts index aba5721c..5ab62ce1 100644 --- a/src/app/api/super-admin/DeedTypesController.ts +++ b/src/app/api/super-admin/DeedTypesController.ts @@ -3,9 +3,13 @@ import { Controller, Get, Post, Put } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesService"; -import { DeedTypes } from "@prisma/client"; +import { DeedTypes, Prisma } from "@prisma/client"; import { DeedType } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import deedTypeHandler from "@App/middlewares/OfficeMembershipHandlers/DeedTypeHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() @@ -18,21 +22,42 @@ export default class DeedTypesController extends ApiController { * @description Get all deedtypes * @returns Deedtype[] list of deedtypes */ - @Get("/api/v1/super-admin/deed-types") + @Get("/api/v1/super-admin/deed-types", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.DeedTypesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + name: { + contains: filter, + mode: "insensitive", + } + } + }; + } + + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + //call service to get prisma entity - const prismaEntity: DeedTypes[] = await this.deedTypesService.get(query); + const deedTypeEntities: DeedTypes[] = await this.deedTypesService.get(query); //Hydrate ressource with prisma entity - const DeedTypes = DeedType.map(DeedType, prismaEntity, { strategy: "excludeAll" }); + const DeedTypes = DeedType.hydrateArray(deedTypeEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, DeedTypes); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -41,7 +66,7 @@ export default class DeedTypesController extends ApiController { * @description Create a new deedtype * @returns Deedtype created */ - @Post("/api/v1/super-admin/deed-types") + @Post("/api/v1/super-admin/deed-types", [authHandler, roleHandler, ruleHandler, deedTypeHandler]) protected async post(req: Request, response: Response) { try { //init DeedType resource with request body values @@ -51,17 +76,17 @@ export default class DeedTypesController extends ApiController { await validateOrReject(deedTypeEntity, { groups: ["createDeedType"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityCreated = await this.deedTypesService.create(deedTypeEntity); + const deedTypeEntityCreated = await this.deedTypesService.create(deedTypeEntity); //Hydrate ressource with prisma entity - const deedTypeEntityCreated = DeedType.hydrate(prismaEntityCreated, { + const deedType = DeedType.hydrate(deedTypeEntityCreated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, deedTypeEntityCreated); + this.httpCreated(response, deedType); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -70,13 +95,22 @@ export default class DeedTypesController extends ApiController { * @description Modify a specific deedtype by uid * @returns Deedtype modified */ - @Put("/api/v1/super-admin/deed-types/:uid") + @Put("/api/v1/super-admin/deed-types/:uid", [authHandler, roleHandler, ruleHandler, deedTypeHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } + + const deedTypeFound = await this.deedTypesService.getByUid(uid); + + if (!deedTypeFound) { + this.httpNotFoundRequest(response, "deed type not found"); + return; + } + //init DeedType resource with request body values const deedTypeEntity = DeedType.hydrate(req.body); @@ -84,17 +118,17 @@ export default class DeedTypesController extends ApiController { await validateOrReject(deedTypeEntity, { groups: ["updateDeedType"] }); //call service to get prisma entity - const prismaEntityUpdated = await this.deedTypesService.update(uid, deedTypeEntity); + const deedTypeEntityUpdated = await this.deedTypesService.update(uid, deedTypeEntity); //Hydrate ressource with prisma entity - const deedTypeEntityUpdated = DeedType.hydrate(prismaEntityUpdated, { + const deedType = DeedType.hydrate(deedTypeEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, deedTypeEntityUpdated); + this.httpSuccess(response, deedType); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -103,22 +137,26 @@ export default class DeedTypesController extends ApiController { * @description Get a specific deedtype by uid * @returns IDeedtype */ - @Get("/api/v1/super-admin/deed-types/:uid") + @Get("/api/v1/super-admin/deed-types/:uid", [authHandler, roleHandler, ruleHandler, deedTypeHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let deedTypeEntity: DeedTypes; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - deedTypeEntity = await this.deedTypesService.getByUid(uid, query); - } else { - //call service to get prisma entity - deedTypeEntity = await this.deedTypesService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); + } + + const deedTypeEntity = await this.deedTypesService.getByUid(uid, query); + + + if (!deedTypeEntity) { + this.httpNotFoundRequest(response, "deed type not found"); + return; } //Hydrate ressource with prisma entity @@ -127,7 +165,7 @@ export default class DeedTypesController extends ApiController { //success this.httpSuccess(response, deedType); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/DeedsController.ts b/src/app/api/super-admin/DeedsController.ts index f8ff9da7..a06de5ad 100644 --- a/src/app/api/super-admin/DeedsController.ts +++ b/src/app/api/super-admin/DeedsController.ts @@ -3,9 +3,13 @@ import { Controller, Get, Put } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import DeedsService from "@Services/super-admin/DeedsService/DeedsService"; import { Service } from "typedi"; -import { Deeds } from "@prisma/client"; +import { Deeds, Prisma } from "@prisma/client"; import { Deed } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import deedHandler from "@App/middlewares/OfficeMembershipHandlers/DeedHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() @@ -18,21 +22,29 @@ export default class DeedsController extends ApiController { * @description Get all deeds * @returns Deed[] list of deeds */ - @Get("/api/v1/super-admin/deeds") + @Get("/api/v1/super-admin/deeds", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.DeedsFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { deed_type : {office: officeWhereInput}}; + query.where.deed_type!.office = officeWhereInput; + //call service to get prisma entity - const prismaEntity: Deeds[] = await this.deedsService.get(query); + const deedEntities: Deeds[] = await this.deedsService.get(query); //Hydrate ressource with prisma entity - const deeds = Deed.map(Deed, prismaEntity, { strategy: "excludeAll" }); + const deeds = Deed.hydrateArray(deedEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, deeds); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -41,22 +53,25 @@ export default class DeedsController extends ApiController { * @description Get a specific deed by uid * @returns Deed */ - @Get("/api/v1/super-admin/deeds/:uid") + @Get("/api/v1/super-admin/deeds/:uid", [authHandler, roleHandler, ruleHandler, deedHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let deedEntity: Deeds; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - deedEntity = await this.deedsService.getByUid(uid, query); - } else { - //call service to get prisma entity - deedEntity = await this.deedsService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); + } + + const deedEntity = await this.deedsService.getByUid(uid, query); + + if (!deedEntity) { + this.httpNotFoundRequest(response, "deed not found"); + return; } //Hydrate ressource with prisma entity @@ -65,7 +80,7 @@ export default class DeedsController extends ApiController { //success this.httpSuccess(response, deed); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -73,31 +88,40 @@ export default class DeedsController extends ApiController { /** * @description Modify a specific deed by uid */ - @Put("/api/v1/super-admin/deeds/:uid") + @Put("/api/v1/super-admin/deeds/:uid", [authHandler, roleHandler, ruleHandler, deedHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } + + const deedFound = await this.deedsService.getByUid(uid); + + if (!deedFound) { + this.httpNotFoundRequest(response, "deed not found"); + return; + } + //init OfficeFolder resource with request body values const deedEntity = Deed.hydrate(req.body); - + //validate folder - await validateOrReject(deedEntity, { groups: ["updateDeed"], forbidUnknownValues: false }); + await validateOrReject(deedEntity, { groups: ["updateDeed"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityUpdated = await this.deedsService.update(uid, deedEntity); + const deedEntityUpdated = await this.deedsService.update(uid, deedEntity); //Hydrate ressource with prisma entity - const deedEntityUpdated = Deed.hydrate(prismaEntityUpdated, { + const deed = Deed.hydrate(deedEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, deedEntityUpdated); + this.httpSuccess(response, deed); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/DocumentTypesController.ts b/src/app/api/super-admin/DocumentTypesController.ts index 3ef79a93..85dc6896 100644 --- a/src/app/api/super-admin/DocumentTypesController.ts +++ b/src/app/api/super-admin/DocumentTypesController.ts @@ -3,10 +3,14 @@ import { Controller, Get, Post, Put } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; import DocumentTypesService from "@Services/super-admin/DocumentTypesService/DocumentTypesService"; -import { DocumentTypes } from "@prisma/client"; +import { DocumentTypes, Prisma } from "@prisma/client"; import ObjectHydrate from "@Common/helpers/ObjectHydrate"; import { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import documentTypeHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentTypeHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() @@ -18,24 +22,31 @@ export default class DocumentTypesController extends ApiController { /** * @description Get all document-types */ - @Get("/api/v1/super-admin/document-types") + @Get("/api/v1/super-admin/document-types", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.DocumentTypesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; //call service to get prisma entity - const prismaEntity: DocumentTypes[] = await this.documentTypesService.get(query); + const documentTypeEntities: DocumentTypes[] = await this.documentTypesService.get(query); //Hydrate ressource with prisma entity - const documentTypes = DocumentType.map(DocumentType, prismaEntity, { + const documentTypes = DocumentType.hydrateArray(documentTypeEntities, { strategy: "excludeAll", }); //success this.httpSuccess(response, documentTypes); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -43,23 +54,28 @@ export default class DocumentTypesController extends ApiController { /** * @description Create a new documentType */ - @Post("/api/v1/super-admin/document-types") + @Post("/api/v1/super-admin/document-types", [authHandler, roleHandler, ruleHandler, documentTypeHandler]) protected async post(req: Request, response: Response) { try { //init DocumentType resource with request body values const documentTypeEntity = DocumentType.hydrate(req.body); + const doesExist = await this.documentTypesService.get({ where: { name: documentTypeEntity.name } }); + if (doesExist.length > 0) { + this.httpBadRequest(response, "Document type name already used"); + return; + } //validate user await validateOrReject(documentTypeEntity, { groups: ["createDocumentType"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityCreated = await this.documentTypesService.create(documentTypeEntity); + const documentTypeEntityCreated = await this.documentTypesService.create(documentTypeEntity); //Hydrate ressource with prisma entity - const userEntityCreated = DocumentType.hydrate(prismaEntityCreated, { + const userEntityCreated = DocumentType.hydrate(documentTypeEntityCreated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, userEntityCreated); + this.httpCreated(response, userEntityCreated); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -67,31 +83,39 @@ export default class DocumentTypesController extends ApiController { /** * @description Modify a specific documentType by uid */ - @Put("/api/v1/super-admin/document-types/:uid") + @Put("/api/v1/super-admin/document-types/:uid", [authHandler, roleHandler, ruleHandler, documentTypeHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentTypeFound = await this.documentTypesService.getByUid(uid); + + if (!documentTypeFound) { + this.httpNotFoundRequest(response, "document type not found"); + return; } //init DocumentType resource with request body values const documentTypeEntity = DocumentType.hydrate(req.body); //validate user - await validateOrReject(documentTypeEntity, { groups: ["update"] }); + await validateOrReject(documentTypeEntity, { groups: ["updateDocumentType"] }); //call service to get prisma entity - const prismaEntityUpdated = await this.documentTypesService.update(uid, documentTypeEntity); + const documentTypeEntityUpdated = await this.documentTypesService.update(uid, documentTypeEntity); //Hydrate ressource with prisma entity - const documentTypeEntityUpdated = DocumentType.hydrate(prismaEntityUpdated, { + const documentType = DocumentType.hydrate(documentTypeEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, documentTypeEntityUpdated); + this.httpSuccess(response, documentType); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -99,31 +123,29 @@ export default class DocumentTypesController extends ApiController { /** * @description Get a specific documentType by uid */ - @Get("/api/v1/super-admin/document-types/:uid") + @Get("/api/v1/super-admin/document-types/:uid", [authHandler, roleHandler, ruleHandler, documentTypeHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let documentTypeEntity: DocumentTypes; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - documentTypeEntity = await this.documentTypesService.getByUid(uid, query); - } else { - //call service to get prisma entity - documentTypeEntity = await this.documentTypesService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); } + + const documentTypeEntity = await this.documentTypesService.getByUid(uid, query); //Hydrate ressource with prisma entity - const user = ObjectHydrate.hydrate(new DocumentType(), documentTypeEntity, { strategy: "excludeAll" }); + const user = ObjectHydrate.hydrate(new DocumentType(), documentTypeEntity!, { strategy: "excludeAll" }); //success this.httpSuccess(response, user); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/DocumentsController.ts b/src/app/api/super-admin/DocumentsController.ts index ae60a9ab..f589ce4c 100644 --- a/src/app/api/super-admin/DocumentsController.ts +++ b/src/app/api/super-admin/DocumentsController.ts @@ -1,11 +1,15 @@ -import { Response, Request } from "express"; -import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import authHandler from "@App/middlewares/AuthHandler"; +import documentHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; import ApiController from "@Common/system/controller-pattern/ApiController"; -import { Service } from "typedi"; +import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import { Documents, Prisma } from "@prisma/client"; import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; -import { Documents } from "@prisma/client"; -import { Document } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import { Request, Response } from "express"; +import { Document } from "le-coffre-resources/dist/SuperAdmin"; +import { Service } from "typedi"; @Controller() @Service() @@ -18,22 +22,33 @@ export default class DocumentsController extends ApiController { * @description Get all documents * @returns IDocument[] list of documents */ - @Get("/api/v1/super-admin/documents") + @Get("/api/v1/super-admin/documents", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.DocumentsFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + + if(!query.where) query.where = { document_type : {office: officeWhereInput}}; + + // query.where.document_type!.office = officeWhereInput; //call service to get prisma entity - const prismaEntity: Documents[] = await this.documentsService.get(query); + + const documentEntities = await this.documentsService.get(query); //Hydrate ressource with prisma entity - const documents = Document.map(Document, prismaEntity, { strategy: "excludeAll" }); + const documents = Document.hydrateArray(documentEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, documents); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -42,7 +57,7 @@ export default class DocumentsController extends ApiController { * @description Create a new document * @returns IDocument created */ - @Post("/api/v1/super-admin/documents") + @Post("/api/v1/super-admin/documents", [authHandler, roleHandler, ruleHandler, documentHandler]) protected async post(req: Request, response: Response) { try { //init Document resource with request body values @@ -52,17 +67,17 @@ export default class DocumentsController extends ApiController { await validateOrReject(documentEntity, { groups: ["createDocument"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityCreated = await this.documentsService.create(documentEntity); + const documentEntityCreated = await this.documentsService.create(documentEntity); //Hydrate ressource with prisma entity - const documentEntityCreated = Document.hydrate(prismaEntityCreated, { + const document = Document.hydrate(documentEntityCreated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, documentEntityCreated); + this.httpCreated(response, document); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -70,30 +85,38 @@ export default class DocumentsController extends ApiController { /** * @description Update a specific document */ - @Put("/api/v1/super-admin/documents/:uid") + @Put("/api/v1/super-admin/documents/:uid", [authHandler, roleHandler, ruleHandler, documentHandler]) protected async update(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); - } + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentFound = await this.documentsService.getByUid(uid); + + if (!documentFound) { + this.httpNotFoundRequest(response, "document not found"); + return; + } //init Document resource with request body values - const documentEntity = Document.hydrate(req.body); + const documentEntity = Document.hydrate(req.body); //validate document await validateOrReject(documentEntity, { groups: ["updateDocument"] }); //call service to get prisma entity - const prismaEntityUpdated: Documents = await this.documentsService.update(uid, documentEntity, req.body.refused_reason); + const documentEntityUpdated: Documents = await this.documentsService.update(uid, documentEntity, req.body.refused_reason); //Hydrate ressource with prisma entity - const document = Document.hydrate(prismaEntityUpdated, { strategy: "excludeAll" }); + const document = Document.hydrate(documentEntityUpdated, { strategy: "excludeAll" }); //success this.httpSuccess(response, document); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -101,12 +124,20 @@ export default class DocumentsController extends ApiController { /** * @description Delete a specific document */ - @Delete("/api/v1/super-admin/documents/:uid") + @Delete("/api/v1/super-admin/documents/:uid", [authHandler, roleHandler, ruleHandler, documentHandler]) protected async delete(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + + const documentFound = await this.documentsService.getByUid(uid); + + if (!documentFound) { + this.httpNotFoundRequest(response, "document not found"); + return; } //call service to get prisma entity @@ -118,7 +149,7 @@ export default class DocumentsController extends ApiController { //success this.httpSuccess(response, document); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -126,22 +157,25 @@ export default class DocumentsController extends ApiController { /** * @description Get a specific document by uid */ - @Get("/api/v1/super-admin/documents/:uid") + @Get("/api/v1/super-admin/documents/:uid", [authHandler, roleHandler, ruleHandler, documentHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let documentEntity: Documents; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - documentEntity = await this.documentsService.getByUid(uid, query); - } else { - //call service to get prisma entity - documentEntity = await this.documentsService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); + } + + const documentEntity = await this.documentsService.getByUid(uid, query); + + if (!documentEntity) { + this.httpNotFoundRequest(response, "document not found"); + return; } //Hydrate ressource with prisma entity @@ -150,7 +184,7 @@ export default class DocumentsController extends ApiController { //success this.httpSuccess(response, document); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/FilesController.ts b/src/app/api/super-admin/FilesController.ts index 68c2dfd1..cb1b7f8d 100644 --- a/src/app/api/super-admin/FilesController.ts +++ b/src/app/api/super-admin/FilesController.ts @@ -1,17 +1,19 @@ import { Response, Request } from "express"; -import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; +import { Controller, Delete, Get } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; -import FilesService from "@Services/private-services/FilesService/FilesService"; -import { Files } from "@prisma/client"; -import { File, Document } from "le-coffre-resources/dist/SuperAdmin"; -import { validateOrReject } from "class-validator"; -import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; +import FilesService from "@Services/common/FilesService/FilesService"; +import { Prisma } from "@prisma/client"; +import { File } from "le-coffre-resources/dist/SuperAdmin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import fileHandler from "@App/middlewares/OfficeMembershipHandlers/FileHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() export default class FilesController extends ApiController { - constructor(private filesService: FilesService, private documentService: DocumentsService) { + constructor(private filesService: FilesService) { super(); } @@ -19,17 +21,24 @@ export default class FilesController extends ApiController { * @description Get all Files * @returns File[] list of Files */ - @Get("/api/v1/super-admin/files") + @Get("/api/v1/super-admin/files", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.FilesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { document: { folder: {office: officeWhereInput}}}; + query.where.document!.folder!.office = officeWhereInput; //call service to get prisma entity - const prismaEntity = await this.filesService.get(query); + const fileEntities = await this.filesService.get(query); //Hydrate ressource with prisma entity - const files = File.map(File, prismaEntity, { strategy: "excludeAll" }); + const files = File.hydrateArray(fileEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, files); @@ -42,87 +51,27 @@ export default class FilesController extends ApiController { /** * @description Get a specific File by uid */ - @Get("/api/v1/super-admin/files/upload/:uid") - protected async getFileData(req: Request, response: Response) { - try { - const uid = req.params["uid"]; - if (!uid) { - throw new Error("No uid provided"); - } - - const file = await this.filesService.updload(uid); - - this.httpSuccess(response, file); - } catch (error) { - this.httpBadRequest(response, error); + @Get("/api/v1/super-admin/files/download/:uid", [authHandler, roleHandler, ruleHandler, fileHandler]) + protected async download(req: Request, response: Response) { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "uid not found"); return; } - } - - /** - * @description Create a new File - * @returns File created - */ - @Post("/api/v1/super-admin/files") - protected async post(req: Request, response: Response) { try { + const fileInfo = await this.filesService.download(uid); - //get file - if(!req.file) throw new Error('No file provided') - - //init File resource with request body values - const fileEntity = File.hydrate(JSON.parse(req.body["q"])); - - //validate File - await validateOrReject(fileEntity, { groups: ["createFile"] }); - - //call service to get prisma entity - const prismaEntityCreated = await this.filesService.create(fileEntity, req.file); - - const document: Document = await this.documentService.getByUid(fileEntity.document!.uid!) - document.document_status = "DEPOSITED"; - await this.documentService.update(document.uid!, document); - - //Hydrate ressource with prisma entity - const fileEntityCreated = File.hydrate(prismaEntityCreated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, fileEntityCreated); - } catch (error) { - this.httpBadRequest(response, error); - return; - } - } - - /** - * @description Update a specific file - */ - @Put("/api/v1/super-admin/files/:uid") - protected async update(req: Request, response: Response) { - try { - const uid = req.params["uid"]; - if (!uid) { - throw new Error("No uid provided"); + if (!fileInfo) { + this.httpNotFoundRequest(response, "file not found"); + return; } - //init File resource with request body values - const fileEntity = File.hydrate(req.body); + response.setHeader("Content-Type", fileInfo.file.mimetype); + response.setHeader("Content-Disposition", `inline; filename=${encodeURIComponent(fileInfo.file.file_name)}`); - //validate file - await validateOrReject(fileEntity, { groups: ["updateFile"] }); - - //call service to get prisma entity - const prismaEntityUpdated: Files = await this.filesService.update(uid, fileEntity); - - //Hydrate ressource with prisma entity - const file = File.hydrate(prismaEntityUpdated, { strategy: "excludeAll" }); - - //success - this.httpSuccess(response, file); + this.httpSuccess(response, fileInfo.buffer); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -130,16 +79,29 @@ export default class FilesController extends ApiController { /** * @description Delete a specific File */ - @Delete("/api/v1/super-admin/files/:uid") + @Delete("/api/v1/super-admin/files/:uid", [authHandler, roleHandler, ruleHandler, fileHandler]) protected async delete(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + + const fileFound = await this.filesService.getByUid(uid); + + if (!fileFound) { + this.httpNotFoundRequest(response, "file not found"); + return; } //call service to get prisma entity - const fileEntity: Files = await this.filesService.delete(uid); + const fileEntity = await this.filesService.deleteKeyAndArchive(uid); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } //Hydrate ressource with prisma entity const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); @@ -147,7 +109,7 @@ export default class FilesController extends ApiController { //success this.httpSuccess(response, file); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -155,23 +117,34 @@ export default class FilesController extends ApiController { /** * @description Get a specific File by uid */ - @Get("/api/v1/super-admin/files/:uid") + @Get("/api/v1/super-admin/files/:uid", [authHandler, roleHandler, ruleHandler, fileHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + const fileEntity = await this.filesService.getByUid(uid, query); + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; } - const fileEntity = await this.filesService.getByUid(uid); - //Hydrate ressource with prisma entity const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); //success this.httpSuccess(response, file); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/LiveVoteController.ts b/src/app/api/super-admin/LiveVoteController.ts new file mode 100644 index 00000000..4a9104ca --- /dev/null +++ b/src/app/api/super-admin/LiveVoteController.ts @@ -0,0 +1,95 @@ +import authHandler from "@App/middlewares/AuthHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; +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, roleHandler]) + 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(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(voteEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, vote); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/OfficeFoldersController.ts b/src/app/api/super-admin/OfficeFoldersController.ts index 989ea9b5..e0b01345 100644 --- a/src/app/api/super-admin/OfficeFoldersController.ts +++ b/src/app/api/super-admin/OfficeFoldersController.ts @@ -3,9 +3,13 @@ import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; import { Service } from "typedi"; -import { OfficeFolders } from "@prisma/client"; +import { OfficeFolders, Prisma } from "@prisma/client"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import folderHandler from "@App/middlewares/OfficeMembershipHandlers/FolderHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() @@ -17,21 +21,58 @@ export default class OfficeFoldersController extends ApiController { /** * @description Get all folders */ - @Get("/api/v1/super-admin/folders") + @Get("/api/v1/super-admin/folders", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query: Prisma.OfficeFoldersFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + OR: [ + { + name: { contains: filter, mode: "insensitive" }, + }, + { + folder_number: { contains: filter, mode: "insensitive" }, + }, + { + customers: { + some: { + contact: { + OR: [ + { first_name: { contains: filter, mode: "insensitive" } }, + { last_name: { contains: filter, mode: "insensitive" } }, + ], + }, + }, + }, + }, + ], + }, + }; + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId }; + if (!query.where) query.where = { office: officeWhereInput }; + query.where.office = officeWhereInput; + //call service to get prisma entity - const prismaEntity: OfficeFolders[] = await this.officeFoldersService.get(query); + const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); + //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.map(OfficeFolder, prismaEntity, { + const officeFolders = OfficeFolder.hydrateArray(officeFolderEntities, { strategy: "excludeAll", }); //success this.httpSuccess(response, officeFolders); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -39,24 +80,23 @@ export default class OfficeFoldersController extends ApiController { /** * @description Create a new folder */ - @Post("/api/v1/super-admin/folders") + @Post("/api/v1/super-admin/folders", [authHandler, roleHandler, ruleHandler, folderHandler]) protected async post(req: Request, response: Response) { try { //init OfficeFolder resource with request body values - const officeFolderEntity = OfficeFolder.hydrate(req.body); + const officeFolderRessource = OfficeFolder.hydrate(req.body); + await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); - //validate folder - await validateOrReject(officeFolderEntity, { groups: ["createFolder"] , forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityCreated = await this.officeFoldersService.create(officeFolderEntity); + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); //Hydrate ressource with prisma entity - const officeFolderEntityCreated = OfficeFolder.hydrate(prismaEntityCreated, { + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll", }); //success - this.httpSuccess(response, officeFolderEntityCreated); + this.httpCreated(response, officeFolders); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -64,13 +104,22 @@ export default class OfficeFoldersController extends ApiController { /** * @description Modify a specific folder by uid */ - @Put("/api/v1/super-admin/folders/:uid") + @Put("/api/v1/super-admin/folders/:uid", [authHandler, roleHandler, ruleHandler, folderHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } + + const officeFolderFound = await this.officeFoldersService.getByUid(uid); + + if (!officeFolderFound) { + this.httpNotFoundRequest(response, "office folder not found"); + return; + } + //init OfficeFolder resource with request body values const officeFolderEntity = OfficeFolder.hydrate(req.body); @@ -78,17 +127,17 @@ export default class OfficeFoldersController extends ApiController { await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); //Hydrate ressource with prisma entity - const officeFolderEntityUpdated = OfficeFolder.hydrate(prismaEntityUpdated, { + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, officeFolderEntityUpdated); + this.httpSuccess(response, officeFolders); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -97,22 +146,25 @@ export default class OfficeFoldersController extends ApiController { * @description Get a specific folder by uid * @returns IFolder */ - @Get("/api/v1/super-admin/folders/:uid") + @Get("/api/v1/super-admin/folders/:uid", [authHandler, roleHandler, ruleHandler, folderHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let officeFolderEntity: OfficeFolders; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); - } else { - //call service to get prisma entity - officeFolderEntity = await this.officeFoldersService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); + } + + const officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); + + if (!officeFolderEntity) { + this.httpNotFoundRequest(response, "folder not found"); + return; } //Hydrate ressource with prisma entity @@ -121,21 +173,28 @@ export default class OfficeFoldersController extends ApiController { //success this.httpSuccess(response, officeFolder); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } - this.httpSuccess(response, await this.officeFoldersService.getByUid("uid")); } /** * @description Delete a specific folder */ - @Delete("/api/v1/super-admin/folders/:uid") + @Delete("/api/v1/super-admin/folders/:uid", [authHandler, roleHandler, ruleHandler, folderHandler]) protected async delete(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeFolderFound = await this.officeFoldersService.getByUid(uid); + + if (!officeFolderFound) { + this.httpNotFoundRequest(response, "office folder not found"); + return; } //call service to get prisma entity @@ -147,7 +206,7 @@ export default class OfficeFoldersController extends ApiController { //success this.httpSuccess(response, officeFolder); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/OfficeRolesController.ts b/src/app/api/super-admin/OfficeRolesController.ts new file mode 100644 index 00000000..802c223e --- /dev/null +++ b/src/app/api/super-admin/OfficeRolesController.ts @@ -0,0 +1,166 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import OfficeRolesService from "@Services/super-admin/OfficeRolesService/OfficeRolesService"; +import { Service } from "typedi"; +import { validateOrReject } from "class-validator"; +import { OfficeRole } from "le-coffre-resources/dist/SuperAdmin"; +import { Prisma } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import officeRoleHandler from "@App/middlewares/OfficeMembershipHandlers/OfficeRoleHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class OfficeRolesController extends ApiController { + constructor(private officeRolesService: OfficeRolesService) { + super(); + } + + /** + * @description Get all officeRoles + */ + @Get("/api/v1/super-admin/office-roles", [authHandler, roleHandler, ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + let query: Prisma.OfficeRolesFindManyArgs = {}; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if(req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + name: { + contains: filter, + mode: "insensitive", + }, + }, + } + } + const officeId: string = req.body.user.office_Id; + const officeWhereInput: Prisma.OfficesWhereInput = { uid: officeId } ; + if(!query.where) query.where = { office: officeWhereInput}; + query.where.office = officeWhereInput; + + //call service to get prisma entity + const officeRolesEntities = await this.officeRolesService.get(query); + + //Hydrate ressource with prisma entity + const officeRoles = OfficeRole.hydrateArray(officeRolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeRoles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new officeRole + */ + @Post("/api/v1/super-admin/office-roles", [authHandler, roleHandler, ruleHandler, officeRoleHandler]) + protected async getAddresses(req: Request, response: Response) { + try { + //init IOfficeRole resource with request body values + const officeRoleEntity = OfficeRole.hydrate(req.body); + + //validate officeRole + await validateOrReject(officeRoleEntity, { groups: ["createOfficeRole"] }); + + //call service to get prisma entity + const officeRoleEntityCreated = await this.officeRolesService.create(officeRoleEntity); + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific officeRole by uid + */ + @Put("/api/v1/super-admin/office-roles/:uid", [authHandler, roleHandler, ruleHandler, officeRoleHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeRoleFound = await this.officeRolesService.getByUid(uid); + + if (!officeRoleFound) { + this.httpNotFoundRequest(response, "officeRole not found"); + return; + } + + //init IOfficeRole resource with request body values + const officeRoleEntity = OfficeRole.hydrate(req.body); + + //validate officeRole + await validateOrReject(officeRoleEntity, { groups: ["updateOfficeRole"] }); + + //call service to get prisma entity + const officeRoleEntityUpdated = await this.officeRolesService.update(officeRoleEntity); + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific officeRole by uid + */ + @Get("/api/v1/super-admin/office-roles/:uid", [authHandler, roleHandler, ruleHandler, officeRoleHandler]) + 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 officeRoleEntity = await this.officeRolesService.getByUid(uid, query); + + if (!officeRoleEntity) { + this.httpNotFoundRequest(response, "officeRole not found"); + return; + } + + //Hydrate ressource with prisma entity + const officeRole = OfficeRole.hydrate(officeRoleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, officeRole); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/OfficesController.ts b/src/app/api/super-admin/OfficesController.ts index 8520fe49..f4edab79 100644 --- a/src/app/api/super-admin/OfficesController.ts +++ b/src/app/api/super-admin/OfficesController.ts @@ -6,6 +6,9 @@ import { Service } from "typedi"; import { Offices } from "@prisma/client"; import { Office as OfficeResource } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import authHandler from "@App/middlewares/AuthHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; @Controller() @Service() @@ -16,26 +19,42 @@ export default class OfficesController extends ApiController { /** * @description Get all offices */ - @Get("/api/v1/super-admin/offices") + @Get("/api/v1/super-admin/offices", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if(req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where : { + name: { + contains: filter, + mode: "insensitive", + } + } + } + } + //call service to get prisma entity - const officesEntity: Offices[] = await this.officesService.get(query); + const officesEntities: Offices[] = await this.officesService.get(query); //Hydrate ressource with prisma entity - const offices = OfficeResource.map(OfficeResource, officesEntity, { strategy: "excludeAll" }); + const offices = OfficeResource.hydrateArray(officesEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, offices); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } /** * @description Create a new office */ - @Post("/api/v1/super-admin/offices") + @Post("/api/v1/super-admin/offices", [authHandler, roleHandler, ruleHandler]) protected async post(req: Request, response: Response) { try { //init IUser resource with request body values @@ -43,70 +62,82 @@ export default class OfficesController extends ApiController { //validate user await validateOrReject(officeEntity, { groups: ["createOffice"], forbidUnknownValues: false }); //call service to get prisma entity - const prismaEntityCreated = await this.officesService.create(officeEntity); + const officeEntityCreated = await this.officesService.create(officeEntity); //Hydrate ressource with prisma entity - const officeEntityCreated = OfficeResource.hydrate(prismaEntityCreated, { + const office = OfficeResource.hydrate(officeEntityCreated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, officeEntityCreated); + this.httpCreated(response, office); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } /** * @description Modify a specific office by uid */ - @Put("/api/v1/super-admin/offices/:uid") + @Put("/api/v1/super-admin/offices/:uid", [authHandler, roleHandler, ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; + } + + const officeFound = await this.officesService.getByUid(uid); + + if (!officeFound) { + this.httpNotFoundRequest(response, "office not found"); + return; } //init IUser resource with request body values const officeEntity = OfficeResource.hydrate(req.body); - //validate user - await validateOrReject(officeEntity, { groups: ["update"] }); + //call service to get prisma entity - const prismaEntityUpdated = await this.officesService.update(uid, officeEntity); + const officeEntityUpdated = await this.officesService.update(uid, officeEntity); //Hydrate ressource with prisma entity - const officeEntityUpdated = OfficeResource.hydrate(prismaEntityUpdated, { + const office = OfficeResource.hydrate(officeEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, officeEntityUpdated); + this.httpSuccess(response, office); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } /** * @description Get a specific office by uid */ - @Get("/api/v1/super-admin/offices/:uid") + @Get("/api/v1/super-admin/offices/:uid", [authHandler, roleHandler, ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let officeEntity: Offices; - //get query + + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - officeEntity = await this.officesService.getByUid(uid, query); - } else { - //call service to get prisma entity - officeEntity = await this.officesService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); } + + const officeEntity = await this.officesService.getByUid(uid, query); + + if (!officeEntity) { + this.httpNotFoundRequest(response, "office not found"); + return; + } + //Hydrate ressource with prisma entity const office = OfficeResource.hydrate(officeEntity, { strategy: "excludeAll" }); //success this.httpSuccess(response, office); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/RolesController.ts b/src/app/api/super-admin/RolesController.ts new file mode 100644 index 00000000..372c02c5 --- /dev/null +++ b/src/app/api/super-admin/RolesController.ts @@ -0,0 +1,148 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RolesService from "@Services/super-admin/RolesService/RolesService"; +import { Service } from "typedi"; +import { validateOrReject } from "class-validator"; +import { Role } from "le-coffre-resources/dist/SuperAdmin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class RolesController extends ApiController { + constructor(private rolesService: RolesService) { + super(); + } + + /** + * @description Get all roles + */ + @Get("/api/v1/super-admin/roles", [authHandler, roleHandler, ruleHandler]) + 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 rolesEntities = await this.rolesService.get(query); + + //Hydrate ressource with prisma entity + const roles = Role.hydrateArray(rolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, roles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new role + */ + @Post("/api/v1/super-admin/roles", [authHandler, roleHandler, ruleHandler]) + protected async getAddresses(req: Request, response: Response) { + try { + //init IRole resource with request body values + const roleEntity = Role.hydrate(req.body); + + //validate role + await validateOrReject(roleEntity, { groups: ["createRole"] }); + + //call service to get prisma entity + const roleEntityCreated = await this.rolesService.create(roleEntity); + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific role by uid + */ + @Put("/api/v1/super-admin/roles/:uid", [authHandler, roleHandler, ruleHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const roleFound = await this.rolesService.getByUid(uid); + + if (!roleFound) { + this.httpNotFoundRequest(response, "role not found"); + return; + } + + //init IRole resource with request body values + const roleEntity = Role.hydrate(req.body); + + //validate role + await validateOrReject(roleEntity, { groups: ["updateRole"] }); + + //call service to get prisma entity + const roleEntityUpdated = await this.rolesService.update(roleEntity); + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific role by uid + */ + @Get("/api/v1/super-admin/roles/:uid", [authHandler, roleHandler, ruleHandler]) + 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 roleEntity = await this.rolesService.getByUid(uid, query); + + if (!roleEntity) { + this.httpNotFoundRequest(response, "role not found"); + return; + } + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/RulesController.ts b/src/app/api/super-admin/RulesController.ts new file mode 100644 index 00000000..6f2f21a4 --- /dev/null +++ b/src/app/api/super-admin/RulesController.ts @@ -0,0 +1,144 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RulesService from "@Services/super-admin/RulesService/RulesService"; +import { Service } from "typedi"; +import { validateOrReject } from "class-validator"; +import { Rule } from "le-coffre-resources/dist/SuperAdmin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class RulesController extends ApiController { + constructor(private rulesService: RulesService) { + super(); + } + + /** + * @description Get all rules + */ + @Get("/api/v1/super-admin/rules", [authHandler, roleHandler, ruleHandler]) + 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 rulesEntities = await this.rulesService.get(query); + + //Hydrate ressource with prisma entity + const rules = Rule.hydrateArray(rulesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rules); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new rule + */ + @Post("/api/v1/super-admin/rules", [authHandler, roleHandler, ruleHandler]) + protected async getAddresses(req: Request, response: Response) { + try { + //init IRule resource with request body values + const ruleEntity = Rule.hydrate(req.body); + + //validate rule + await validateOrReject(ruleEntity, { groups: ["createRule"] }); + + //call service to get prisma entity + const ruleEntityCreated = await this.rulesService.create(ruleEntity); + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific rule by uid + */ + @Put("/api/v1/super-admin/rules/:uid", [authHandler, roleHandler, ruleHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const ruleFound = await this.rulesService.getByUid(uid); + + if (!ruleFound) { + this.httpNotFoundRequest(response, "rule not found"); + return; + } + + //init IRule resource with request body values + const ruleEntity = Rule.hydrate(req.body); + + //call service to get prisma entity + const ruleEntityUpdated = await this.rulesService.update(ruleEntity); + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific rule by uid + */ + @Get("/api/v1/super-admin/rules/:uid", [authHandler, roleHandler, ruleHandler]) + 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 ruleEntity = await this.rulesService.getByUid(uid, query); + + if (!ruleEntity) { + this.httpNotFoundRequest(response, "rule not found"); + return; + } + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/UsersController.ts b/src/app/api/super-admin/UsersController.ts index aee392e8..fd135312 100644 --- a/src/app/api/super-admin/UsersController.ts +++ b/src/app/api/super-admin/UsersController.ts @@ -4,35 +4,56 @@ import ApiController from "@Common/system/controller-pattern/ApiController"; import UsersService from "@Services/super-admin/UsersService/UsersService"; import { Service } from "typedi"; import { validateOrReject } from "class-validator"; -import User from "le-coffre-resources/dist/Notary"; -import { Users } from "@prisma/client"; +import User from "le-coffre-resources/dist/SuperAdmin"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import roleHandler from "@App/middlewares/RolesHandler"; +import RolesService from "@Services/super-admin/RolesService/RolesService"; +import OfficeRolesService from "@Services/super-admin/OfficeRolesService/OfficeRolesService"; @Controller() @Service() export default class UsersController extends ApiController { - constructor(private usersService: UsersService) { + constructor(private usersService: UsersService, private roleService: RolesService, private officeRoleService: OfficeRolesService) { super(); } /** * @description Get all users */ - @Get("/api/v1/super-admin/users") + @Get("/api/v1/super-admin/users", [authHandler, roleHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query - const query = JSON.parse(req.query["q"] as string); + let query; + if (req.query["q"]) { + query = JSON.parse(req.query["q"] as string); + } + + if (req.query["search"] && typeof req.query["search"] === "string") { + const filter = req.query["search"]; + query = { + where: { + contact: { + OR: [ + { first_name: { contains: filter, mode: "insensitive" } }, + { last_name: { contains: filter, mode: "insensitive" } }, + ], + }, + }, + }; + } //call service to get prisma entity - const usersEntity = await this.usersService.get(query); + const usersEntities = await this.usersService.get(query); //Hydrate ressource with prisma entity - const users = User.map(User, usersEntity, { strategy: "excludeAll" }); + const users = User.hydrateArray(usersEntities, { strategy: "excludeAll" }); //success this.httpSuccess(response, users); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -40,8 +61,8 @@ export default class UsersController extends ApiController { /** * @description Create a new user */ - @Post("/api/v1/super-admin/users") - protected async getAddresses(req: Request, response: Response) { + @Post("/api/v1/super-admin/users", [authHandler, roleHandler, ruleHandler]) + protected async create(req: Request, response: Response) { try { //init IUser resource with request body values const userEntity = User.hydrate(req.body); @@ -50,17 +71,17 @@ export default class UsersController extends ApiController { await validateOrReject(userEntity, { groups: ["createUser"] }); //call service to get prisma entity - const prismaEntityCreated = await this.usersService.create(userEntity); + const userEntityCreated = await this.usersService.create(userEntity); //Hydrate ressource with prisma entity - const userEntityCreated = User.hydrate(prismaEntityCreated, { + const user = User.hydrate(userEntityCreated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, userEntityCreated); + this.httpCreated(response, user); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -68,31 +89,62 @@ export default class UsersController extends ApiController { /** * @description Modify a specific user by uid */ - @Put("/api/v1/super-admin/users/:uid") + @Put("/api/v1/super-admin/users/:uid", [authHandler, roleHandler, ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; + if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } + + const userFound = await this.usersService.getByUidWithRole(uid); + + if (!userFound) { + this.httpNotFoundRequest(response, "user not found"); + return; + } + //init IUser resource with request body values const userEntity = User.hydrate(req.body); - //validate user - await validateOrReject(userEntity, { groups: ["update"] }); + if(userEntity.role) { + const role = await this.roleService.getByUid(userEntity.role.uid!); + if(!role) { + this.httpBadRequest(response, "Role not found"); + return; + } + if (role.name === "super-admin" || userFound.role.name === "super-admin" ) { + this.httpBadRequest(response, "Cannot assign or remove super-admin role"); + return; + } + } + if(userEntity.office_role) { + const officeRole = await this.officeRoleService.getByUid(userEntity.office_role.uid!); + if(!officeRole) { + this.httpBadRequest(response, "Office role not found"); + return; + } + if (officeRole.office_uid != userFound.office_uid) { + this.httpBadRequest(response, "Cannot assign an office role from another office"); + return; + } + } + //call service to get prisma entity - const prismaEntityUpdated = await this.usersService.update(uid, userEntity); + const userEntityUpdated = await this.usersService.update(uid, userEntity); //Hydrate ressource with prisma entity - const userEntityUpdated = User.hydrate(prismaEntityUpdated, { + const user = User.hydrate(userEntityUpdated, { strategy: "excludeAll", }); //success - this.httpSuccess(response, userEntityUpdated); + this.httpSuccess(response, user); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } @@ -100,21 +152,23 @@ export default class UsersController extends ApiController { /** * @description Get a specific user by uid */ - @Get("/api/v1/super-admin/users/:uid") + @Get("/api/v1/super-admin/users/:uid", [authHandler, roleHandler, ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } - let userEntity: Users; - //get query + let query; if (req.query["q"]) { - const query = JSON.parse(req.query["q"] as string); - userEntity = await this.usersService.getByUid(uid, query); - } else { - //call service to get prisma entity - userEntity = await this.usersService.getByUid(uid); + query = JSON.parse(req.query["q"] as string); + } + const userEntity = await this.usersService.getByUid(uid, query); + + if (!userEntity) { + this.httpNotFoundRequest(response, "user not found"); + return; } //Hydrate ressource with prisma entity @@ -123,7 +177,7 @@ export default class UsersController extends ApiController { //success this.httpSuccess(response, user); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response, error); return; } } diff --git a/src/app/api/super-admin/VotesController.ts b/src/app/api/super-admin/VotesController.ts new file mode 100644 index 00000000..308e46e3 --- /dev/null +++ b/src/app/api/super-admin/VotesController.ts @@ -0,0 +1,116 @@ +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"; +import roleHandler from "@App/middlewares/RolesHandler"; + +@Controller() +@Service() +export default class VotesController extends ApiController { + constructor(private votesService: VotesService) { + super(); + } + + /** + * @description Get all votes + */ + @Get("/api/v1/super-admin/votes", [authHandler, roleHandler]) + 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(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, roleHandler]) + 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(voteEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, vote); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Delete a specific vote + */ + @Delete("/api/v1/super-admin/votes/:uid", [authHandler, roleHandler]) + 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; + } + + if (voteFound.voter_uid !== req.body.user.userId) { + this.httpUnauthorized(response, "Can't delete a vote that's not yours"); + return; + } + + //call service to get prisma entity + const votetEntity: Votes = await this.votesService.delete(uid); + + //Hydrate ressource with prisma entity + const vote = Vote.hydrate(votetEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, vote); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/index.ts b/src/app/index.ts index e2b0a51f..dc98b2e4 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -1,16 +1,50 @@ import { Container } from "typedi"; import HomeController from "./HomeController"; -import UsersController from "./api/super-admin/UsersController"; -import FoldersController from "./api/super-admin/OfficeFoldersController"; -import CustomersController from "./api/super-admin/CustomersController"; -import OfficesController from "./api/super-admin/OfficesController"; -import DeedsController from "./api/super-admin/DeedsController"; -import DeedTypesController from "./api/super-admin/DeedTypesController"; -import DocumentsController from "./api/super-admin/DocumentsController"; -import DocumentTypesController from "./api/super-admin/DocumentTypesController"; -import IdNotUserInfoController from "./api/idnot-user/UserInfoController"; +import UsersControllerSuperAdmin from "./api/super-admin/UsersController"; +import FoldersControllerSuperAdmin from "./api/super-admin/OfficeFoldersController"; +import CustomersControllerSuperAdmin from "./api/super-admin/CustomersController"; +import OfficesControllerSuperAdmin from "./api/super-admin/OfficesController"; +import DeedsControllerSuperAdmin from "./api/super-admin/DeedsController"; +import DeedTypesControllerSuperAdmin from "./api/super-admin/DeedTypesController"; +import DocumentsControllerSuperAdmin from "./api/super-admin/DocumentsController"; +import DocumentTypesControllerSuperAdmin from "./api/super-admin/DocumentTypesController"; +import IdNotUserController from "./api/idnot/UserController"; +import FranceConnectCustomerController from "./api/franceConnect/CustomerController"; +import FilesControllerSuperAdmin from "./api/super-admin/FilesController"; +import RulesControllerSuperAdmin from "./api/super-admin/RulesController"; +import RolesControllerSuperAdmin from "./api/super-admin/RolesController"; +import OfficeRolesControllerSuperAdmin from "./api/super-admin/OfficeRolesController"; +import UsersControllerAdmin from "./api/admin/UsersController"; +import FoldersControllerAdmin from "./api/admin/OfficeFoldersController"; +import CustomersControllerAdmin from "./api/admin/CustomersController"; +import OfficesControllerAdmin from "./api/admin/OfficesController"; +import DeedsControllerAdmin from "./api/admin/DeedsController"; +import DeedTypesControllerAdmin from "./api/admin/DeedTypesController"; +import DocumentsControllerAdmin from "./api/admin/DocumentsController"; +import DocumentTypesControllerAdmin from "./api/admin/DocumentTypesController"; +import FilesControllerAdmin from "./api/admin/FilesController"; +import RulesControllerAdmin from "./api/admin/RulesController"; +import RolesControllerAdmin from "./api/admin/RolesController"; +import OfficeRolesControllerAdmin from "./api/admin/OfficeRolesController"; +import UsersControllerNotary from "./api/notary/UsersController"; +import FoldersControllerNotary from "./api/notary/OfficeFoldersController"; +import CustomersControllerNotary from "./api/notary/CustomersController"; +import OfficesControllerNotary from "./api/notary/OfficesController"; +import DeedsControllerNotary from "./api/notary/DeedsController"; +import DeedTypesControllerNotary from "./api/notary/DeedTypesController"; +import DocumentsControllerNotary from "./api/notary/DocumentsController"; +import DocumentTypesControllerNotary from "./api/notary/DocumentTypesController"; +import FilesControllerNotary from "./api/notary/FilesController"; +import RulesControllerNotary from "./api/notary/RulesController"; +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 FilesController from "./api/super-admin/FilesController"; +import OfficeFoldersController from "./api/customer/OfficeFoldersController"; +import CustomersController from "./api/customer/CustomersController"; +import AppointmentsController from "./api/super-admin/AppointmentsController"; +import VotesController from "./api/super-admin/VotesController"; +import LiveVoteController from "./api/super-admin/LiveVoteController"; /** @@ -19,16 +53,51 @@ import FilesController from "./api/super-admin/FilesController"; export default { start: () => { Container.get(HomeController); - Container.get(UsersController); - Container.get(FoldersController); - Container.get(CustomersController); - Container.get(OfficesController); - Container.get(DeedsController); - Container.get(DeedTypesController); - Container.get(DocumentsController); - Container.get(DocumentTypesController); - Container.get(IdNotUserInfoController); - Container.get(FilesController); + Container.get(UsersControllerSuperAdmin); + Container.get(FoldersControllerSuperAdmin); + Container.get(CustomersControllerSuperAdmin); + Container.get(OfficesControllerSuperAdmin); + Container.get(DeedsControllerSuperAdmin); + 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); + Container.get(DocumentsControllerSuperAdmin); + Container.get(RulesControllerSuperAdmin); + Container.get(RolesControllerSuperAdmin); + Container.get(OfficeRolesControllerSuperAdmin); + Container.get(UsersControllerAdmin); + Container.get(FoldersControllerAdmin); + Container.get(CustomersControllerAdmin); + Container.get(OfficesControllerAdmin); + Container.get(DeedsControllerAdmin); + Container.get(DeedTypesControllerAdmin); + Container.get(DocumentsControllerAdmin); + Container.get(DocumentTypesControllerAdmin); + Container.get(FilesControllerAdmin); + Container.get(RulesControllerAdmin); + Container.get(RolesControllerAdmin); + Container.get(OfficeRolesControllerAdmin); + Container.get(UsersControllerNotary); + Container.get(FoldersControllerNotary); + Container.get(CustomersControllerNotary); + Container.get(OfficesControllerNotary); + Container.get(DeedsControllerNotary); + Container.get(DeedTypesControllerNotary); + Container.get(DocumentsControllerNotary); + Container.get(DocumentTypesControllerNotary); + Container.get(FilesControllerNotary); + Container.get(RulesControllerNotary); + Container.get(RolesControllerNotary); + Container.get(OfficeRolesControllerNotary); + Container.get(FilesControllerCustomer); Container.get(DocumentsControllerCustomer); + Container.get(OfficeFoldersController); + Container.get(CustomersController) }, }; diff --git a/src/app/middlewares/AuthHandler.ts b/src/app/middlewares/AuthHandler.ts new file mode 100644 index 00000000..bd3f1293 --- /dev/null +++ b/src/app/middlewares/AuthHandler.ts @@ -0,0 +1,31 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import AuthService from "@Services/common/AuthService/AuthService"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; + +export default function authHandler(req: Request, response: Response, next: NextFunction) { + try { + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + if (!token) { + response.status(HttpCodes.UNAUTHORIZED).send("Missing token in authorization header"); + return; + } + + const authService = Container.get(AuthService); + authService.verifyAccessToken(token, (err, userPayload) => { + if (err) { + response.status(HttpCodes.UNAUTHORIZED).send("Error while verifying token"); + return; + } + req.body.user = userPayload; + next(); + }); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/CustomerHandler/DocumentHandler.ts b/src/app/middlewares/CustomerHandler/DocumentHandler.ts new file mode 100644 index 00000000..f263f7dd --- /dev/null +++ b/src/app/middlewares/CustomerHandler/DocumentHandler.ts @@ -0,0 +1,31 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import DocumentsService from "@Services/customer/DocumentsService/DocumentsService"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; + +export default async function documentHandler(req: Request, response: Response, next: NextFunction) { + try { + const customerId = req.body.user.customerId; + const uid = req.path && req.path.split("/")[5]; + + if (!uid) { + response.status(HttpCodes.BAD_REQUEST).send("Missing document uid"); + return; + } + + const documentService = Container.get(DocumentsService); + const document = await documentService.getByUid(uid); + + if (document?.depositor_uid != customerId) { + response.status(HttpCodes.UNAUTHORIZED).send("Not authorized with this depositor"); + return; + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/CustomerHandler/FileHandler.ts b/src/app/middlewares/CustomerHandler/FileHandler.ts new file mode 100644 index 00000000..0c9d82a1 --- /dev/null +++ b/src/app/middlewares/CustomerHandler/FileHandler.ts @@ -0,0 +1,39 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import FilesService from "@Services/common/FilesService/FilesService"; +import DocumentsService from "@Services/customer/DocumentsService/DocumentsService"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; + +export default async function fileHandler(req: Request, response: Response, next: NextFunction) { + const customerId = req.body.user.customerId; + const uid = req.path && req.path.split("/")[5]; + const document = req.body.document; + + if (uid) { + const fileService = Container.get(FilesService); + const file = await fileService.getByUidWithDocument(uid); + if (!file) { + response.status(HttpCodes.NOT_FOUND).send("File not found"); + return; + } + if (file.document.depositor_uid != customerId) { + response.status(HttpCodes.UNAUTHORIZED).send("Not authorized with this depositor"); + return; + } + } + + if (document) { + const documentService = Container.get(DocumentsService); + const documentFound = await documentService.getByUid(document.uid!); + if(!documentFound) { + response.status(HttpCodes.NOT_FOUND).send("Document not found"); + return; + } + if (documentFound.depositor_uid != customerId) { + response.status(HttpCodes.UNAUTHORIZED).send("Not authorized with this depositor"); + return; + } + } + + next(); +} diff --git a/src/app/middlewares/FileHandler.ts b/src/app/middlewares/FileHandler.ts deleted file mode 100644 index 3a6138ac..00000000 --- a/src/app/middlewares/FileHandler.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NextFunction, Request, Response } from "express"; -import multer from "multer"; - -export default function fileHandler(req: Request, response: Response, next: NextFunction) { - const storage = multer.memoryStorage() - const upload = multer({storage:storage}).single('file'); - - // Here call the upload middleware of multer - upload(req, response, function (err) { - if (err instanceof multer.MulterError) { - // A Multer error occurred when uploading. - const err = new Error('Multer error'); - return next(err) - } else if (err) { - // An unknown error occurred when uploading. - const err = new Error('Server Error') - return next(err) - } - next() - }) -} - diff --git a/src/app/middlewares/OfficeMembershipHandlers/DeedHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DeedHandler.ts new file mode 100644 index 00000000..f4986dc7 --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/DeedHandler.ts @@ -0,0 +1,51 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import DeedsService from "@Services/super-admin/DeedsService/DeedsService"; +import { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import DocumentTypesService from "@Services/super-admin/DocumentTypesService/DocumentTypesService"; + +export default async function deedHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const documentTypes: DocumentType[] = req.body.document_types; + + if (uid) { + const deedService = Container.get(DeedsService); + const deed = await deedService.getByUidWithOffice(uid); + + if (!deed) { + response.status(HttpCodes.NOT_FOUND).send("Deed not found"); + return; + } + + if (deed.deed_type.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + if (documentTypes) { + const documentTypeService = Container.get(DocumentTypesService); + documentTypes.forEach(async (documentType) => { + const deedTypeWithOffice = await documentTypeService.getByUidWithOffice(documentType.uid!); + if (!deedTypeWithOffice) { + response.status(HttpCodes.NOT_FOUND).send("Deed type not found"); + return; + } + if (deedTypeWithOffice.office?.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + }); + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts new file mode 100644 index 00000000..f8b8e104 --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts @@ -0,0 +1,56 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesService"; +import { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import DocumentTypesService from "@Services/super-admin/DocumentTypesService/DocumentTypesService"; + +export default async function deedTypeHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const documentTypes: DocumentType[] = req.body.document_types; + const office = req.body.office; + + if (office && office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + + if (uid) { + const deedTypeService = Container.get(DeedTypesService); + const deedType = await deedTypeService.getByUidWithOffice(uid!); + + if (!deedType) { + response.status(HttpCodes.NOT_FOUND).send("Deed type not found"); + return; + } + + if (deedType.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + if (documentTypes) { + const documentTypeService = Container.get(DocumentTypesService); + documentTypes.forEach(async (documentType) => { + const documentTypeWithOffice = await documentTypeService.getByUidWithOffice(documentType.uid!); + if (!documentTypeWithOffice) { + response.status(HttpCodes.NOT_FOUND).send("Document type not found"); + return; + } + if (documentTypeWithOffice.office?.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + }); + } + + next(); + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts new file mode 100644 index 00000000..9d684de0 --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts @@ -0,0 +1,65 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; +import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; +import DocumentTypesService from "@Services/super-admin/DocumentTypesService/DocumentTypesService"; +import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; + +export default async function documentHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const documentType: DocumentType = req.body.document_type; + const folder: OfficeFolder = req.body.folder; + + if (folder) { + const officeFolderService = Container.get(OfficeFoldersService); + const officeFolderWithOffice = await officeFolderService.getByUidWithOffice(folder.uid!); + if (!officeFolderWithOffice) { + response.status(HttpCodes.NOT_FOUND).send("Folder not found"); + return; + } + if (officeFolderWithOffice.office?.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + if (documentType) { + const documentTypeService = Container.get(DocumentTypesService); + const documentTypeWithOffice = await documentTypeService.getByUidWithOffice(documentType.uid!); + if (!documentTypeWithOffice) { + response.status(HttpCodes.NOT_FOUND).send("Document type not found"); + return; + } + if (documentTypeWithOffice.office?.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + if (uid) { + const documentService = Container.get(DocumentsService); + const document = await documentService.getByUidWithOffice(uid!); + + if (!document) { + response.sendStatus(HttpCodes.NOT_FOUND); + return; + } + + if (document.document_type.office.uid != officeId) { + response.sendStatus(HttpCodes.UNAUTHORIZED); + return; + } + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts new file mode 100644 index 00000000..9c8c8071 --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts @@ -0,0 +1,39 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import DocumentTypesService from "@Services/super-admin/DocumentTypesService/DocumentTypesService"; + +export default async function documentTypeHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const office = req.body.office; + + if (office && office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + + if (uid) { + const documentTypeService = Container.get(DocumentTypesService); + const documentType = await documentTypeService.getByUidWithOffice(uid!); + + if (!documentType) { + response.status(HttpCodes.NOT_FOUND).send("Document type not found"); + return; + } + + if (documentType.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/FileHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/FileHandler.ts new file mode 100644 index 00000000..64556871 --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/FileHandler.ts @@ -0,0 +1,48 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import FilesService from "@Services/common/FilesService/FilesService"; +import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; + +export default async function fileHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + let uid = req.path && req.path.split("/")[5]; + const document = req.body.document; + + if (document) { + const documentService = Container.get(DocumentsService); + const documentWithOffice = await documentService.getByUidWithOffice(document.uid!); + if (!documentWithOffice) { + response.status(HttpCodes.NOT_FOUND).send("Document not found"); + return; + } + if (documentWithOffice.folder.office?.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + if (uid === "download") uid = req.path && req.path.split("/")[6]; + + if (uid) { + const fileService = Container.get(FilesService); + const file = await fileService.getByUidWithOffice(uid!); + + if (!file) { + response.status(HttpCodes.NOT_FOUND).send("File not found"); + return; + } + if (file.document.folder.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + next(); + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts new file mode 100644 index 00000000..5993fa7b --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts @@ -0,0 +1,66 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; +import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesService"; + +export default async function folderHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const office = req.body.office; + const officeFolderNumber = req.body.folder_number; + const deed = req.body.deed; + + if (office && office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + + if (deed && deed.deed_type) { + const deedTypeService = Container.get(DeedTypesService); + const deedTypeWithOffice = await deedTypeService.getByUidWithOffice(deed.deed_type.uid!); + if (!deedTypeWithOffice) { + response.status(HttpCodes.NOT_FOUND).send("Deed type not found"); + return; + } + if (deedTypeWithOffice.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this deed type"); + return; + } + } + + const officeFolderService = Container.get(OfficeFoldersService); + + if (officeFolderNumber && req.method == "POST") { + const officeFoldersWithSameNumber = await officeFolderService.get({ + where: { folder_number: officeFolderNumber, office: { uid: officeId } }, + }); + if (officeFoldersWithSameNumber.length) { + response.status(HttpCodes.BAD_REQUEST).send("Office number already used"); + return; + } + } + + if (uid) { + const officeFolder = await officeFolderService.getByUidWithOffice(uid!); + + if (!officeFolder) { + response.status(HttpCodes.NOT_FOUND).send("Office folder not found"); + return; + } + + if (officeFolder.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/OfficeRoleHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/OfficeRoleHandler.ts new file mode 100644 index 00000000..c0e9f53f --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/OfficeRoleHandler.ts @@ -0,0 +1,39 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import OfficeRolesService from "@Services/super-admin/OfficeRolesService/OfficeRolesService"; + +export default async function officeRoleHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const office = req.body.office; + + if (office && office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + + if (uid) { + const officeRoleService = Container.get(OfficeRolesService); + const officeRole = await officeRoleService.getByUidWithOffice(uid!); + + if (!officeRole) { + response.status(HttpCodes.NOT_FOUND).send("Office role not found"); + return; + } + + if (officeRole.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/UserHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/UserHandler.ts new file mode 100644 index 00000000..ea05b60d --- /dev/null +++ b/src/app/middlewares/OfficeMembershipHandlers/UserHandler.ts @@ -0,0 +1,38 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; +import UsersService from "@Services/super-admin/UsersService/UsersService"; + +export default async function userHandler(req: Request, response: Response, next: NextFunction) { + try { + const officeId = req.body.user.office_Id; + const uid = req.path && req.path.split("/")[5]; + const office = req.body.office_membership; + + if (office && office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + + if (uid) { + const userService = Container.get(UsersService); + const user = await userService.getByUidWithOffice(uid!); + + if (!user) { + response.status(HttpCodes.NOT_FOUND).send("User not found"); + return; + } + + if (user.office_membership.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); + return; + } + } + + next(); + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/RolesHandler.ts b/src/app/middlewares/RolesHandler.ts new file mode 100644 index 00000000..3a4a9c77 --- /dev/null +++ b/src/app/middlewares/RolesHandler.ts @@ -0,0 +1,22 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; + +export default async function roleHandler(req: Request, response: Response, next: NextFunction) { + try { + + const namespace = req.path && req.path.split("/")[3]; + const role = req.body.user.role; + + if (namespace != "notary" && role != namespace && role != "super-admin") { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this role"); + return; + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/app/middlewares/RulesHandler.ts b/src/app/middlewares/RulesHandler.ts new file mode 100644 index 00000000..cd35dcfe --- /dev/null +++ b/src/app/middlewares/RulesHandler.ts @@ -0,0 +1,21 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; + +export default async function ruleHandler(req: Request, response: Response, next: NextFunction) { + try { + const rules = req.body.user.rules; + const service = req.path && req.path.split("/")[4]; + + if (!rules.includes(req.method + " " + service)) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with those rules"); + return; + } + + next(); + + } catch (error) { + console.log(error); + response.status(HttpCodes.INTERNAL_ERROR).send("Internal server error"); + return; + } +} diff --git a/src/common/config/variables/Variables.ts b/src/common/config/variables/Variables.ts index bc20851c..a7b3cf3d 100644 --- a/src/common/config/variables/Variables.ts +++ b/src/common/config/variables/Variables.ts @@ -19,6 +19,9 @@ export class BackendVariables { @IsNotEmpty() public readonly DATABASE_NAME!: string; + @IsNotEmpty() + public readonly DATABASE_URL!: string; + @IsNotEmpty() public readonly API_ROOT_URL!: string; @@ -31,8 +34,6 @@ export class BackendVariables { @IsNotEmpty() public readonly APP_ROOT_URL!: string; - public readonly NODE_ENV = process.env.NODE_ENV; - @IsNotEmpty() public readonly IDNOT_CONNEXION_URL!: string; @@ -54,13 +55,27 @@ export class BackendVariables { @IsNotEmpty() public readonly PINATA_GATEWAY!: string; + @IsNotEmpty() + public readonly ACCESS_TOKEN_SECRET!: string; + + @IsNotEmpty() + public readonly REFRESH_TOKEN_SECRET!: string; + + @IsNotEmpty() + public readonly MAILCHIMP_API_KEY!: string; + + @IsNotEmpty() + public readonly ENV!: string; + public constructor() { + dotenv.config(); this.DATABASE_PORT = process.env["DATABASE_PORT"]!; this.DATABASE_HOST = process.env["DATABASE_HOST"]!; this.DATABASE_USERNAME = process.env["DATABASE_USERNAME"]!; this.DATABASE_PASSWORD = process.env["DATABASE_PASSWORD"]!; this.DATABASE_NAME = process.env["DATABASE_NAME"]!; + this.DATABASE_URL = process.env["DEV_PRISMA_STUDIO_DB_URL"]!; this.API_ROOT_URL = process.env["API_ROOT_URL"]!; this.APP_PORT = process.env["APP_PORT"]!; this.APP_ROOT_URL = process.env["APP_ROOT_URL"]!; @@ -72,9 +87,23 @@ export class BackendVariables { this.PINATA_API_KEY = process.env["PINATA_API_KEY"]!; this.PINATA_API_SECRET = process.env["PINATA_API_SECRET"]!; this.PINATA_GATEWAY = process.env["PINATA_GATEWAY"]!; + this.ACCESS_TOKEN_SECRET = process.env["ACCESS_TOKEN_SECRET"]!; + this.REFRESH_TOKEN_SECRET = process.env["REFRESH_TOKEN_SECRET"]!; + this.MAILCHIMP_API_KEY = process.env["MAILCHIMP_API_KEY"]!; + this.ENV = process.env["ENV"]!; + } - public async validate() { - await validateOrReject(this); + public async validate(groups?: string[]) { + const validationOptions = groups ? { groups } : undefined; + + try { + await validateOrReject(this, validationOptions); + } catch (error: any) { + if (process.env["ENV"] === "dev") { + throw error; + } + throw new Error("Some env variables are required!"); + } return this; } } diff --git a/src/common/databases/migrations/20230505075245_v1/migration.sql b/src/common/databases/migrations/20230505075245_v1/migration.sql deleted file mode 100644 index c212eab0..00000000 --- a/src/common/databases/migrations/20230505075245_v1/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `iv` to the `files` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "files" ADD COLUMN "iv" VARCHAR(255) NOT NULL; diff --git a/src/common/databases/migrations/20230505131655_v2/migration.sql b/src/common/databases/migrations/20230505131655_v2/migration.sql deleted file mode 100644 index a7f5aaa6..00000000 --- a/src/common/databases/migrations/20230505131655_v2/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `file_name` to the `files` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "files" ADD COLUMN "file_name" VARCHAR(255) NOT NULL; diff --git a/src/common/databases/migrations/20230510204321_v4/migration.sql b/src/common/databases/migrations/20230510204321_v4/migration.sql deleted file mode 100644 index 463c9e19..00000000 --- a/src/common/databases/migrations/20230510204321_v4/migration.sql +++ /dev/null @@ -1,9 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `iv` on the `files` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "files" DROP COLUMN "iv", -ADD COLUMN "key" VARCHAR(255); diff --git a/src/common/databases/migrations/20230511085908_v5/migration.sql b/src/common/databases/migrations/20230511085908_v5/migration.sql deleted file mode 100644 index a5b3abcb..00000000 --- a/src/common/databases/migrations/20230511085908_v5/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "files" ADD COLUMN "archived_at" TIMESTAMP(3); diff --git a/src/common/databases/migrations/20230426144239_init/migration.sql b/src/common/databases/migrations/20230621092719_init/migration.sql similarity index 85% rename from src/common/databases/migrations/20230426144239_init/migration.sql rename to src/common/databases/migrations/20230621092719_init/migration.sql index d017a9c4..f8237a5c 100644 --- a/src/common/databases/migrations/20230426144239_init/migration.sql +++ b/src/common/databases/migrations/20230621092719_init/migration.sql @@ -35,9 +35,9 @@ CREATE TABLE "contacts" ( "last_name" VARCHAR(255) NOT NULL, "email" VARCHAR(255) NOT NULL, "phone_number" VARCHAR(50), - "cell_phone_number" VARCHAR(50), + "cell_phone_number" VARCHAR(50) NOT NULL, "civility" "ECivility" NOT NULL DEFAULT 'MALE', - "address_uid" VARCHAR(255) NOT NULL, + "address_uid" VARCHAR(255), "birthdate" TIMESTAMP(3), "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3), @@ -50,6 +50,7 @@ CREATE TABLE "users" ( "uid" TEXT NOT NULL, "idNot" VARCHAR(255) NOT NULL, "contact_uid" VARCHAR(255) NOT NULL, + "roles_uid" TEXT NOT NULL, "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3), "office_uid" VARCHAR(255) NOT NULL, @@ -174,6 +175,11 @@ CREATE TABLE "files" ( "uid" TEXT NOT NULL, "document_uid" VARCHAR(255) NOT NULL, "file_path" VARCHAR(255) NOT NULL, + "file_name" VARCHAR(255) NOT NULL, + "mimetype" VARCHAR(255) NOT NULL, + "size" INTEGER NOT NULL, + "archived_at" TIMESTAMP(3), + "key" VARCHAR(255), "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3), @@ -249,6 +255,50 @@ CREATE TABLE "deed_type_has_document_types" ( CONSTRAINT "deed_type_has_document_types_pkey" PRIMARY KEY ("uid") ); +-- CreateTable +CREATE TABLE "roles" ( + "uid" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "roles_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "rules" ( + "uid" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + "role_has_rules_uid" TEXT, + "office_role_has_rules_uid" TEXT, + + CONSTRAINT "rules_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "role_has_rules" ( + "uid" TEXT NOT NULL, + "role_uid" VARCHAR(255) NOT NULL, + "rule_uid" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "role_has_rules_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "office_role_has_rules" ( + "uid" TEXT NOT NULL, + "role_uid" VARCHAR(255) NOT NULL, + "rule_uid" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "office_role_has_rules_pkey" PRIMARY KEY ("uid") +); + -- CreateIndex CREATE UNIQUE INDEX "addresses_uid_key" ON "addresses"("uid"); @@ -366,12 +416,27 @@ CREATE UNIQUE INDEX "deed_type_has_document_types_uid_key" ON "deed_type_has_doc -- CreateIndex CREATE UNIQUE INDEX "deed_type_has_document_types_deed_type_uid_document_type_ui_key" ON "deed_type_has_document_types"("deed_type_uid", "document_type_uid"); +-- CreateIndex +CREATE UNIQUE INDEX "roles_uid_key" ON "roles"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "rules_uid_key" ON "rules"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "role_has_rules_uid_key" ON "role_has_rules"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "office_role_has_rules_uid_key" ON "office_role_has_rules"("uid"); + -- AddForeignKey ALTER TABLE "contacts" ADD CONSTRAINT "contacts_address_uid_fkey" FOREIGN KEY ("address_uid") REFERENCES "addresses"("uid") ON DELETE CASCADE ON UPDATE CASCADE; -- 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 RESTRICT 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; @@ -444,6 +509,14 @@ ALTER TABLE "deed_type_has_document_types" ADD CONSTRAINT "deed_type_has_documen -- AddForeignKey ALTER TABLE "deed_type_has_document_types" ADD CONSTRAINT "deed_type_has_document_types_deed_type_uid_fkey" FOREIGN KEY ("deed_type_uid") REFERENCES "deed_types"("uid") ON DELETE CASCADE ON UPDATE CASCADE; --- AlterTable -ALTER TABLE "contacts" ALTER COLUMN "cell_phone_number" SET NOT NULL, -ALTER COLUMN "address_uid" DROP NOT NULL; \ No newline at end of file +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_role_has_rules_uid_fkey" FOREIGN KEY ("role_has_rules_uid") REFERENCES "role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_office_role_has_rules_uid_fkey" FOREIGN KEY ("office_role_has_rules_uid") REFERENCES "office_role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "role_has_rules" ADD CONSTRAINT "role_has_rules_role_uid_fkey" FOREIGN KEY ("role_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "office_role_has_rules" ADD CONSTRAINT "office_role_has_rules_role_uid_fkey" FOREIGN KEY ("role_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230621100427_v1/migration.sql b/src/common/databases/migrations/20230621100427_v1/migration.sql new file mode 100644 index 00000000..be549452 --- /dev/null +++ b/src/common/databases/migrations/20230621100427_v1/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to alter the column `roles_uid` on the `users` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(255)`. + +*/ +-- DropForeignKey +ALTER TABLE "users" DROP CONSTRAINT "users_roles_uid_fkey"; + +-- AlterTable +ALTER TABLE "users" ALTER COLUMN "roles_uid" SET DATA TYPE VARCHAR(255); + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230622172124_v2/migration.sql b/src/common/databases/migrations/20230622172124_v2/migration.sql new file mode 100644 index 00000000..34d5f531 --- /dev/null +++ b/src/common/databases/migrations/20230622172124_v2/migration.sql @@ -0,0 +1,37 @@ +/* + Warnings: + + - You are about to drop the column `office_role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - You are about to drop the column `role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - Added the required column `office_uid` to the `office_role_has_rules` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_office_role_has_rules_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_role_has_rules_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "users" DROP CONSTRAINT "users_roles_uid_fkey"; + +-- AlterTable +ALTER TABLE "office_role_has_rules" ADD COLUMN "office_uid" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "rules" DROP COLUMN "office_role_has_rules_uid", +DROP COLUMN "role_has_rules_uid", +ADD COLUMN "officesRolesHasRulesUid" TEXT, +ADD COLUMN "rolesHasRulesUid" TEXT; + +-- 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 "rules" ADD CONSTRAINT "rules_rolesHasRulesUid_fkey" FOREIGN KEY ("rolesHasRulesUid") REFERENCES "role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_officesRolesHasRulesUid_fkey" FOREIGN KEY ("officesRolesHasRulesUid") REFERENCES "office_role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "office_role_has_rules" ADD CONSTRAINT "office_role_has_rules_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230622172838_v3/migration.sql b/src/common/databases/migrations/20230622172838_v3/migration.sql new file mode 100644 index 00000000..b218d50d --- /dev/null +++ b/src/common/databases/migrations/20230622172838_v3/migration.sql @@ -0,0 +1,24 @@ +/* + Warnings: + + - You are about to drop the column `officesRolesHasRulesUid` on the `rules` table. All the data in the column will be lost. + - You are about to drop the column `rolesHasRulesUid` on the `rules` table. All the data in the column will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_officesRolesHasRulesUid_fkey"; + +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_rolesHasRulesUid_fkey"; + +-- AlterTable +ALTER TABLE "rules" DROP COLUMN "officesRolesHasRulesUid", +DROP COLUMN "rolesHasRulesUid", +ADD COLUMN "office_role_has_rules_uid" TEXT, +ADD COLUMN "role_has_rules_uid" TEXT; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_role_has_rules_uid_fkey" FOREIGN KEY ("role_has_rules_uid") REFERENCES "role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_office_role_has_rules_uid_fkey" FOREIGN KEY ("office_role_has_rules_uid") REFERENCES "office_role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230623070044_v4/migration.sql b/src/common/databases/migrations/20230623070044_v4/migration.sql new file mode 100644 index 00000000..865da2cf --- /dev/null +++ b/src/common/databases/migrations/20230623070044_v4/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - You are about to drop the column `rule_uid` on the `office_role_has_rules` table. All the data in the column will be lost. + - You are about to drop the column `rule_uid` on the `role_has_rules` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "office_role_has_rules" DROP COLUMN "rule_uid"; + +-- AlterTable +ALTER TABLE "role_has_rules" DROP COLUMN "rule_uid"; diff --git a/src/common/databases/migrations/20230623072820_v5/migration.sql b/src/common/databases/migrations/20230623072820_v5/migration.sql new file mode 100644 index 00000000..417d4724 --- /dev/null +++ b/src/common/databases/migrations/20230623072820_v5/migration.sql @@ -0,0 +1,30 @@ +/* + Warnings: + + - You are about to drop the column `office_role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - You are about to drop the column `role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - Added the required column `rule_uid` to the `office_role_has_rules` table without a default value. This is not possible if the table is not empty. + - Added the required column `rule_uid` to the `role_has_rules` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_office_role_has_rules_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_role_has_rules_uid_fkey"; + +-- AlterTable +ALTER TABLE "office_role_has_rules" ADD COLUMN "rule_uid" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "role_has_rules" ADD COLUMN "rule_uid" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "rules" DROP COLUMN "office_role_has_rules_uid", +DROP COLUMN "role_has_rules_uid"; + +-- AddForeignKey +ALTER TABLE "role_has_rules" ADD CONSTRAINT "role_has_rules_rule_uid_fkey" FOREIGN KEY ("rule_uid") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "office_role_has_rules" ADD CONSTRAINT "office_role_has_rules_rule_uid_fkey" FOREIGN KEY ("rule_uid") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230627155351_v6/migration.sql b/src/common/databases/migrations/20230627155351_v6/migration.sql new file mode 100644 index 00000000..42e2a343 --- /dev/null +++ b/src/common/databases/migrations/20230627155351_v6/migration.sql @@ -0,0 +1,86 @@ +/* + Warnings: + + - You are about to drop the `office_role_has_rules` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `role_has_rules` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "office_role_has_rules" DROP CONSTRAINT "office_role_has_rules_office_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "office_role_has_rules" DROP CONSTRAINT "office_role_has_rules_role_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "office_role_has_rules" DROP CONSTRAINT "office_role_has_rules_rule_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "role_has_rules" DROP CONSTRAINT "role_has_rules_role_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "role_has_rules" DROP CONSTRAINT "role_has_rules_rule_uid_fkey"; + +-- AlterTable +ALTER TABLE "users" ADD COLUMN "office_role_uid" VARCHAR(255); + +-- DropTable +DROP TABLE "office_role_has_rules"; + +-- DropTable +DROP TABLE "role_has_rules"; + +-- CreateTable +CREATE TABLE "office_roles" ( + "uid" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "office_uid" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "office_roles_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "_RolesHasRules" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "_OfficeRolesHasRules" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "office_roles_uid_key" ON "office_roles"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "_RolesHasRules_AB_unique" ON "_RolesHasRules"("A", "B"); + +-- CreateIndex +CREATE INDEX "_RolesHasRules_B_index" ON "_RolesHasRules"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_OfficeRolesHasRules_AB_unique" ON "_OfficeRolesHasRules"("A", "B"); + +-- CreateIndex +CREATE INDEX "_OfficeRolesHasRules_B_index" ON "_OfficeRolesHasRules"("B"); + +-- 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 "office_roles" ADD CONSTRAINT "office_roles_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_RolesHasRules" ADD CONSTRAINT "_RolesHasRules_A_fkey" FOREIGN KEY ("A") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_RolesHasRules" ADD CONSTRAINT "_RolesHasRules_B_fkey" FOREIGN KEY ("B") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_OfficeRolesHasRules" ADD CONSTRAINT "_OfficeRolesHasRules_A_fkey" FOREIGN KEY ("A") REFERENCES "office_roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_OfficeRolesHasRules" ADD CONSTRAINT "_OfficeRolesHasRules_B_fkey" FOREIGN KEY ("B") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230628100711_v7/migration.sql b/src/common/databases/migrations/20230628100711_v7/migration.sql new file mode 100644 index 00000000..4d8f4bf3 --- /dev/null +++ b/src/common/databases/migrations/20230628100711_v7/migration.sql @@ -0,0 +1,144 @@ +/* + Warnings: + + - You are about to drop the `deed_has_document_types` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `deed_type_has_document_types` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `office_folder_has_customers` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `office_folder_has_stakeholder` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `user_has_notifications` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "deed_has_document_types" DROP CONSTRAINT "deed_has_document_types_deed_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "deed_has_document_types" DROP CONSTRAINT "deed_has_document_types_document_type_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "deed_type_has_document_types" DROP CONSTRAINT "deed_type_has_document_types_deed_type_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "deed_type_has_document_types" DROP CONSTRAINT "deed_type_has_document_types_document_type_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "office_folder_has_customers" DROP CONSTRAINT "office_folder_has_customers_customer_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "office_folder_has_customers" DROP CONSTRAINT "office_folder_has_customers_office_folder_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "office_folder_has_stakeholder" DROP CONSTRAINT "office_folder_has_stakeholder_office_folder_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "office_folder_has_stakeholder" DROP CONSTRAINT "office_folder_has_stakeholder_user_stakeholder_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "user_has_notifications" DROP CONSTRAINT "user_has_notifications_notification_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "user_has_notifications" DROP CONSTRAINT "user_has_notifications_user_uid_fkey"; + +-- DropTable +DROP TABLE "deed_has_document_types"; + +-- DropTable +DROP TABLE "deed_type_has_document_types"; + +-- DropTable +DROP TABLE "office_folder_has_customers"; + +-- DropTable +DROP TABLE "office_folder_has_stakeholder"; + +-- DropTable +DROP TABLE "user_has_notifications"; + +-- CreateTable +CREATE TABLE "_OfficeFolderHasCustomers" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "_UserHasNotifications" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "_OfficeFolderHasStakeholders" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "_DeedHasDocumentTypes" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "_DeedTypeHasDocumentTypes" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "_OfficeFolderHasCustomers_AB_unique" ON "_OfficeFolderHasCustomers"("A", "B"); + +-- CreateIndex +CREATE INDEX "_OfficeFolderHasCustomers_B_index" ON "_OfficeFolderHasCustomers"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_UserHasNotifications_AB_unique" ON "_UserHasNotifications"("A", "B"); + +-- CreateIndex +CREATE INDEX "_UserHasNotifications_B_index" ON "_UserHasNotifications"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_OfficeFolderHasStakeholders_AB_unique" ON "_OfficeFolderHasStakeholders"("A", "B"); + +-- CreateIndex +CREATE INDEX "_OfficeFolderHasStakeholders_B_index" ON "_OfficeFolderHasStakeholders"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_DeedHasDocumentTypes_AB_unique" ON "_DeedHasDocumentTypes"("A", "B"); + +-- CreateIndex +CREATE INDEX "_DeedHasDocumentTypes_B_index" ON "_DeedHasDocumentTypes"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_DeedTypeHasDocumentTypes_AB_unique" ON "_DeedTypeHasDocumentTypes"("A", "B"); + +-- CreateIndex +CREATE INDEX "_DeedTypeHasDocumentTypes_B_index" ON "_DeedTypeHasDocumentTypes"("B"); + +-- AddForeignKey +ALTER TABLE "_OfficeFolderHasCustomers" ADD CONSTRAINT "_OfficeFolderHasCustomers_A_fkey" FOREIGN KEY ("A") REFERENCES "customers"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_OfficeFolderHasCustomers" ADD CONSTRAINT "_OfficeFolderHasCustomers_B_fkey" FOREIGN KEY ("B") REFERENCES "office_folders"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserHasNotifications" ADD CONSTRAINT "_UserHasNotifications_A_fkey" FOREIGN KEY ("A") REFERENCES "notifications"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserHasNotifications" ADD CONSTRAINT "_UserHasNotifications_B_fkey" FOREIGN KEY ("B") REFERENCES "users"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_OfficeFolderHasStakeholders" ADD CONSTRAINT "_OfficeFolderHasStakeholders_A_fkey" FOREIGN KEY ("A") REFERENCES "office_folders"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_OfficeFolderHasStakeholders" ADD CONSTRAINT "_OfficeFolderHasStakeholders_B_fkey" FOREIGN KEY ("B") REFERENCES "users"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DeedHasDocumentTypes" ADD CONSTRAINT "_DeedHasDocumentTypes_A_fkey" FOREIGN KEY ("A") REFERENCES "deed"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DeedHasDocumentTypes" ADD CONSTRAINT "_DeedHasDocumentTypes_B_fkey" FOREIGN KEY ("B") REFERENCES "document_types"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DeedTypeHasDocumentTypes" ADD CONSTRAINT "_DeedTypeHasDocumentTypes_A_fkey" FOREIGN KEY ("A") REFERENCES "deed_types"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DeedTypeHasDocumentTypes" ADD CONSTRAINT "_DeedTypeHasDocumentTypes_B_fkey" FOREIGN KEY ("B") REFERENCES "document_types"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230703120600_v9/migration.sql b/src/common/databases/migrations/20230703120600_v9/migration.sql new file mode 100644 index 00000000..720264aa --- /dev/null +++ b/src/common/databases/migrations/20230703120600_v9/migration.sql @@ -0,0 +1,23 @@ +-- 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"; + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_contact_uid_fkey" FOREIGN KEY ("contact_uid") REFERENCES "contacts"("uid") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE RESTRICT 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 SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230703122557_v10/migration.sql b/src/common/databases/migrations/20230703122557_v10/migration.sql new file mode 100644 index 00000000..8d7c8594 --- /dev/null +++ b/src/common/databases/migrations/20230703122557_v10/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - A unique constraint covering the columns `[idNot,uid]` on the table `users` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[contact_uid,uid]` on the table `users` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "users_idNot_key"; + +-- CreateIndex +CREATE UNIQUE INDEX "users_idNot_uid_key" ON "users"("idNot", "uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "users_contact_uid_uid_key" ON "users"("contact_uid", "uid"); diff --git a/src/common/databases/migrations/20230703123246_v11/migration.sql b/src/common/databases/migrations/20230703123246_v11/migration.sql new file mode 100644 index 00000000..842ec44e --- /dev/null +++ b/src/common/databases/migrations/20230703123246_v11/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - A unique constraint covering the columns `[idNot]` on the table `users` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "users_contact_uid_uid_key"; + +-- DropIndex +DROP INDEX "users_idNot_uid_key"; + +-- CreateIndex +CREATE UNIQUE INDEX "users_idNot_key" ON "users"("idNot"); diff --git a/src/common/databases/migrations/20230711134012_/migration.sql b/src/common/databases/migrations/20230711134012_/migration.sql new file mode 100644 index 00000000..205eb444 --- /dev/null +++ b/src/common/databases/migrations/20230711134012_/migration.sql @@ -0,0 +1,43 @@ +-- 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 "email" ( + "uid" TEXT NOT NULL, + "templateName" VARCHAR(255) NOT NULL, + "from" VARCHAR(255), + "to" VARCHAR(255) NOT NULL, + "subject" VARCHAR(255) NOT NULL, + "templateVariables" JSON NOT NULL DEFAULT '{}', + "cc" VARCHAR(255)[], + "cci" VARCHAR(255)[], + "sentAt" TIMESTAMP(3), + "nbTrySend" INTEGER DEFAULT 0, + "lastTrySendDate" TIMESTAMP(3), + + CONSTRAINT "email_pkey" PRIMARY KEY ("uid") +); + +-- CreateIndex +CREATE UNIQUE INDEX "email_uid_key" ON "email"("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; diff --git a/src/common/databases/migrations/20230713145026_v12/migration.sql b/src/common/databases/migrations/20230713145026_v12/migration.sql new file mode 100644 index 00000000..c5dac8d4 --- /dev/null +++ b/src/common/databases/migrations/20230713145026_v12/migration.sql @@ -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; diff --git a/src/common/databases/migrations/20230725084826_v12/migration.sql b/src/common/databases/migrations/20230725084826_v12/migration.sql new file mode 100644 index 00000000..0b7f1455 --- /dev/null +++ b/src/common/databases/migrations/20230725084826_v12/migration.sql @@ -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; diff --git a/src/common/databases/migrations/20230725151748_v13/migration.sql b/src/common/databases/migrations/20230725151748_v13/migration.sql new file mode 100644 index 00000000..b8c667d7 --- /dev/null +++ b/src/common/databases/migrations/20230725151748_v13/migration.sql @@ -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"; diff --git a/src/common/databases/migrations/20230726095252_v25/migration.sql b/src/common/databases/migrations/20230726095252_v25/migration.sql new file mode 100644 index 00000000..389c4749 --- /dev/null +++ b/src/common/databases/migrations/20230726095252_v25/migration.sql @@ -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"); diff --git a/src/common/databases/migrations/20230816144031_v22/migration.sql b/src/common/databases/migrations/20230816144031_v22/migration.sql new file mode 100644 index 00000000..59a287ba --- /dev/null +++ b/src/common/databases/migrations/20230816144031_v22/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - Added the required column `label` to the `roles` table without a default value. This is not possible if the table is not empty. + - Added the required column `label` to the `rules` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "roles" ADD COLUMN "label" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "rules" ADD COLUMN "label" VARCHAR(255) NOT NULL; diff --git a/src/common/databases/schema.prisma b/src/common/databases/schema.prisma index 742b331b..858709ed 100644 --- a/src/common/databases/schema.prisma +++ b/src/common/databases/schema.prisma @@ -8,6 +8,7 @@ generator client { datasource db { provider = "postgresql" url = env("DEV_PRISMA_STUDIO_DB_URL") + shadowDatabaseUrl = env("DEV_PRISMA_STUDIO_SHADOW_URL") } // Entités -> snake_case @@ -50,16 +51,22 @@ model Contacts { } model Users { - uid String @id @unique @default(uuid()) @map("uid") - idNot String @unique @db.VarChar(255) - contact Contacts @relation(fields: [contact_uid], references: [uid], onDelete: Cascade) - contact_uid String @unique @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - office_membership Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) - office_uid String @db.VarChar(255) - user_has_notifications UserHasNotifications[] - office_folder_has_stakeholder OfficeFolderHasStakeholders[] + uid String @id @unique @default(uuid()) @map("uid") + idNot String @unique @db.VarChar(255) + contact Contacts @relation(fields: [contact_uid], references: [uid], onDelete: Cascade) + contact_uid String @unique @db.VarChar(255) + role Roles @relation(fields: [roles_uid], references: [uid], onDelete: Cascade) + roles_uid String @db.VarChar(255) + office_role OfficeRoles? @relation(fields: [office_role_uid], references: [uid], onDelete: Cascade) + office_role_uid String? @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + office_membership Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) + office_uid String @db.VarChar(255) + notifications Notifications[] @relation("UserHasNotifications") + office_folders OfficeFolders[] @relation("OfficeFolderHasStakeholders") + appointment Appointments[] + votes Votes[] @@map("users") } @@ -78,95 +85,56 @@ model Offices { users Users[] office_folders OfficeFolders[] document_types DocumentTypes[] + office_roles OfficeRoles[] @@map("offices") } model Customers { - uid String @id @unique @default(uuid()) - status ECustomerStatus @default(PENDING) - contact Contacts @relation(fields: [contact_uid], references: [uid], onDelete: Cascade) - contact_uid String @unique @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - office_folder_has_customers OfficeFolderHasCustomers[] - documents Documents[] + uid String @id @unique @default(uuid()) + status ECustomerStatus @default(PENDING) + contact Contacts @relation(fields: [contact_uid], references: [uid], onDelete: Cascade) + contact_uid String @unique @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + office_folders OfficeFolders[] @relation("OfficeFolderHasCustomers") + documents Documents[] @@map("customers") } -model UserHasNotifications { - uid String @id @unique @default(uuid()) - user Users @relation(fields: [user_uid], references: [uid]) - user_uid String @db.VarChar(255) - notification Notifications @relation(fields: [notification_uid], references: [uid], onDelete: Cascade) - notification_uid String @db.VarChar(255) - notification_status ENotificationStatus @default(UNREAD) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - - @@unique([notification_uid, user_uid]) - @@map("user_has_notifications") -} - model Notifications { - uid String @id @unique @default(uuid()) - message String @db.VarChar(255) - redirection_url String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - user_has_notifications UserHasNotifications[] + uid String @id @unique @default(uuid()) + message String @db.VarChar(255) + redirection_url String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + users Users[] @relation("UserHasNotifications") @@map("notifications") } model OfficeFolders { - uid String @id @unique @default(uuid()) - folder_number String @db.VarChar(255) - name String @db.VarChar(255) - description String? @db.VarChar(255) - archived_description String? @db.VarChar(255) - status EFolderStatus @default(LIVE) - deed Deeds @relation(fields: [deed_uid], references: [uid], onDelete: Cascade) - deed_uid String @unique @db.VarChar(255) - office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) - office_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - office_folder_has_customers OfficeFolderHasCustomers[] - office_folder_has_stakeholder OfficeFolderHasStakeholders[] - documents Documents[] + uid String @id @unique @default(uuid()) + folder_number String @db.VarChar(255) + name String @db.VarChar(255) + description String? @db.VarChar(255) + archived_description String? @db.VarChar(255) + status EFolderStatus @default(LIVE) + deed Deeds @relation(fields: [deed_uid], references: [uid], onDelete: Cascade) + deed_uid String @unique @db.VarChar(255) + office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) + office_uid String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + stakeholders Users[] @relation("OfficeFolderHasStakeholders") + customers Customers[] @relation("OfficeFolderHasCustomers") + documents Documents[] @@unique([folder_number, office_uid]) @@map("office_folders") } -model OfficeFolderHasCustomers { - uid String @id @unique @default(uuid()) - customer Customers @relation(fields: [customer_uid], references: [uid], onDelete: Cascade) - customer_uid String @db.VarChar(255) - office_folder OfficeFolders @relation(fields: [office_folder_uid], references: [uid], onDelete: Cascade) - office_folder_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - - @@unique([office_folder_uid, customer_uid]) - @@map("office_folder_has_customers") -} - -model OfficeFolderHasStakeholders { - uid String @id @unique @default(uuid()) - office_folder OfficeFolders @relation(fields: [office_folder_uid], references: [uid], onDelete: Cascade) - office_folder_uid String @db.VarChar(255) - user_stakeholder Users @relation(fields: [user_stakeholder_uid], references: [uid], onDelete: Cascade) - user_stakeholder_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - - @@unique([office_folder_uid, user_stakeholder_uid]) - @@map("office_folder_has_stakeholder") -} - model Documents { uid String @id @unique @default(uuid()) document_status EDocumentStatus @default(ASKED) @@ -204,6 +172,8 @@ model Files { document_uid String @db.VarChar(255) file_path String @unique @db.VarChar(255) file_name String @db.VarChar(255) + mimetype String @db.VarChar(255) + size Int archived_at DateTime? key String? @db.VarChar(255) created_at DateTime? @default(now()) @@ -223,75 +193,124 @@ model BlockchainAnchors { } model DocumentTypes { - uid String @id @unique @default(uuid()) - name String @db.VarChar(255) - public_description String @db.VarChar(255) - private_description String? @db.VarChar(255) - office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) - office_uid String @db.VarChar(255) - archived_at DateTime? - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - documents Documents[] - deed_has_document_types DeedHasDocumentTypes[] - deed_type_has_document_types DeedTypeHasDocumentTypes[] + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + public_description String @db.VarChar(255) + private_description String? @db.VarChar(255) + office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) + office_uid String @db.VarChar(255) + archived_at DateTime? + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + documents Documents[] + deeds Deeds[] @relation("DeedHasDocumentTypes") + deed_type DeedTypes[] @relation("DeedTypeHasDocumentTypes") @@unique([name, office_uid]) @@map("document_types") } -model DeedHasDocumentTypes { - uid String @id @unique @default(uuid()) - document_type DocumentTypes @relation(fields: [document_type_uid], references: [uid], onDelete: Cascade) - document_type_uid String @db.VarChar(255) - deed Deeds @relation(fields: [deed_uid], references: [uid], onDelete: Cascade) - deed_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - - @@unique([deed_uid, document_type_uid]) - @@map("deed_has_document_types") -} - model Deeds { - uid String @id @unique @default(uuid()) - deed_type DeedTypes @relation(fields: [deed_type_uid], references: [uid], onDelete: Cascade) - deed_type_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - deed_has_document_types DeedHasDocumentTypes[] - office_folder OfficeFolders? + uid String @id @unique @default(uuid()) + deed_type DeedTypes @relation(fields: [deed_type_uid], references: [uid], onDelete: Cascade) + deed_type_uid String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + document_types DocumentTypes[] @relation("DeedHasDocumentTypes") + office_folder OfficeFolders? @@map("deed") } model DeedTypes { - uid String @id @unique @default(uuid()) - name String @db.VarChar(255) - description String @db.VarChar(255) - archived_at DateTime? - office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) - office_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - deed Deeds[] - deed_type_has_document_types DeedTypeHasDocumentTypes[] + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + description String @db.VarChar(255) + archived_at DateTime? + office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) + office_uid String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + deed Deeds[] + document_types DocumentTypes[] @relation("DeedTypeHasDocumentTypes") @@unique([name, office_uid]) @@map("deed_types") } -model DeedTypeHasDocumentTypes { - uid String @id @unique @default(uuid()) - document_type DocumentTypes @relation(fields: [document_type_uid], references: [uid], onDelete: Cascade) - document_type_uid String @db.VarChar(255) - deed_type DeedTypes @relation(fields: [deed_type_uid], references: [uid], onDelete: Cascade) - deed_type_uid String @db.VarChar(255) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt +model Roles { + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + label String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + rules Rules[] @relation("RolesHasRules") + users Users[] - @@unique([deed_type_uid, document_type_uid]) - @@map("deed_type_has_document_types") + @@map("roles") +} + +model OfficeRoles { + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) + office_uid String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + rules Rules[] @relation("OfficeRolesHasRules") + users Users[] + + @@map("office_roles") +} + +model Rules { + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + label String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + role Roles[] @relation("RolesHasRules") + office_roles OfficeRoles[] @relation("OfficeRolesHasRules") + + @@map("rules") +} + +model Emails { + uid String @id @unique @default(uuid()) + templateName String @db.VarChar(255) + from String? @db.VarChar(255) + to String @db.VarChar(255) + subject String @db.VarChar(255) + templateVariables Json @default("{}") @db.Json + cc String[] @db.VarChar(255) + cci String[] @db.VarChar(255) + sentAt DateTime? + nbTrySend Int? @default(0) + lastTrySendDate DateTime? + + @@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 { @@ -328,3 +347,13 @@ enum EDocumentStatus { ANCHORED REFUSED } + +enum EVote { + NOMINATE + DISMISS +} + +enum EAppointmentStatus { + OPEN + CLOSED +} diff --git a/src/common/databases/seeders/seeder.ts b/src/common/databases/seeders/seeder.ts index 39f8f7cd..0e812e5c 100644 --- a/src/common/databases/seeders/seeder.ts +++ b/src/common/databases/seeders/seeder.ts @@ -1,605 +1,1600 @@ -import { - Addresses, - Contacts, - Customers, - DeedHasDocumentTypes, - DeedTypeHasDocumentTypes, - DeedTypes, - Deeds, - DocumentHistory, - DocumentTypes, - Documents, - EDocumentStatus, - EFolderStatus, - EOfficeStatus, - Files, - OfficeFolderHasCustomers, - OfficeFolders, - Offices, - Users, - ECivility, - ECustomerStatus, - PrismaClient, -} from "@prisma/client"; +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"; -(async () => { - const prisma = new PrismaClient(); +import "module-alias/register"; - const randomString = () => { - const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - let result = ""; - for (let i = 10; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; - return result; - }; - const uidCustomer1: string = randomString(); - const uidCustomer2: string = randomString(); +export default async function main() { + try{ + const prisma = new PrismaClient(); - const uidContact1: string = randomString(); - const uidContact2: string = randomString(); - const uidContact3: string = randomString(); - const uidContact4: string = randomString(); - - const uidAddress1: string = randomString(); - const uidAddress2: string = randomString(); - const uidAddress3: string = randomString(); - const uidAddress4: string = randomString(); - - const uidOffice1: string = randomString(); - const uidOffice2: string = randomString(); - - const uidUser1: string = randomString(); - const uidUser2: string = randomString(); - - const uidOfficeFolder1: string = randomString(); - const uidOfficeFolder2: string = randomString(); - const uidOfficeFolder3: string = randomString(); - const uidOfficeFolder4: string = randomString(); - const uidOfficeFolder5: string = randomString(); - - const uidDeed1: string = randomString(); - const uidDeed2: string = randomString(); - const uidDeed3: string = randomString(); - const uidDeed4: string = randomString(); - const uidDeed5: string = randomString(); - - const uidDeedType1: string = randomString(); - const uidDeedType2: string = randomString(); - - const uidDocument1: string = randomString(); - const uidDocument2: string = randomString(); - const uidDocument3: string = randomString(); - const uidDocument4: string = randomString(); - const uidDocument5: string = randomString(); - - const uidDocumentType1: string = randomString(); - const uidDocumentType2: string = randomString(); - const uidDocumentType3: string = randomString(); - - const uidOfficeFolderHasCustomer1: string = randomString(); - const uidOfficeFolderHasCustomer2: string = randomString(); - - const uidFiles1: string = randomString(); - const uidFiles2: string = randomString(); - - const uidDeedHasDocumentType1: string = randomString(); - const uidDeedHasDocumentType2: string = randomString(); - - const uidDeedTypeHasDocumentType1: string = randomString(); - const uidDeedTypeHasDocumentType2: string = randomString(); - - const uidDocumentHistory1: string = randomString(); - const uidDocumentHistory2: string = randomString(); - - // const existingData = await prisma.contacts.findFirst({ where: { uid: uidContact4 } }); - // if (existingData) { - // console.log("Seed data already exists. Skipping seeding process."); - // return; - // } - - - const customers: Customers[] = [ - { - uid: uidCustomer1, - contact_uid: uidContact1, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer2, - contact_uid: uidContact2, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - ]; - - const addresses: Addresses[] = [ - { - uid: uidAddress1, - address: "123 Main St", - city: "Los Angeles", - zip_code: 90001, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress2, - address: "Rue Pierre Emillion", - city: "Paris", - zip_code: 75003, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress3, - address: "Rue Pierre Charles", - city: "Paris", - zip_code: 75003, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress4, - address: "Rue Pierre Pologne", - city: "Paris", - zip_code: 75003, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const contacts: Contacts[] = [ - { - uid: uidContact1, - address_uid: uidAddress1, - first_name: "John", - last_name: "Doe", - email: "john.doe@example.com", - phone_number: randomString(), - cell_phone_number: randomString(), - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact2, - address_uid: uidAddress2, - first_name: "Jane", - last_name: "Doe", - email: "jane.doe@example.com", - phone_number: randomString(), - cell_phone_number: randomString(), - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact3, - address_uid: uidAddress3, - first_name: "Maitre Marcelino", - last_name: "Jack", - email: "Marcelino.Jack@example.com", - phone_number: randomString(), - cell_phone_number: randomString(), - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact4, - address_uid: uidAddress4, - first_name: "Maitre Massi", - last_name: "Jack", - email: "Massi.Jack@example.com", - phone_number: randomString(), - cell_phone_number: randomString(), - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - ]; - - const offices: Offices[] = [ - { - uid: uidOffice1, - idNot: randomString(), - name: "LA Office", - crpcen: randomString(), - address_uid: uidAddress1, - created_at: new Date(), - updated_at: new Date(), - office_status: EOfficeStatus.ACTIVATED, - }, - { - uid: uidOffice2, - idNot: randomString(), - name: "NYC Office", - crpcen: randomString(), - address_uid: uidAddress2, - created_at: new Date(), - updated_at: new Date(), - office_status: EOfficeStatus.DESACTIVATED, - }, - ]; - - const users: Users[] = [ - { - uid: uidUser1, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact1, - office_uid: uidOffice1, - }, - { - uid: uidUser2, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact2, - office_uid: uidOffice2, - }, - ]; - - const officeFolders: OfficeFolders[] = [ - { - uid: uidOfficeFolder1, - folder_number: "0001", - name: "Dossier", - deed_uid: uidDeed1, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder2, - folder_number: "0002", - name: "Dossier", - deed_uid: uidDeed2, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice2, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder3, - folder_number: "0003", - name: "Dossier", - deed_uid: uidDeed3, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice2, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder4, - folder_number: "0004", - name: "Dossier", - deed_uid: uidDeed4, - status: EFolderStatus.ARCHIVED, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice2, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder5, - folder_number: "0005", - name: "Dossier", - deed_uid: uidDeed5, - status: EFolderStatus.ARCHIVED, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice2, - description: null, - archived_description: null, - }, - ]; - - const deeds: Deeds[] = [ - { - uid: uidDeed1, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed2, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed3, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed4, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed5, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const deedTypes: DeedTypes[] = [ - { - uid: uidDeedType1, - name: "Acte de mariage", - archived_at: null, - description: "Acte regroupant deux personnes en mariage", - office_uid: uidOffice1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedType2, - name: "Vente d'un bien immobilier", - archived_at: null, - description: "Permet de vendre un bien immobilier à une entité ou une personne physique", - office_uid: uidOffice2, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const documents: Documents[] = [ - { - uid: uidDocument1, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer1, - document_status: EDocumentStatus.DEPOSITED, - folder_uid: uidOfficeFolder1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument2, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer2, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder2, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument3, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer1, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder1, - document_type_uid: uidDocumentType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument4, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer1, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder1, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument5, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer1, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const documentTypes: DocumentTypes[] = [ - { - uid: uidDocumentType1, - archived_at: null, - name: "Acte de naissance", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Acte de naissance est un document officiel qui atteste de la naissance d'une personne", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType2, - archived_at: null, - name: "Carte d'identité", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, demander un recto-verso au client", - public_description: "Carte d'identité est un document officiel qui atteste de l'identité d'une personne", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType3, - archived_at: null, - name: "Autres documents", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, demander un recto-verso au client", - public_description: "Carte d'identité est un document officiel qui atteste de l'identité d'une personne", - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const officeFolderHasCustomers: OfficeFolderHasCustomers[] = [ - { - uid: uidOfficeFolderHasCustomer1, - customer_uid: uidCustomer1, - office_folder_uid: uidOfficeFolder1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidOfficeFolderHasCustomer2, - customer_uid: uidCustomer2, - office_folder_uid: uidOfficeFolder2, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const files: Files[] = [ - { - uid: uidFiles1, - document_uid: uidDocument1, - file_name: "fileName1", - file_path: "https://www.google1.com", - key: '', - archived_at: null, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidFiles2, - document_uid: uidDocument1, - file_name: "fileName2", - file_path: "https://www.google2.com", - key: '', - archived_at: null, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const deedHasDocumentTypes: DeedHasDocumentTypes[] = [ - { - uid: uidDeedHasDocumentType1, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType2, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const deedTypeHasDocumentTypes: DeedTypeHasDocumentTypes[] = [ - { - uid: uidDeedTypeHasDocumentType1, - deed_type_uid: uidDeedType1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType2, - deed_type_uid: uidDeedType2, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const documentHistories: DocumentHistory[] = [ - { - uid: uidDocumentHistory1, - document_status: EDocumentStatus.ASKED, - document_uid: uidDocument1, - refused_reason: "", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentHistory2, - document_status: EDocumentStatus.DEPOSITED, - document_uid: uidDocument1, - refused_reason: "Le document n'est pas conforme", - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - for (const address of addresses) { - await prisma.addresses.create({ data: address }); + const randomString = () => { + const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let result = ""; + for (let i = 10; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; + return result; + }; + + const idNot1 = "dlefvlef"; + const idNot2 = "jelkvelknvlkn"; + const idNot3 = "rleenrenlnr"; + const idNot4 = "ljfeflecnmd"; + const idNot5 = "rflrefrjf"; + const idNot6 = "er3ojfdlfnd"; + + const addresses: Address[] = [ + { + address: "148 Avenue du bac", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Pierre Emillion", + city: "Pacé", + zip_code: 35740, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Pierre Charles", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Pierre Pologne", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Pierre Marcel", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Pierre Jacques", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Pierre Pascal", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Maxime Henry", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Maxime Francis", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Avenue Paul Roger", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Avenue Paul Franck", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Avenue Paul Maréchal", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Avenue Marcel Denis", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Place Alexandre", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Place Alexandre Jacques", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Place Alexandre 2", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue du livre", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Place de la joie", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Paul Henry", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + { + address: "Rue Marcelin", + city: "Rennes", + zip_code: 35000, + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const contacts: Contact[] = [ + { + address: addresses[0], + first_name: "Arnaud", + last_name: "Daubernatali", + email: "arnaud.daubernatali@smart-chain.fr", + phone_number: "06 12 34 56 78", + cell_phone_number: "06 12 34 56 78", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[1], + first_name: "Maxime", + last_name: "Lalo", + email: "maxime.lalo@smart-chain.fr", + phone_number: "06 23 45 67 89", + cell_phone_number: "06 23 45 67 89", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[2], + first_name: "Vincent", + last_name: "Alamelle", + email: "vincent.alamelle@smart-chain.fr", + phone_number: "06 34 56 78 90", + cell_phone_number: "06 34 56 78 90", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[3], + first_name: "Melissa", + last_name: "Desde", + email: "melissa.desde@smart-chain.fr", + phone_number: "06 45 67 89 01", + cell_phone_number: "06 45 67 89 01", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[4], + first_name: "Maxime", + last_name: "Leroy", + email: "maxime.leroy@hotmail.fr", + phone_number: "06 56 78 90 12", + cell_phone_number: "06 56 78 90 12", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[5], + first_name: "Thibault", + last_name: "Dubois", + email: "thibault.dubois@outlook.com", + phone_number: "06 67 89 01 23", + cell_phone_number: "06 67 89 01 23", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[6], + first_name: "Léa", + last_name: "Fontaine", + email: "lea.fontaine@gmail.com", + phone_number: "06 78 90 12 34", + cell_phone_number: "06 78 90 12 34", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[7], + first_name: "Guillaume", + last_name: "Renaud", + email: "guillaume.renaud@gmail.com", + phone_number: "06 89 01 23 45", + cell_phone_number: "06 89 01 23 45", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[8], + first_name: "Lucie", + last_name: "Chevalier", + email: "lucie.chevalier@outlook.com", + phone_number: "07 12 34 56 78", + cell_phone_number: "07 12 34 56 78", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[9], + first_name: "Sébastien", + last_name: "Dubois", + email: "sebastien.dubois@gmail.com", + phone_number: "07 23 45 67 89", + cell_phone_number: "07 23 45 67 89", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[10], + first_name: "Mathilde", + last_name: "Durand", + email: "mathilde.durand@gmail.com", + phone_number: "07 34 56 78 90", + cell_phone_number: "07 34 56 78 90", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[11], + first_name: "Antoine", + last_name: "Bernard", + email: "antoine.bernard@outlook.com", + phone_number: "07 45 67 89 01", + cell_phone_number: "07 45 67 89 01", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[12], + first_name: "Camille", + last_name: "Laurent", + email: "camille.laurent@gmail.com", + phone_number: "07 56 78 90 12", + cell_phone_number: "07 56 78 90 12", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[13], + first_name: "Julien", + last_name: "Mercier", + email: "julien.mercier@hotmail.fr", + phone_number: "07 67 89 01 23", + cell_phone_number: "07 67 89 01 23", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[14], + first_name: "Charlotte", + last_name: "Lefebvre", + email: "charlotte.lefebvre@gmail.com", + phone_number: "07 78 90 12 34", + cell_phone_number: "07 78 90 12 34", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[15], + first_name: "Caroline", + last_name: "Pallut", + email: "caroline.pallut@gmail.com", + phone_number: "07 89 01 23 45", + cell_phone_number: "07 89 01 23 45", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[16], + first_name: "Nadège", + last_name: "Gauchet", + email: "nedege.gauchet@outlook.com", + phone_number: "06 11 22 33 44", + cell_phone_number: "06 11 22 33 44", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[17], + first_name: "Matthieu", + last_name: "Bougeard", + email: "matthieu.bougeard@gmail.com", + phone_number: "07 22 33 44 55", + cell_phone_number: "07 22 33 44 55", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + { + address: addresses[18], + first_name: "Cécile", + last_name: "Celton", + email: "cecile.celton@outlook.com", + phone_number: "06 55 66 77 88", + cell_phone_number: "06 55 66 77 88", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.FEMALE, + }, + { + address: addresses[19], + first_name: "Gwendal", + last_name: "Texier", + email: "gwendal.texier@gmail.com", + phone_number: "07 88 99 00 11", + cell_phone_number: "07 88 99 00 11", + birthdate: null, + created_at: new Date(), + updated_at: new Date(), + civility: ECivility.MALE, + }, + ]; + + const offices: Office[] = [ + { + idNot: idNot1, + name: "Office Rennes", + crpcen: randomString(), + address: addresses[0], + created_at: new Date(), + updated_at: new Date(), + office_status: EOfficeStatus.ACTIVATED, + }, + ]; + + const customers: Customer[] = [ + { + contact: contacts[5], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[6], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[7], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[8], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[9], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[10], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[11], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[12], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[13], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[14], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[15], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[16], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[17], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[18], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + { + contact: contacts[19], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, + ]; + + const rules: Rule[] = [ + { + name: "GET users", + label: "Lecture des utilisateurs", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET offices", + label: "Lecture des offices", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET customers", + label: "Lecture des clients", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET deeds", + label: "Lecture des actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET deed-types", + label: "Lecture des types d'actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET documents", + label: "Lecture des documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET document-types", + label: "Lecture des types de documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET files", + label: "Lecture des fichiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET folders", + label: "Lecture des dossiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET roles", + label: "Lecture utilisateurs", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET rules", + label: "Lecture des droits", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "GET office-roles", + label: "Lecture des rôles d'office", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT users", + label: "Modification des utilisateurs", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT offices", + label: "Modification des offices", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT customers", + label: "Modification des clients", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT deeds", + label: "Modification des actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT deed-types", + label: "Modification des types d'actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT documents", + label: "Modification des documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT document-types", + label: "Modification des types de documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT files", + label: "Modification des fichiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT folders", + label: "Modification des dossiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT roles", + label: "Modification des rôles", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT rules", + label: "Modification des droits", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "PUT office-roles", + label: "Modification des rôles d'office", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST users", + label: "Création des utilisateurs", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST offices", + label: "Création des offices", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST customers", + label: "Création des clients", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST deeds", + label: "Création des actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST deed-types", + label: "Création des types d'actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST documents", + label: "Création des documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST document-types", + label: "Création des types de documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST files", + label: "Création des fichiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST folders", + label: "Création des dossiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST roles", + label: "Création des rôles", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST rules", + label: "Création des droits", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "POST office-roles", + label: "Création des rôles d'office", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE users", + label: "Suppression des utilisateurs", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE offices", + label: "Suppression des offices", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE customers", + label: "Suppression des clients", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE deeds", + label: "Suppression des actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE deed-types", + label: "Suppression des types d'actes", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE documents", + label: "Suppression des documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE document-types", + label: "Suppression des types de documents", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE files", + label: "Suppression des fichiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE folders", + label: "Suppression des dossiers", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE roles", + label: "Suppression des rôles", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE rules", + label: "Suppression des droits", + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "DELETE office-roles", + label: "Suppression des rôles d'office", + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const roles: Role[] = [ + { + name: "super-admin", + label: "Super administrateur", + created_at: new Date(), + updated_at: new Date(), + rules: rules, + }, + { + name: "admin", + label: "Administrateur", + created_at: new Date(), + updated_at: new Date(), + rules: rules.slice(0, 33), + }, + { + name: "notary", + label: "Notaire", + created_at: new Date(), + updated_at: new Date(), + rules: rules.slice(0, 22), + }, + { + name: "default", + label: "Utilisateur", + created_at: new Date(), + updated_at: new Date(), + rules: rules.slice(0, 11), + }, + ]; + + const officeRoles: OfficeRole[] = [ + { + name: "Notaire", + created_at: new Date(), + updated_at: new Date(), + office: offices[0]!, + rules: rules.slice(0, 33), + }, + { + name: "Collaborateur", + created_at: new Date(), + updated_at: new Date(), + office: offices[0]!, + rules: rules.slice(0, 22), + } + ]; + + const users: User[] = [ + { + created_at: new Date(), + updated_at: new Date(), + idNot: idNot2, + contact: contacts[0], + office_membership: offices[0], + role: roles[0], + }, + { + created_at: new Date(), + updated_at: new Date(), + idNot: idNot3, + contact: contacts[1], + office_membership: offices[0], + role: roles[1], + }, + { + created_at: new Date(), + updated_at: new Date(), + idNot: idNot4, + contact: contacts[2], + office_membership: offices[0], + role: roles[2], + office_role: officeRoles[2], + }, + { + created_at: new Date(), + updated_at: new Date(), + idNot: idNot5, + contact: contacts[3], + office_membership: offices[0], + role: roles[1], + office_role: officeRoles[3], + }, + { + created_at: new Date(), + updated_at: new Date(), + idNot: idNot6, + contact: contacts[4], + office_membership: offices[0], + role: roles[3], + }, + ]; + + const deedTypes: DeedType[] = [ + { + name: "Acte de donation", + archived_at: null, + description: "Acte de donation", + office: offices[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "Acte de vente", + archived_at: null, + description: "Acte de vente", + office: offices[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "Acte de succession", + archived_at: null, + description: "Acte de succession", + office: offices[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + name: "Acte de vente de maison individuelle", + archived_at: null, + description: "Acte de vente de maison individuelle", + office: offices[0], + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const deeds: Deed[] = [ + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[0], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[1], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + { + deed_type: deedTypes[2], + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const documentTypes: DocumentType[] = [ + { + archived_at: null, + name: "Document d'identité", + office: offices[0], + private_description: + "Document officiel d'identification utilisé par plusieurs personnes pour prouver leur identité et leur nationalité (CNI, passeport)", + public_description: + "Document officiel d'identification utilisé par plusieurs personnes pour prouver leur identité et leur nationalité (CNI, passeport)", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Taxe Foncière", + office: offices[0], + private_description: "Impôt annuel imposé sur les propriétés foncières et utilisé pour financer les services publics locaux.", + public_description: "Impôt annuel imposé sur les propriétés foncières et utilisé pour financer les services publics locaux.", + created_at: new Date(), + updated_at: new Date(), + }, + + { + archived_at: null, + name: "Contrat Mariage", + office: offices[0], + private_description: "Accord légal qui établit les droits et les obligations entre deux personnes s'unissant en mariage.", + public_description: "Accord légal qui établit les droits et les obligations entre deux personnes s'unissant en mariage.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Livret de famille", + office: offices[0], + private_description: + "Document officiel qui enregistre les détails et les événements familiaux tels que les mariages, les naissances et les décès d'un couple et de leurs enfants.", + public_description: + "Document officiel qui enregistre les détails et les événements familiaux tels que les mariages, les naissances et les décès d'un couple et de leurs enfants.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Bail commercial", + office: offices[0], + private_description: + "Contrat légal entre un propriétaire et un locataire pour la location d'un bien immobilier utilisé à des fins commerciales ou professionnelles.", + public_description: + "Contrat légal entre un propriétaire et un locataire pour la location d'un bien immobilier utilisé à des fins commerciales ou professionnelles.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Statuts SCI", + office: offices[0], + private_description: "Document légal qui définit les règles et les dispositions régissant la Société Civile Immobilière (SCI).", + public_description: "Document légal qui définit les règles et les dispositions régissant la Société Civile Immobilière (SCI).", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Avis de taxe foncière", + office: offices[0], + private_description: "Notification officielle indiquant le montant de l'impôt foncier dû sur une propriété.", + public_description: "Notification officielle indiquant le montant de l'impôt foncier dû sur une propriété.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Appel de charge de copropriété", + office: offices[0], + private_description: + "Document envoyé aux copropriétaires pour les informer des dépenses et des charges communes liées à la gestion et à l'entretien de l'immeuble.", + public_description: + "Document envoyé aux copropriétaires pour les informer des dépenses et des charges communes liées à la gestion et à l'entretien de l'immeuble.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "PVAG", + office: offices[0], + private_description: + "Compte rendu écrit des discussions, décisions et résolutions prises lors d'une réunion d'assemblée générale de copropriété.", + public_description: + "Compte rendu écrit des discussions, décisions et résolutions prises lors d'une réunion d'assemblée générale de copropriété.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Règlement de copropriété", + office: offices[0], + private_description: + "Document juridique qui établit les règles et les droits des copropriétaires d'un immeuble en copropriété.", + public_description: "Document juridique qui établit les règles et les droits des copropriétaires d'un immeuble en copropriété.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Titre de propriété", + office: offices[0], + private_description: "Document légal qui atteste de la propriété d'un bien immobilier et en identifie le propriétaire.", + public_description: "Document légal qui atteste de la propriété d'un bien immobilier et en identifie le propriétaire.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Plan et loi carrez", + office: offices[0], + private_description: + "Document officiel qui mesure la superficie d'un lot ou d'un bien immobilier, conformément à la loi Carrez qui encadre les transactions immobilières.", + public_description: + "Document officiel qui mesure la superficie d'un lot ou d'un bien immobilier, conformément à la loi Carrez qui encadre les transactions immobilières.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "CNI", + office: offices[0], + private_description: + "Document officiel d'identification délivré par l'État pour prouver l'identité et la nationalité d'une personne.", + public_description: + "Document officiel d'identification délivré par l'État pour prouver l'identité et la nationalité d'une personne.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Modifications règlement copropriété (plusieurs)", + office: offices[0], + private_description: + "Documents légaux qui apportent des changements ou des ajustements aux règles et dispositions du règlement de copropriété initial.", + public_description: + "Documents légaux qui apportent des changements ou des ajustements aux règles et dispositions du règlement de copropriété initial.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Avis de décès", + office: offices[0], + private_description: "Notification officielle délivrée par les autorités compétentes pour informer du décès d'une personne.", + public_description: "Notification officielle délivrée par les autorités compétentes pour informer du décès d'une personne.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Lettre de mission", + office: offices[0], + private_description: + "Document contractuel qui définit les termes et les objectifs d'une mission confiée à une personne ou à une entreprise.", + public_description: + "Document contractuel qui définit les termes et les objectifs d'une mission confiée à une personne ou à une entreprise.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "DPE", + office: offices[0], + private_description: "Diagnostic de Performance Energétique.", + public_description: "Diagnostic de Performance Energétique.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "RIB", + office: offices[0], + private_description: "Relevé d'identité bancaire ou IBAN.", + public_description: "Relevé d'identité bancaire ou IBAN.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Acte d'achat par la SCI", + office: offices[0], + private_description: "Acte d'achat par la SCI.", + public_description: "Acte d'achat par la SCI.", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Other", + office: offices[0], + private_description: "Other", + public_description: "Other", + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const officeFolders: OfficeFolder[] = [ + { + folder_number: "0001", + name: "Vente par Mme. Simon au profit de Mme. Lextrait", + deed: deeds[0], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0002", + name: "Donation des parts sociales de la société SARL FLORE", + deed: deeds[1], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0003", + name: "Vente par Mme. Lefebvre au profit de Mme. Mathieu", + deed: deeds[2], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0004", + name: "Vente par Mme. Chevalier au profit de M. Daveau", + deed: deeds[3], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0005", + name: "Vente par M. Lalo au profit de Mme. Pigale", + deed: deeds[4], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0006", + name: "Donation des parts sociales de la société SMART-TALENT", + deed: deeds[5], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0007", + name: "Vente par M. Girard au profit de M. Louis", + deed: deeds[6], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0008", + name: "Vente par Mme. Leclerc au profit de M. Louis", + deed: deeds[7], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + { + folder_number: "0009", + name: "Vente par M. Lambert au profit de M. Holmes", + deed: deeds[8], + status: EFolderStatus.LIVE, + created_at: new Date(), + updated_at: new Date(), + office: offices[0], + description: null, + archived_description: null, + }, + ]; + + for (const office of offices) { + const officeCreated = await prisma.offices.create({ + data: { + idNot: office.idNot, + name: office.name, + crpcen: office.crpcen, + address: { + create: { + address: office.address!.address, + zip_code: office.address!.zip_code, + city: office.address!.city, + }, + }, + office_status: EOfficeStatus.DESACTIVATED, + }, + }); + office.uid = officeCreated.uid; + } + for (const rule of rules) { + const ruleCreated = await prisma.rules.create({ + data: { + name: rule.name, + label: rule.label, + }, + }); + rule.uid = ruleCreated.uid; + } + + for (const role of roles) { + const roleCreated = await prisma.roles.create({ + data: { + name: role.name, + label: role.label, + rules: { + connect: role.rules?.map((rule) => ({ + uid: rule.uid!, + })), + }, + }, + }); + role.uid = roleCreated.uid; + } + + for (const officeRole of officeRoles) { + const officeRoleCreated = await prisma.officeRoles.create({ + data: { + name: officeRole.name, + office: { + connect: { + uid: officeRole.office.uid, + }, + }, + rules: { + connect: officeRole.rules?.map((rule) => ({ + uid: rule.uid!, + })), + }, + }, + }); + officeRole.uid = officeRoleCreated.uid; + } + + for (const user of users) { + const createArgs: Prisma.UsersCreateArgs = { + data: { + idNot: user.idNot, + office_membership: { + connectOrCreate: { + where: { + idNot: user.office_membership!.idNot, + }, + create: { + idNot: user.office_membership!.idNot, + name: user.office_membership!.name, + crpcen: user.office_membership!.crpcen, + address: { + create: { + address: user.office_membership!.address!.address, + zip_code: user.office_membership!.address!.zip_code, + city: user.office_membership!.address!.city, + }, + }, + }, + }, + }, + contact: { + create: { + first_name: user.contact!.first_name, + last_name: user.contact!.last_name, + email: user.contact!.email, + phone_number: user.contact!.phone_number, + cell_phone_number: user.contact!.cell_phone_number, + civility: ECivility[user.contact!.civility as keyof typeof ECivility], + address: {}, + }, + }, + role: { + connect: { + uid: user.role!.uid, + }, + }, + }, + }; + if (user.contact!.address) { + createArgs.data.contact!.create!.address!.create = { + address: user.contact!.address.address, + zip_code: user.contact!.address.zip_code, + city: user.contact!.address.city, + }; + } + if (user.office_role) { + createArgs.data.office_role = { + connect: { + uid: user.office_role.uid, + }, + }; + } + const userCreated = await prisma.users.create(createArgs); + user.uid = userCreated.uid; + } + + for (const customer of customers) { + const createArgs: Prisma.CustomersCreateArgs = { + data: { + status: ECustomerStatus.PENDING, + contact: { + create: { + first_name: customer.contact!.first_name, + last_name: customer.contact!.last_name, + email: customer.contact!.email, + phone_number: customer.contact!.phone_number, + cell_phone_number: customer.contact!.cell_phone_number, + civility: ECivility[customer.contact!.civility as keyof typeof ECivility], + address: {}, + }, + }, + }, + }; + + if (customer.contact?.address) { + createArgs.data.contact!.create!.address = { + create: { + address: customer.contact?.address?.address, + zip_code: customer.contact?.address?.zip_code, + city: customer.contact?.address?.city, + }, + }; + } + const customersCreated = await prisma.customers.create(createArgs); + customer.uid = customersCreated.uid; + } + + for (const deedType of deedTypes) { + const createArgs: Prisma.DeedTypesCreateArgs = { + data: { + name: deedType.name, + description: deedType.description, + office: { + connect: { + uid: deedType.office!.uid, + }, + }, + }, + }; + if (deedType.document_types) { + createArgs.data.document_types = { + connect: deedType.document_types.map((documentType) => ({ + uid: documentType.uid, + })), + }; + } + const deedTypeCreated = await prisma.deedTypes.create(createArgs); + deedType.uid = deedTypeCreated.uid; + } + + for (const deed of deeds) { + const createArgs: Prisma.DeedsCreateArgs = { + data: { + deed_type: { + connect: { + uid: deed.deed_type!.uid, + }, + }, + }, + }; + const deedTypeWithDocumentTypes = await prisma.deedTypes.findUniqueOrThrow({ + where: { + uid: deed.deed_type!.uid, + }, + include: { document_types: true }, + }); + + if (deedTypeWithDocumentTypes.document_types) { + createArgs.data.document_types = { + connect: deedTypeWithDocumentTypes.document_types.map((documentType) => ({ + uid: documentType.uid, + })), + }; + } + const deedCreated = await prisma.deeds.create(createArgs); + deed.uid = deedCreated.uid; + } + + for (const documentType of documentTypes) { + const documentTypeCreated = await prisma.documentTypes.create({ + data: { + name: documentType.name, + public_description: documentType.public_description, + private_description: documentType.private_description, + office: { + connect: { + uid: documentType.office!.uid, + }, + }, + }, + }); + documentType.uid = documentTypeCreated.uid; + } + + for (const officeFolder of officeFolders) { + const officeFolderCreated = await prisma.officeFolders.create({ + data: { + folder_number: officeFolder.folder_number, + name: officeFolder.name, + description: officeFolder.description, + status: EFolderStatus.LIVE, + deed: { + connect: { + uid: officeFolder.deed?.uid, + }, + }, + office: { + connect: { + uid: officeFolder.office!.uid, + }, + }, + stakeholders: { + connect: officeFolder.stakeholders?.map((stakeholder) => ({ + uid: stakeholder.uid!, + })), + }, + }, + }); + officeFolder.uid = officeFolderCreated.uid; + } + + console.log(">MOCK DATA - Seeding completed!"); } - - for (const contact of contacts) { - await prisma.contacts.create({ data: contact }); + catch(error){ + console.log("Data already seeded, skiping"); } - - for (const office of offices) { - await prisma.offices.create({ data: office }); - } - - for (const user of users) { - await prisma.users.create({ data: user }); - } - - for (const customer of customers) { - await prisma.customers.create({ data: customer }); - } - - for (const deedType of deedTypes) { - await prisma.deedTypes.create({ data: deedType }); - } - - for (const deed of deeds) { - await prisma.deeds.create({ data: deed }); - } - for (const officeFolder of officeFolders) { - await prisma.officeFolders.create({ data: officeFolder }); - } - - for (const documentType of documentTypes) { - await prisma.documentTypes.create({ data: documentType }); - } - - for (const document of documents) { - await prisma.documents.create({ data: document }); - } - - for (const file of files) { - await prisma.files.create({ data: file }); - } - - for (const documentHistory of documentHistories) { - await prisma.documentHistory.create({ data: documentHistory }); - } - - for (const officeFolderHasCustomer of officeFolderHasCustomers) { - await prisma.officeFolderHasCustomers.create({ data: officeFolderHasCustomer }); - } - - for (const deedHasDocumentType of deedHasDocumentTypes) { - await prisma.deedHasDocumentTypes.create({ data: deedHasDocumentType }); - } - - for (const deedTypeHasDocumentType of deedTypeHasDocumentTypes) { - await prisma.deedTypeHasDocumentTypes.create({ data: deedTypeHasDocumentType }); - } - - console.log(">MOCK DATA - Seeding completed!"); -})(); + +} +main(); diff --git a/src/common/databases/seeders/seeder2.ts b/src/common/databases/seeders/seeder2.ts deleted file mode 100644 index e0e6b892..00000000 --- a/src/common/databases/seeders/seeder2.ts +++ /dev/null @@ -1,2088 +0,0 @@ -import { - Addresses, - Contacts, - Customers, - DeedHasDocumentTypes, - DeedTypeHasDocumentTypes, - DeedTypes, - Deeds, - DocumentHistory, - DocumentTypes, - Documents, - EDocumentStatus, - EFolderStatus, - EOfficeStatus, - Files, - OfficeFolderHasCustomers, - OfficeFolders, - Offices, - Users, - ECivility, - ECustomerStatus, - PrismaClient, -} from "@prisma/client"; - -(async () => { - const prisma = new PrismaClient(); - - const existingData = await prisma.contacts.findFirst({ where: { email: "john.doe@example.com" } }); - if (existingData) { - console.log("Seed data already exists. Skipping seeding process."); - return; - } - - const randomString = () => { - const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - let result = ""; - for (let i = 10; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; - return result; - }; - const uidCustomer1: string = randomString(); - const uidCustomer2: string = randomString(); - const uidCustomer3: string = randomString(); - const uidCustomer4: string = randomString(); - const uidCustomer5: string = randomString(); - const uidCustomer6: string = randomString(); - const uidCustomer7: string = randomString(); - const uidCustomer8: string = randomString(); - const uidCustomer9: string = randomString(); - const uidCustomer10: string = randomString(); - const uidCustomer11: string = randomString(); - const uidCustomer12: string = randomString(); - const uidCustomer13: string = randomString(); - const uidCustomer14: string = randomString(); - const uidCustomer15: string = randomString(); - - const uidContact1: string = randomString(); - const uidContact2: string = randomString(); - const uidContact3: string = randomString(); - const uidContact4: string = randomString(); - const uidContact5: string = randomString(); - const uidContact6: string = randomString(); - const uidContact7: string = randomString(); - const uidContact8: string = randomString(); - const uidContact9: string = randomString(); - const uidContact10: string = randomString(); - const uidContact11: string = randomString(); - const uidContact12: string = randomString(); - const uidContact13: string = randomString(); - const uidContact14: string = randomString(); - const uidContact15: string = randomString(); - const uidContact16: string = randomString(); - const uidContact17: string = randomString(); - const uidContact18: string = randomString(); - const uidContact19: string = randomString(); - const uidContact20: string = randomString(); - - const uidAddress1: string = randomString(); - const uidAddress2: string = randomString(); - const uidAddress3: string = randomString(); - const uidAddress4: string = randomString(); - const uidAddress5: string = randomString(); - const uidAddress6: string = randomString(); - const uidAddress7: string = randomString(); - const uidAddress8: string = randomString(); - const uidAddress9: string = randomString(); - const uidAddress10: string = randomString(); - const uidAddress11: string = randomString(); - const uidAddress12: string = randomString(); - const uidAddress13: string = randomString(); - const uidAddress14: string = randomString(); - const uidAddress15: string = randomString(); - const uidAddress16: string = randomString(); - const uidAddress17: string = randomString(); - const uidAddress18: string = randomString(); - const uidAddress19: string = randomString(); - const uidAddress20: string = randomString(); - - const uidOffice1: string = randomString(); - - const uidUser1: string = randomString(); - const uidUser2: string = randomString(); - const uidUser3: string = randomString(); - const uidUser4: string = randomString(); - const uidUser5: string = randomString(); - - const uidOfficeFolder1: string = randomString(); - const uidOfficeFolder2: string = randomString(); - const uidOfficeFolder3: string = randomString(); - const uidOfficeFolder4: string = randomString(); - const uidOfficeFolder5: string = randomString(); - const uidOfficeFolder6: string = randomString(); - const uidOfficeFolder7: string = randomString(); - const uidOfficeFolder8: string = randomString(); - const uidOfficeFolder9: string = randomString(); - const uidOfficeFolder10: string = randomString(); - const uidOfficeFolder11: string = randomString(); - const uidOfficeFolder12: string = randomString(); - const uidOfficeFolder13: string = randomString(); - const uidOfficeFolder14: string = randomString(); - const uidOfficeFolder15: string = randomString(); - const uidOfficeFolder16: string = randomString(); - const uidOfficeFolder17: string = randomString(); - const uidOfficeFolder18: string = randomString(); - const uidOfficeFolder19: string = randomString(); - const uidOfficeFolder20: string = randomString(); - const uidOfficeFolder21: string = randomString(); - - const uidDeed1: string = randomString(); - const uidDeed2: string = randomString(); - const uidDeed3: string = randomString(); - const uidDeed4: string = randomString(); - const uidDeed5: string = randomString(); - const uidDeed6: string = randomString(); - const uidDeed7: string = randomString(); - const uidDeed8: string = randomString(); - const uidDeed9: string = randomString(); - const uidDeed10: string = randomString(); - const uidDeed11: string = randomString(); - const uidDeed12: string = randomString(); - const uidDeed13: string = randomString(); - const uidDeed14: string = randomString(); - const uidDeed15: string = randomString(); - const uidDeed16: string = randomString(); - const uidDeed17: string = randomString(); - const uidDeed18: string = randomString(); - const uidDeed19: string = randomString(); - const uidDeed20: string = randomString(); - const uidDeed21: string = randomString(); - - - const uidDeedType1: string = randomString(); - const uidDeedType2: string = randomString(); - const uidDeedType3: string = randomString(); - const uidDeedType4: string = randomString(); - - const uidDocument1: string = randomString(); - const uidDocument2: string = randomString(); - const uidDocument3: string = randomString(); - const uidDocument4: string = randomString(); - - const uidDocumentType1: string = randomString(); - const uidDocumentType2: string = randomString(); - const uidDocumentType3: string = randomString(); - const uidDocumentType4: string = randomString(); - const uidDocumentType5: string = randomString(); - const uidDocumentType6: string = randomString(); - const uidDocumentType7: string = randomString(); - const uidDocumentType8: string = randomString(); - const uidDocumentType9: string = randomString(); - const uidDocumentType10: string = randomString(); - const uidDocumentType11: string = randomString(); - const uidDocumentType12: string = randomString(); - const uidDocumentType13: string = randomString(); - const uidDocumentType14: string = randomString(); - const uidDocumentType15: string = randomString(); - const uidDocumentType16: string = randomString(); - const uidDocumentType17: string = randomString(); - const uidDocumentType18: string = randomString(); - - const uidOfficeFolderHasCustomer1: string = randomString(); - const uidOfficeFolderHasCustomer2: string = randomString(); - const uidOfficeFolderHasCustomer3: string = randomString(); - const uidOfficeFolderHasCustomer4: string = randomString(); - const uidOfficeFolderHasCustomer5: string = randomString(); - - - const uidFiles1: string = randomString(); - const uidFiles2: string = randomString(); - - const uidDeedHasDocumentType1: string = randomString(); - const uidDeedHasDocumentType2: string = randomString(); - const uidDeedHasDocumentType3: string = randomString(); - const uidDeedHasDocumentType4: string = randomString(); - const uidDeedHasDocumentType5: string = randomString(); - const uidDeedHasDocumentType6: string = randomString(); - const uidDeedHasDocumentType7: string = randomString(); - const uidDeedHasDocumentType8: string = randomString(); - const uidDeedHasDocumentType9: string = randomString(); - const uidDeedHasDocumentType10: string = randomString(); - const uidDeedHasDocumentType11: string = randomString(); - const uidDeedHasDocumentType12: string = randomString(); - const uidDeedHasDocumentType13: string = randomString(); - const uidDeedHasDocumentType14: string = randomString(); - const uidDeedHasDocumentType15: string = randomString(); - const uidDeedHasDocumentType16: string = randomString(); - const uidDeedHasDocumentType17: string = randomString(); - const uidDeedHasDocumentType18: string = randomString(); - const uidDeedHasDocumentType19: string = randomString(); - const uidDeedHasDocumentType20: string = randomString(); - const uidDeedHasDocumentType21: string = randomString(); - const uidDeedHasDocumentType22: string = randomString(); - const uidDeedHasDocumentType23: string = randomString(); - const uidDeedHasDocumentType24: string = randomString(); - const uidDeedHasDocumentType25: string = randomString(); - const uidDeedHasDocumentType26: string = randomString(); - const uidDeedHasDocumentType27: string = randomString(); - const uidDeedHasDocumentType28: string = randomString(); - const uidDeedHasDocumentType29: string = randomString(); - const uidDeedHasDocumentType30: string = randomString(); - const uidDeedHasDocumentType31: string = randomString(); - const uidDeedHasDocumentType32: string = randomString(); - const uidDeedHasDocumentType33: string = randomString(); - const uidDeedHasDocumentType34: string = randomString(); - const uidDeedHasDocumentType35: string = randomString(); - const uidDeedHasDocumentType36: string = randomString(); - const uidDeedHasDocumentType37: string = randomString(); - const uidDeedHasDocumentType38: string = randomString(); - const uidDeedHasDocumentType39: string = randomString(); - const uidDeedHasDocumentType40: string = randomString(); - const uidDeedHasDocumentType41: string = randomString(); - const uidDeedHasDocumentType42: string = randomString(); - const uidDeedHasDocumentType43: string = randomString(); - const uidDeedHasDocumentType44: string = randomString(); - const uidDeedHasDocumentType45: string = randomString(); - const uidDeedHasDocumentType46: string = randomString(); - const uidDeedHasDocumentType47: string = randomString(); - const uidDeedHasDocumentType48: string = randomString(); - const uidDeedHasDocumentType49: string = randomString(); - const uidDeedHasDocumentType50: string = randomString(); - const uidDeedHasDocumentType51: string = randomString(); - const uidDeedHasDocumentType52: string = randomString(); - const uidDeedHasDocumentType53: string = randomString(); - - - - const uidDeedTypeHasDocumentType1: string = randomString(); - const uidDeedTypeHasDocumentType2: string = randomString(); - const uidDeedTypeHasDocumentType3: string = randomString(); - const uidDeedTypeHasDocumentType4: string = randomString(); - const uidDeedTypeHasDocumentType5: string = randomString(); - const uidDeedTypeHasDocumentType6: string = randomString(); - const uidDeedTypeHasDocumentType7: string = randomString(); - const uidDeedTypeHasDocumentType8: string = randomString(); - - - - - const uidDocumentHistory1: string = randomString(); - const uidDocumentHistory2: string = randomString(); - - const customers: Customers[] = [ - { - uid: uidCustomer1, - contact_uid: uidContact1, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer2, - contact_uid: uidContact2, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer3, - contact_uid: uidContact3, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer4, - contact_uid: uidContact4, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer5, - contact_uid: uidContact5, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer6, - contact_uid: uidContact6, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer7, - contact_uid: uidContact7, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer8, - contact_uid: uidContact8, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer9, - contact_uid: uidContact9, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer10, - contact_uid: uidContact10, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer11, - contact_uid: uidContact11, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer12, - contact_uid: uidContact12, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer13, - contact_uid: uidContact13, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer14, - contact_uid: uidContact14, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - { - uid: uidCustomer15, - contact_uid: uidContact15, - created_at: new Date(), - updated_at: new Date(), - status: ECustomerStatus.PENDING, - }, - ]; - - const addresses: Addresses[] = [ - { - uid: uidAddress1, - address: "148 Avenue du bac", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress2, - address: "Rue Pierre Emillion", - city: "Pacé", - zip_code: 35740, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress3, - address: "Rue Pierre Charles", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress4, - address: "Rue Pierre Pologne", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress5, - address: "Rue Pierre Marcel", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress6, - address: "Rue Pierre Jacques", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress7, - address: "Rue Pierre Pascal", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress8, - address: "Rue Maxime Henry", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress9, - address: "Rue Maxime Francis", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress10, - address: "Avenue Paul Roger", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress11, - address: "Avenue Paul Franck", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress12, - address: "Avenue Paul Maréchal", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress13, - address: "Avenue Marcel Denis", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress14, - address: "Place Alexandre", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress15, - address: "Place Alexandre Jacques", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress16, - address: "Place Alexandre 2", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress17, - address: "Rue du livre", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress18, - address: "Place de la joie", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress19, - address: "Rue Paul Henry", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidAddress20, - address: "Rue Marcelin", - city: "Rennes", - zip_code: 35000, - created_at: new Date(), - updated_at: new Date(), - }, - - ]; - - const contacts: Contacts[] = [ - { - uid: uidContact1, - address_uid: uidAddress1, - first_name: "Manon", - last_name: "Simon", - email: "manon.simon@gmail.com", - phone_number: "06 12 34 56 78", - cell_phone_number: "06 12 34 56 78", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact2, - address_uid: uidAddress2, - first_name: "Kevin", - last_name: "Hautefaye", - email: "kevin.hautefaye@gmail.com", - phone_number: "06 23 45 67 89", - cell_phone_number: "06 23 45 67 89", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact3, - address_uid: uidAddress3, - first_name: "Maxime", - last_name: "Lalo", - email: "maxime.lalo@gmail.com", - phone_number: "06 34 56 78 90", - cell_phone_number: "06 34 56 78 90", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact4, - address_uid: uidAddress4, - first_name: "Vincent", - last_name: "Brognard", - email: "vincent.brognard@gmail.com", - phone_number: "06 45 67 89 01", - cell_phone_number: "06 45 67 89 01", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact5, - address_uid: uidAddress5, - first_name: "Maxime", - last_name: "Leroy", - email: "maxime.leroy@hotmail.fr", - phone_number: "06 56 78 90 12", - cell_phone_number: "06 56 78 90 12", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact6, - address_uid: uidAddress6, - first_name: "Thibault", - last_name: "Dubois", - email: "thibault.dubois@outlook.com", - phone_number: "06 67 89 01 23", - cell_phone_number: "06 67 89 01 23", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact7, - address_uid: uidAddress7, - first_name: "Léa", - last_name: "Fontaine", - email: "lea.fontaine@gmail.com", - phone_number: "06 78 90 12 34", - cell_phone_number: "06 78 90 12 34", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact8, - address_uid: uidAddress8, - first_name: "Guillaume", - last_name: "Renaud", - email: "guillaume.renaud@gmail.com", - phone_number: "06 89 01 23 45", - cell_phone_number: "06 89 01 23 45", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact9, - address_uid: uidAddress9, - first_name: "Lucie", - last_name: "Chevalier", - email: "lucie.chevalier@outlook.com", - phone_number: "07 12 34 56 78", - cell_phone_number: "07 12 34 56 78", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact10, - address_uid: uidAddress10, - first_name: "Sébastien", - last_name: "Dubois", - email: "sebastien.dubois@gmail.com", - phone_number: "07 23 45 67 89", - cell_phone_number: "07 23 45 67 89", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact11, - address_uid: uidAddress11, - first_name: "Mathilde", - last_name: "Durand", - email: "mathilde.durand@gmail.com", - phone_number: "07 34 56 78 90", - cell_phone_number: "07 34 56 78 90", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact12, - address_uid: uidAddress12, - first_name: "Antoine", - last_name: "Bernard", - email: "antoine.bernard@outlook.com", - phone_number: "07 45 67 89 01", - cell_phone_number: "07 45 67 89 01", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact13, - address_uid: uidAddress13, - first_name: "Camille", - last_name: "Laurent", - email: "camille.laurent@gmail.com", - phone_number: "07 56 78 90 12", - cell_phone_number: "07 56 78 90 12", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact14, - address_uid: uidAddress14, - first_name: "Julien", - last_name: "Mercier", - email: "julien.mercier@hotmail.fr", - phone_number: "07 67 89 01 23", - cell_phone_number: "07 67 89 01 23", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact15, - address_uid: uidAddress15, - first_name: "Charlotte", - last_name: "Lefebvre", - email: "charlotte.lefebvre@gmail.com", - phone_number: "07 78 90 12 34", - cell_phone_number: "07 78 90 12 34", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact16, - address_uid: uidAddress16, - first_name: "Caroline", - last_name: "Pallut", - email: "caroline.pallut@gmail.com", - phone_number: "07 89 01 23 45", - cell_phone_number: "07 89 01 23 45", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact17, - address_uid: uidAddress17, - first_name: "Nadège", - last_name: "Gauchet", - email: "nedege.gauchet@outlook.com", - phone_number: "06 11 22 33 44", - cell_phone_number: "06 11 22 33 44", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact18, - address_uid: uidAddress18, - first_name: "Matthieu", - last_name: "Bougeard", - email: "matthieu.bougeard@gmail.com", - phone_number: "07 22 33 44 55", - cell_phone_number: "07 22 33 44 55", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - { - uid: uidContact19, - address_uid: uidAddress19, - first_name: "Cécile", - last_name: "Celton", - email: "cecile.celton@outlook.com", - phone_number: "06 55 66 77 88", - cell_phone_number: "06 55 66 77 88", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.FEMALE, - }, - { - uid: uidContact20, - address_uid: uidAddress20, - first_name: "Gwendal", - last_name: "Texier", - email: "gwendal.texier@gmail.com", - phone_number: "07 88 99 00 11", - cell_phone_number: "07 88 99 00 11", - birthdate: null, - created_at: new Date(), - updated_at: new Date(), - civility: ECivility.MALE, - }, - ]; - - const offices: Offices[] = [ - { - uid: uidOffice1, - idNot: randomString(), - name: "Office Rennes", - crpcen: randomString(), - address_uid: uidAddress1, - created_at: new Date(), - updated_at: new Date(), - office_status: EOfficeStatus.ACTIVATED, - } - ]; - - const users: Users[] = [ - { - uid: uidUser1, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact16, - office_uid: uidOffice1, - }, - { - uid: uidUser2, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact17, - office_uid: uidOffice1, - }, - { - uid: uidUser3, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact18, - office_uid: uidOffice1, - }, - { - uid: uidUser4, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact19, - office_uid: uidOffice1, - }, - { - uid: uidUser5, - created_at: new Date(), - updated_at: new Date(), - idNot: randomString(), - contact_uid: uidContact20, - office_uid: uidOffice1, - }, - ]; - - const officeFolders: OfficeFolders[] = [ - { - uid: uidOfficeFolder1, - folder_number: "0001", - name: "Dossier", - deed_uid: uidDeed1, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder2, - folder_number: "0002", - name: "Dossier", - deed_uid: uidDeed2, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder3, - folder_number: "0003", - name: "Dossier", - deed_uid: uidDeed3, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder4, - folder_number: "0004", - name: "Dossier", - deed_uid: uidDeed4, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder5, - folder_number: "0005", - name: "Dossier", - deed_uid: uidDeed5, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder6, - folder_number: "0006", - name: "Dossier", - deed_uid: uidDeed6, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder7, - folder_number: "0007", - name: "Dossier", - deed_uid: uidDeed7, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder8, - folder_number: "0008", - name: "Dossier", - deed_uid: uidDeed8, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder9, - folder_number: "0009", - name: "Dossier", - deed_uid: uidDeed9, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder10, - folder_number: "00010", - name: "Dossier", - deed_uid: uidDeed10, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder11, - folder_number: "00011", - name: "Dossier", - deed_uid: uidDeed11, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder12, - folder_number: "00012", - name: "Dossier", - deed_uid: uidDeed12, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder13, - folder_number: "00013", - name: "Dossier", - deed_uid: uidDeed13, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder14, - folder_number: "00014", - name: "Dossier", - deed_uid: uidDeed14, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder15, - folder_number: "00015", - name: "Dossier", - deed_uid: uidDeed15, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder16, - folder_number: "00016", - name: "Dossier", - deed_uid: uidDeed16, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder17, - folder_number: "00017", - name: "Dossier", - deed_uid: uidDeed17, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder18, - folder_number: "00018", - name: "Dossier", - deed_uid: uidDeed18, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder19, - folder_number: "00019", - name: "Dossier", - deed_uid: uidDeed19, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder20, - folder_number: "00020", - name: "Dossier", - deed_uid: uidDeed20, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - { - uid: uidOfficeFolder21, - folder_number: "00021", - name: "Dossier", - deed_uid: uidDeed21, - status: EFolderStatus.LIVE, - created_at: new Date(), - updated_at: new Date(), - office_uid: uidOffice1, - description: null, - archived_description: null, - }, - ]; - - const deeds: Deeds[] = [ - { - uid: uidDeed1, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed2, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed3, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed4, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed5, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed6, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed7, - deed_type_uid: uidDeedType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed8, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed9, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed10, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed11, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed12, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed13, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed14, - deed_type_uid: uidDeedType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed15, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed16, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed17, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed18, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed19, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed20, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeed21, - deed_type_uid: uidDeedType3, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const deedTypes: DeedTypes[] = [ - { - uid: uidDeedType1, - name: "Acte de donation", - archived_at: null, - description: "Acte de donation", - office_uid: uidOffice1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedType2, - name: "Acte de vente", - archived_at: null, - description: "Acte de vente", - office_uid: uidOffice1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedType3, - name: "Acte de succession", - archived_at: null, - description: "Acte de succession", - office_uid: uidOffice1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedType4, - name: "Acte de vente de maison individuelle", - archived_at: null, - description: "Acte de vente de maison individuelle", - office_uid: uidOffice1, - created_at: new Date(), - updated_at: new Date(), - }, - - ]; - - const documents: Documents[] = [ - { - uid: uidDocument1, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer1, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument2, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer2, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder2, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument3, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer3, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder3, - document_type_uid: uidDocumentType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocument4, - blockchain_anchor_uid: null, - depositor_uid: uidCustomer4, - document_status: EDocumentStatus.ASKED, - folder_uid: uidOfficeFolder4, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const documentTypes: DocumentTypes[] = [ - { - uid: uidDocumentType1, - archived_at: null, - name: "Document d'identité", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, demander un recto-verso au client", - public_description: "Document officiel d'identification utilisé par plusieurs personnes pour prouver leur identité et leur nationalité (CNI, passeport)", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType2, - archived_at: null, - name: "Taxe Foncière", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Impôt annuel imposé sur les propriétés foncières et utilisé pour financer les services publics locaux.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType3, - archived_at: null, - name: "Contrat Mariage", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Accord légal qui établit les droits et les obligations entre deux personnes s'unissant en mariage.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType4, - archived_at: null, - name: "Livret de famille", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document officiel qui enregistre les détails et les événements familiaux tels que les mariages, les naissances et les décès d'un couple et de leurs enfants.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType16, - archived_at: null, - name: "Bail commercial", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Contrat légal entre un propriétaire et un locataire pour la location d'un bien immobilier utilisé à des fins commerciales ou professionnelles.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType5, - archived_at: null, - name: "Statuts SCI", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document légal qui définit les règles et les dispositions régissant la Société Civile Immobilière (SCI).", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType6, - archived_at: null, - name: "Avis de taxe foncière", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Notification officielle indiquant le montant de l'impôt foncier dû sur une propriété.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType7, - archived_at: null, - name: "Appel de charge de copropriété", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document envoyé aux copropriétaires pour les informer des dépenses et des charges communes liées à la gestion et à l'entretien de l'immeuble.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType8, - archived_at: null, - name: "PVAG", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Compte rendu écrit des discussions, décisions et résolutions prises lors d'une réunion d'assemblée générale de copropriété.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType9, - archived_at: null, - name: "Règlement de copropriété", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document juridique qui établit les règles et les droits des copropriétaires d'un immeuble en copropriété.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType10, - archived_at: null, - name: "Titre de propriété", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document légal qui atteste de la propriété d'un bien immobilier et en identifie le propriétaire.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType11, - archived_at: null, - name: "Plan et loi carrez", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document officiel qui mesure la superficie d'un lot ou d'un bien immobilier, conformément à la loi Carrez qui encadre les transactions immobilières.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType12, - archived_at: null, - name: "CNI", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document officiel d'identification délivré par l'État pour prouver l'identité et la nationalité d'une personne.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType13, - archived_at: null, - name: "Modifications règlement copropriété (plusieurs)", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Documents légaux qui apportent des changements ou des ajustements aux règles et dispositions du règlement de copropriété initial.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType14, - archived_at: null, - name: "Avis de décès", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Notification officielle délivrée par les autorités compétentes pour informer du décès d'une personne.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType15, - archived_at: null, - name: "Lettre de mission", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Document contractuel qui définit les termes et les objectifs d'une mission confiée à une personne ou à une entreprise.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType17, - archived_at: null, - name: "DPE", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "Diagnostic de Performance Energétique.", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentType18, - archived_at: null, - name: "RIB", - office_uid: uidOffice1, - private_description: "Ce document est confidentiel, et ne doit pas être divulgué", - public_description: "RIB.", - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const officeFolderHasCustomers: OfficeFolderHasCustomers[] = [ - { - uid: uidOfficeFolderHasCustomer1, - customer_uid: uidCustomer1, - office_folder_uid: uidOfficeFolder1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidOfficeFolderHasCustomer2, - customer_uid: uidCustomer2, - office_folder_uid: uidOfficeFolder2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidOfficeFolderHasCustomer3, - customer_uid: uidCustomer3, - office_folder_uid: uidOfficeFolder3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidOfficeFolderHasCustomer4, - customer_uid: uidCustomer4, - office_folder_uid: uidOfficeFolder4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidOfficeFolderHasCustomer5, - customer_uid: uidCustomer2, - office_folder_uid: uidOfficeFolder21, - created_at: new Date(), - updated_at: new Date(), - }, - - ]; - - const files: Files[] = [ - { - uid: uidFiles1, - document_uid: uidDocument1, - file_name: "fileName1", - file_path: "https://www.google1.com", - key: '', - archived_at: null, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidFiles2, - document_uid: uidDocument2, - file_name: "fileName1", - file_path: "https://www.google2.com", - key: '', - archived_at: null, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const deedHasDocumentTypes: DeedHasDocumentTypes[] = [ - { - uid: uidDeedHasDocumentType1, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType2, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType3, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType3, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType4, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType5, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType16, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType6, - deed_uid: uidDeed1, - document_type_uid: uidDocumentType5, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType7, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType6, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType8, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType7, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType9, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType8, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType10, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType9, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType11, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType12, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType11, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType13, - deed_uid: uidDeed2, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType19, - deed_uid: uidDeed3, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType20, - deed_uid: uidDeed3, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType21, - deed_uid: uidDeed3, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType22, - deed_uid: uidDeed3, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType23, - deed_uid: uidDeed3, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType14, - deed_uid: uidDeed4, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType15, - deed_uid: uidDeed4, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType26, - deed_uid: uidDeed4, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType27, - deed_uid: uidDeed4, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType28, - deed_uid: uidDeed4, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType29, - deed_uid: uidDeed5, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType30, - deed_uid: uidDeed5, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType31, - deed_uid: uidDeed5, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType32, - deed_uid: uidDeed5, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType33, - deed_uid: uidDeed5, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType34, - deed_uid: uidDeed6, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType35, - deed_uid: uidDeed6, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType36, - deed_uid: uidDeed6, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType37, - deed_uid: uidDeed6, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType38, - deed_uid: uidDeed6, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType39, - deed_uid: uidDeed7, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType40, - deed_uid: uidDeed7, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType41, - deed_uid: uidDeed7, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType42, - deed_uid: uidDeed7, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType43, - deed_uid: uidDeed7, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType44, - deed_uid: uidDeed8, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType45, - deed_uid: uidDeed8, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType46, - deed_uid: uidDeed8, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType47, - deed_uid: uidDeed8, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType48, - deed_uid: uidDeed8, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType49, - deed_uid: uidDeed9, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType50, - deed_uid: uidDeed9, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType51, - deed_uid: uidDeed9, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType16, - deed_uid: uidDeed9, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType17, - deed_uid: uidDeed9, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedHasDocumentType18, - deed_uid: uidDeed10, - document_type_uid: uidDocumentType14, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType24, - deed_uid: uidDeed10, - document_type_uid: uidDocumentType15, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType25, - deed_uid: uidDeed10, - document_type_uid: uidDocumentType4, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType52, - deed_uid: uidDeed10, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedHasDocumentType53, - deed_uid: uidDeed10, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - - - ]; - - const deedTypeHasDocumentTypes: DeedTypeHasDocumentTypes[] = [ - { - uid: uidDeedTypeHasDocumentType1, - deed_type_uid: uidDeedType1, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType2, - deed_type_uid: uidDeedType2, - document_type_uid: uidDocumentType2, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType3, - deed_type_uid: uidDeedType3, - document_type_uid: uidDocumentType3, - created_at: new Date(), - updated_at: new Date(), - }, - - { - uid: uidDeedTypeHasDocumentType4, - deed_type_uid: uidDeedType4, - document_type_uid: uidDocumentType1, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType5, - deed_type_uid: uidDeedType4, - document_type_uid: uidDocumentType6, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType6, - deed_type_uid: uidDeedType4, - document_type_uid: uidDocumentType10, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType7, - deed_type_uid: uidDeedType4, - document_type_uid: uidDocumentType17, - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDeedTypeHasDocumentType8, - deed_type_uid: uidDeedType4, - document_type_uid: uidDocumentType18, - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - const documentHistories: DocumentHistory[] = [ - { - uid: uidDocumentHistory1, - document_status: EDocumentStatus.ASKED, - document_uid: uidDocument1, - refused_reason: "", - created_at: new Date(), - updated_at: new Date(), - }, - { - uid: uidDocumentHistory2, - document_status: EDocumentStatus.DEPOSITED, - document_uid: uidDocument1, - refused_reason: "Le document n'est pas conforme", - created_at: new Date(), - updated_at: new Date(), - }, - ]; - - for (const address of addresses) { - await prisma.addresses.create({ data: address }); - } - - for (const contact of contacts) { - await prisma.contacts.create({ data: contact }); - } - - for (const office of offices) { - await prisma.offices.create({ data: office }); - } - - for (const user of users) { - await prisma.users.create({ data: user }); - } - - for (const customer of customers) { - await prisma.customers.create({ data: customer }); - } - - for (const deedType of deedTypes) { - await prisma.deedTypes.create({ data: deedType }); - } - - for (const deed of deeds) { - await prisma.deeds.create({ data: deed }); - } - for (const officeFolder of officeFolders) { - await prisma.officeFolders.create({ data: officeFolder }); - } - - for (const documentType of documentTypes) { - await prisma.documentTypes.create({ data: documentType }); - } - - for (const document of documents) { - await prisma.documents.create({ data: document }); - } - - for (const file of files) { - await prisma.files.create({ data: file }); - } - - for (const documentHistory of documentHistories) { - await prisma.documentHistory.create({ data: documentHistory }); - } - - for (const officeFolderHasCustomer of officeFolderHasCustomers) { - await prisma.officeFolderHasCustomers.create({ data: officeFolderHasCustomer }); - } - - for (const deedHasDocumentType of deedHasDocumentTypes) { - await prisma.deedHasDocumentTypes.create({ data: deedHasDocumentType }); - } - - for (const deedTypeHasDocumentType of deedTypeHasDocumentTypes) { - await prisma.deedTypeHasDocumentTypes.create({ data: deedTypeHasDocumentType }); - } - - console.log(">MOCK DATA - Seeding completed!"); -})(); diff --git a/src/common/emails/EmailBuilder.ts b/src/common/emails/EmailBuilder.ts new file mode 100644 index 00000000..b66c8238 --- /dev/null +++ b/src/common/emails/EmailBuilder.ts @@ -0,0 +1,50 @@ + +import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; +import { Documents } from "@prisma/client"; +import { Document } from "le-coffre-resources/dist/SuperAdmin"; +import { Service } from "typedi"; +import { ETemplates } from "./Templates/EmailTemplates"; +import MailchimpService from "@Services/common/MailchimpService/MailchimpService"; + +@Service() +export default class EmailBuilder { + public constructor(private mailchimpService: MailchimpService ,private documentsService: DocumentsService){} + + public async sendDocumentEmails(documentEntity: Documents){ + if(documentEntity.document_status !== "ASKED" && documentEntity.document_status !== "REFUSED") return; + + const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ office: true}} }); + if(!documentPrisma) throw new Error("Document not found"); + const document = Document.hydrate(documentPrisma); + const to = document.depositor!.contact!.email; + + const templateVariables = { + civility: document.depositor!.contact!.civility, + last_name: document.depositor!.contact!.last_name, + office_name: document.folder!.office!.name, + link: "http://localhost:3000" + }; + + let templateName = ETemplates.DOCUMENT_ASKED; + let subject = "Document Asked"; + if(documentEntity.document_status === "REFUSED"){ + templateName = ETemplates.DOCUMENT_REFUSED; + subject = "Document Refused"; + } + + this.mailchimpService.create({ + templateName, + to, + subject, + templateVariables, + uid: "", + from: null, + cc: [], + cci: [], + sentAt: null, + nbTrySend: null, + lastTrySendDate: null, + }); + + } +} diff --git a/src/common/emails/Templates/EmailTemplates.ts b/src/common/emails/Templates/EmailTemplates.ts new file mode 100644 index 00000000..28f7f6fc --- /dev/null +++ b/src/common/emails/Templates/EmailTemplates.ts @@ -0,0 +1,4 @@ +export const ETemplates = { + DOCUMENT_ASKED: "DOCUMENT_ASKED", + DOCUMENT_REFUSED: "DOCUMENT_REFUSED", +}; \ No newline at end of file diff --git a/src/common/repositories/AddressesRepository.ts b/src/common/repositories/AddressesRepository.ts deleted file mode 100644 index 7bd53e84..00000000 --- a/src/common/repositories/AddressesRepository.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Database from "@Common/databases/database"; -import BaseRepository from "@Repositories/BaseRepository"; -import { Service } from "typedi"; -import { Addresses } from "@prisma/client"; - -@Service() -export default class AddressesRepository extends BaseRepository { - constructor(private database: Database) { - super(); - } - protected get model() { - return this.database.getClient().addresses; - } - protected get instanceDb() { - return this.database.getClient(); - } - - /** - * @description : Find many addresses - */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); - return this.model.findMany(query); - } - - /** - * @description : Find one address - */ - public async findOneByUid(uid: string): Promise { - const addressEntity = await this.model.findUnique({ - where: { - uid: uid, - }, - }); - - if (!addressEntity) { - throw new Error("Address not found"); - } - - return addressEntity; - } -} diff --git a/src/common/repositories/AppointmentsRepository.ts b/src/common/repositories/AppointmentsRepository.ts new file mode 100644 index 00000000..62b74d34 --- /dev/null +++ b/src/common/repositories/AppointmentsRepository.ts @@ -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 { + 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 { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/repositories/ContactRepository.ts b/src/common/repositories/ContactRepository.ts new file mode 100644 index 00000000..8a3861ee --- /dev/null +++ b/src/common/repositories/ContactRepository.ts @@ -0,0 +1,29 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Contacts, Customers } from "@prisma/client"; + +@Service() +export default class ContactRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().contacts; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find unique customer by email + */ + public async findOneByEmail(email: string): Promise<(Contacts & {customers: Customers | null}) | null> { + return this.model.findUnique({ + where: { + email: email, + }, + include: { customers: true } + }); + } +} diff --git a/src/common/repositories/ContactsRepository.ts b/src/common/repositories/ContactsRepository.ts deleted file mode 100644 index b302d1f6..00000000 --- a/src/common/repositories/ContactsRepository.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Database from "@Common/databases/database"; -import BaseRepository from "@Repositories/BaseRepository"; -import { Service } from "typedi"; -import { Contacts } from "@prisma/client"; - -@Service() -export default class ContactsRepository extends BaseRepository { - constructor(private database: Database) { - super(); - } - protected get model() { - return this.database.getClient().contacts; - } - protected get instanceDb() { - return this.database.getClient(); - } - - /** - * @description : Find many contacts - */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); - return this.model.findMany(query); - } - - /** - * @description : Find unique contact - */ - public async findOneByUid(uid: string): Promise { - const contactEntity = await this.model.findUnique({ - where: { - uid: uid, - }, - }); - - if (!contactEntity) { - throw new Error("contact not found"); - } - - return contactEntity; - } -} diff --git a/src/common/repositories/CustomersRepository.ts b/src/common/repositories/CustomersRepository.ts index 4f846795..8a27293a 100644 --- a/src/common/repositories/CustomersRepository.ts +++ b/src/common/repositories/CustomersRepository.ts @@ -1,7 +1,7 @@ import Database from "@Common/databases/database"; import BaseRepository from "@Repositories/BaseRepository"; import { Service } from "typedi"; -import { Contacts, Customers, ECivility, ECustomerStatus, Prisma } from "@prisma/client"; +import { Customers, ECivility, ECustomerStatus, Prisma } from "@prisma/client"; import { Customer } from "le-coffre-resources/dist/SuperAdmin"; @Service() @@ -19,11 +19,7 @@ export default class CustomersRepository extends BaseRepository { /** * @description : Find many customers */ - public async findMany(query: Prisma.CustomersFindManyArgs): Promise< - (Customers & { - contact: Contacts; - })[] - > { + public async findMany(query: Prisma.CustomersFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); if (!query.include) return this.model.findMany({ ...query, include: { contact: true } }); return this.model.findMany({ ...query, include: { contact: { include: { address: true } } } }); @@ -50,12 +46,12 @@ export default class CustomersRepository extends BaseRepository { }, }; - if (customer.contact!.address) { + if (customer.contact?.address) { createArgs.data.contact!.create!.address = { create: { - address: customer.contact!.address!.address, - zip_code: customer.contact!.address!.zip_code, - city: customer.contact!.address!.city, + address: customer.contact?.address?.address, + zip_code: customer.contact?.address?.zip_code, + city: customer.contact?.address?.city, }, }; } @@ -98,20 +94,23 @@ export default class CustomersRepository extends BaseRepository { /** * @description : Find unique customer */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.CustomersFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.CustomersInclude) { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const customerEntity = await this.model.findUnique(findOneArgs); - if (!customerEntity) { - throw new Error("Customer not found"); - } + include: query, + }); + } - return customerEntity; + /** + * @description : Find unique customer + */ + public async findOneByContact(contactUid: string) { + return this.model.findUnique({ + where: { + contact_uid: contactUid, + }, + }); } } diff --git a/src/common/repositories/DeedTypesHasDocumentTypesRepository.ts b/src/common/repositories/DeedTypesHasDocumentTypesRepository.ts deleted file mode 100644 index 53cb40a7..00000000 --- a/src/common/repositories/DeedTypesHasDocumentTypesRepository.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Database from "@Common/databases/database"; -import { DeedTypeHasDocumentTypes } from "@prisma/client"; -import BaseRepository from "@Repositories/BaseRepository"; -import { Service } from "typedi"; - -@Service() -export default class DeedTypeHasDocumentTypesRepository extends BaseRepository { - constructor(private database: Database) { - super(); - } - protected get model() { - return this.database.getClient().deedTypeHasDocumentTypes; - } - protected get instanceDb() { - return this.database.getClient(); - } - - /** - * @description : Find many relations between deed type and a document type - */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); - return this.model.findMany(query); - } - - /** - * @description : Find unique relation between deed type and a document type - */ - public async findOneByUid(uid: string): Promise { - const deedTypeHasDoculmentTypesEntity = await this.model.findUnique({ - where: { - uid: uid, - }, - }); - - if (!deedTypeHasDoculmentTypesEntity) { - throw new Error("deed type not found"); - } - - return deedTypeHasDoculmentTypesEntity; - } -} diff --git a/src/common/repositories/DeedTypesRepository.ts b/src/common/repositories/DeedTypesRepository.ts index 6f38421d..43495cbe 100644 --- a/src/common/repositories/DeedTypesRepository.ts +++ b/src/common/repositories/DeedTypesRepository.ts @@ -19,7 +19,7 @@ export default class DeedTypesRepository extends BaseRepository { /** * @description : Find many deed types */ - public async findMany(query: any): Promise { + public async findMany(query: Prisma.DeedTypesFindManyArgs): Promise { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -39,17 +39,14 @@ export default class DeedTypesRepository extends BaseRepository { }, }, }; - if (deedType.deed_type_has_document_types) { - createArgs.data.deed_type_has_document_types = { - createMany: { - data: deedType.deed_type_has_document_types.map((relation) => ({ - document_type_uid: relation.document_type.uid!, - })), - skipDuplicates: true, - }, + if (deedType.document_types) { + createArgs.data.document_types = { + connect: deedType.document_types.map((documentType) => ({ + uid: documentType.uid, + })), }; } - return this.model.create(createArgs); + return this.model.create({ ...createArgs, include: { document_types: true } }); } /** @@ -64,48 +61,38 @@ export default class DeedTypesRepository extends BaseRepository { name: deedType.name, description: deedType.description, archived_at: deedType.archived_at, - office: { - connect: { - uid: deedType.office!.uid, - }, + document_types: { + set: deedType.document_types?.map((documentType) => ({ + uid: documentType.uid!, + })), }, }, - include: { - deed_type_has_document_types: true, - }, }; - if (deedType.deed_type_has_document_types) { - updateArgs.data.deed_type_has_document_types = { - deleteMany: { deed_type_uid: uid }, - createMany: { - data: deedType.deed_type_has_document_types.map((relation) => ({ - document_type_uid: relation.document_type.uid!, - })), - skipDuplicates: true, - }, - }; - } - return this.model.update(updateArgs); + + return this.model.update({ ...updateArgs, include: { document_types: true } }); } /** * @description : Find unique deed type */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.DeedTypesFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.DeedTypesInclude) { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const deedTypeEntity = await this.model.findUnique(findOneArgs); + include: query, + }); + } - if (!deedTypeEntity) { - throw new Error("deed type not found"); - } - - return deedTypeEntity; + /** + * @description : Find unique deed type with relations + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { office: true }, + }); } } diff --git a/src/common/repositories/DeedsHasDocumentTypesRepository.ts b/src/common/repositories/DeedsHasDocumentTypesRepository.ts deleted file mode 100644 index 65bac2c0..00000000 --- a/src/common/repositories/DeedsHasDocumentTypesRepository.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Database from "@Common/databases/database"; -import { DeedHasDocumentTypes } from "@prisma/client"; -import BaseRepository from "@Repositories/BaseRepository"; -import { Service } from "typedi"; - -@Service() -export default class DeedHasDocumentTypesRepository extends BaseRepository { - constructor(private database: Database) { - super(); - } - protected get model() { - return this.database.getClient().deedHasDocumentTypes; - } - protected get instanceDb() { - return this.database.getClient(); - } - - /** - * @description : Find many deeds - */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); - return this.model.findMany(query); - } - - /** - * @description : Find unique relation between deed and a document type - */ - public async findOneByUid(uid: string): Promise { - const deedHasDocumentTypesEntity = await this.model.findUnique({ - where: { - uid: uid, - }, - }); - - if (!deedHasDocumentTypesEntity) { - throw new Error("relation between deed and document type not found"); - } - - return deedHasDocumentTypesEntity; - } -} diff --git a/src/common/repositories/DeedsRepository.ts b/src/common/repositories/DeedsRepository.ts index 945a181d..bc86c149 100644 --- a/src/common/repositories/DeedsRepository.ts +++ b/src/common/repositories/DeedsRepository.ts @@ -19,7 +19,7 @@ export default class DeedsRepository extends BaseRepository { /** * @description : Find many users */ - public async findMany(query: any): Promise { + public async findMany(query: Prisma.DeedsFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -41,22 +41,19 @@ export default class DeedsRepository extends BaseRepository { where: { uid: deed.deed_type!.uid, }, - include: { deed_type_has_document_types: true }, + include: { document_types: true }, }); if (deedTypeWithDocumentTypes.archived_at) throw new Error("deed type is archived"); - if (deedTypeWithDocumentTypes.deed_type_has_document_types) { - createArgs.data.deed_has_document_types = { - createMany: { - data: deedTypeWithDocumentTypes.deed_type_has_document_types.map((relation) => ({ - document_type_uid: relation.document_type_uid, - })), - skipDuplicates: true, - }, + if (deedTypeWithDocumentTypes.document_types) { + createArgs.data.document_types = { + connect: deedTypeWithDocumentTypes.document_types.map((documentType) => ({ + uid: documentType.uid, + })), }; } - return this.model.create(createArgs); + return this.model.create({ ...createArgs, include: { document_types: true } }); } /** @@ -67,44 +64,45 @@ export default class DeedsRepository extends BaseRepository { where: { uid: uid, }, - data: {}, + data: { + document_types: { + set: deed.document_types?.map((documentType) => ({ + uid: documentType.uid!, + })), + }, + }, include: { - deed_has_document_types: true, + document_types: true, }, }; - - if (deed.deed_has_document_types) { - updateArgs.data.deed_has_document_types = { - deleteMany: { deed_uid: uid }, - createMany: { - data: deed.deed_has_document_types.map((relation) => ({ - document_type_uid: relation.document_type.uid!, - })), - skipDuplicates: true, - }, - }; - } - return this.model.update(updateArgs); + + return this.model.update({ ...updateArgs, include: { document_types: true } }); } /** * @description : Find unique deed */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.DeedsFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.DeedsInclude): Promise { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const deedTypeEntity = await this.model.findUnique(findOneArgs); + include: query, + }); + } - if (!deedTypeEntity) { - throw new Error("deed not found"); - } - - return deedTypeEntity; + /** + * @description : Find unique deed + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { + deed_type: { include: { office: true } }, + document_types: { include: { office: true } }, + }, + }); } } diff --git a/src/common/repositories/DocumentTypesRepository.ts b/src/common/repositories/DocumentTypesRepository.ts index e9cb3fef..a8b3ad3f 100644 --- a/src/common/repositories/DocumentTypesRepository.ts +++ b/src/common/repositories/DocumentTypesRepository.ts @@ -19,7 +19,7 @@ export default class DocumentTypesRepository extends BaseRepository { /** * @description : Find many document types */ - public async findMany(query: any): Promise { + public async findMany(query: Prisma.DocumentTypesFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -28,7 +28,7 @@ export default class DocumentTypesRepository extends BaseRepository { * @description : Create a document type */ public async create(documentType: DocumentType): Promise { - return this.model.create({ + const createArgs: Prisma.DocumentTypesCreateArgs = { data: { name: documentType.name, public_description: documentType.public_description, @@ -39,14 +39,15 @@ export default class DocumentTypesRepository extends BaseRepository { }, }, }, - }); + }; + return this.model.create(createArgs); } /** * @description : update given document type */ public async update(uid: string, documentType: DocumentType): Promise { - return this.model.update({ + const updateArgs: Prisma.DocumentTypesUpdateArgs = { where: { uid: uid, }, @@ -55,33 +56,33 @@ export default class DocumentTypesRepository extends BaseRepository { public_description: documentType.public_description, private_description: documentType.private_description, archived_at: documentType.archived_at, - office: { - connect: { - uid: documentType.office!.uid, - }, - }, }, - }); + }; + + return this.model.update(updateArgs); } /** * @description : find unique document type */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.DocumentTypesFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.DocumentTypesInclude) { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const documentTypeEntity = await this.model.findUnique(findOneArgs); + include: query, + }); + } - if (!documentTypeEntity) { - throw new Error("Document Type not found"); - } - - return documentTypeEntity; + /** + * @description : Find unique document type with relations + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { office: true }, + }); } } diff --git a/src/common/repositories/DocumentsRepository.ts b/src/common/repositories/DocumentsRepository.ts index 1e1aa340..c5110e6d 100644 --- a/src/common/repositories/DocumentsRepository.ts +++ b/src/common/repositories/DocumentsRepository.ts @@ -3,6 +3,7 @@ import BaseRepository from "@Repositories/BaseRepository"; import { Service } from "typedi"; import { Documents, EDocumentStatus, Prisma } from "@prisma/client"; import { Document } from "le-coffre-resources/dist/SuperAdmin"; +import { Document as DocumentCustomer } from "le-coffre-resources/dist/Customer"; @Service() export default class DocumentsRepository extends BaseRepository { @@ -19,7 +20,7 @@ export default class DocumentsRepository extends BaseRepository { /** * @description : Find many documents */ - public async findMany(query: any): Promise { + public async findMany(query: Prisma.DocumentsFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -28,7 +29,7 @@ export default class DocumentsRepository extends BaseRepository { * @description : Create a document */ public async create(document: Document): Promise { - const documentCreated = await this.model.create({ + const createArgs: Prisma.DocumentsCreateArgs = { data: { folder: { connect: { @@ -46,7 +47,9 @@ export default class DocumentsRepository extends BaseRepository { }, }, }, - }); + }; + + const documentCreated = await this.model.create({ ...createArgs, include: { document_type: true } }); await this.instanceDb.documentHistory.create({ data: { @@ -64,21 +67,35 @@ export default class DocumentsRepository extends BaseRepository { /** * @description : Create many documents linked to an office folder */ - public async createMany(documents: Document[]): Promise { - return this.model.createMany({ + public async createMany(documents: Document[]): Promise { + const createArgs: Prisma.DocumentsCreateManyArgs = { data: documents.map((document) => ({ folder_uid: document.folder!.uid!, depositor_uid: document.depositor!.uid!, document_type_uid: document.document_type!.uid!, })), skipDuplicates: true, - }); + }; + + const batchPayload = await this.model.createMany(createArgs); + + const documentsCreated = await this.model.findMany({ orderBy: { created_at: "desc" }, take: batchPayload.count }); + + const createHistoryArgs: Prisma.DocumentHistoryCreateManyArgs = { + data: documentsCreated.map((document) => ({ + document_uid: document.uid!, + })), + skipDuplicates: true, + }; + await this.instanceDb.documentHistory.createMany(createHistoryArgs); + + return documentsCreated; } /** * @description : Update data of a document */ - public async update(uid: string, document: Document, refusedReason?: string): Promise { + public async update(uid: string, document: Partial, refusedReason?: string): Promise { return this.model.update({ where: { uid: uid, @@ -90,7 +107,7 @@ export default class DocumentsRepository extends BaseRepository { document_status: EDocumentStatus[document.document_status as keyof typeof EDocumentStatus], refused_reason: refusedReason, }, - } + }, }, }); } @@ -109,20 +126,24 @@ export default class DocumentsRepository extends BaseRepository { /** * @description : Find unique document */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.DocumentsFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.DocumentsInclude): Promise { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const documentEntity = await this.model.findUnique(findOneArgs); - if (!documentEntity) { - throw new Error("Document not found"); - } + include: query, + }); + } - return documentEntity; + /** + * @description : Find unique document with relations + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { folder: { include: { office: true } }, document_type: { include: { office: true } } }, + }); } } diff --git a/src/common/repositories/EmailRepository.ts b/src/common/repositories/EmailRepository.ts new file mode 100644 index 00000000..82c9fa0f --- /dev/null +++ b/src/common/repositories/EmailRepository.ts @@ -0,0 +1,75 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Emails, Prisma } from "prisma/prisma-client"; + +@Service() +export default class EmailRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().emails; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many emails + */ + public async findMany(query: Prisma.EmailsFindManyArgs) { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Create an email + */ + public async create(email: Emails): Promise { + const createArgs: Prisma.EmailsCreateArgs = { + data: { + templateName: email.templateName, + from: email.from, + to: email.to, + subject: email.subject, + templateVariables: email.templateVariables!, + cc: email.cc, + cci: email.cci, + }, + }; + return this.model.create(createArgs); + } + + /** + * @description : update given email + */ + public async update(uid: string, email: Emails): Promise { + const updateArgs: Prisma.EmailsUpdateArgs = { + where: { + uid: uid, + }, + data: { + sentAt: email.sentAt, + nbTrySend: email.nbTrySend, + lastTrySendDate: email.lastTrySendDate, + }, + }; + + return this.model.update(updateArgs); + } + + /** + * @description : find unique email + */ + public async findOneByUid(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + }); + } + + + +} diff --git a/src/common/repositories/FilesRepository.ts b/src/common/repositories/FilesRepository.ts index 34f2f89c..02776bdf 100644 --- a/src/common/repositories/FilesRepository.ts +++ b/src/common/repositories/FilesRepository.ts @@ -1,7 +1,7 @@ import Database from "@Common/databases/database"; import BaseRepository from "@Repositories/BaseRepository"; import { Service } from "typedi"; -import { Files } from "@prisma/client"; +import { Files, Prisma } from "@prisma/client"; import { File } from "le-coffre-resources/dist/SuperAdmin"; @Service() @@ -19,7 +19,7 @@ export default class FilesRepository extends BaseRepository { /** * @description : Find many files */ - public async findMany(query: any): Promise { + public async findMany(query: Prisma.FilesFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -28,7 +28,7 @@ export default class FilesRepository extends BaseRepository { * @description : Create a file linked to a document */ public async create(file: File, key: string): Promise { - return this.model.create({ + const createArgs: Prisma.FilesCreateArgs = { data: { document: { connect: { @@ -37,55 +37,82 @@ export default class FilesRepository extends BaseRepository { }, file_name: file.file_name, file_path: file.file_path, - key: key + mimetype: file.mimetype, + size: file.size, + key: key, }, - include: { document: true } - }); + }; + return this.model.create({ ...createArgs, include: { document: true } }); } /** * @description : Update data of a file */ - public async update(uid: string, file: File): Promise { - return this.model.update({ + public async update(uid: string, file: File, key: string): Promise { + const updateArgs: Prisma.FilesUpdateArgs = { where: { uid: uid, }, data: { + file_name: file.file_name, file_path: file.file_path, + mimetype: file.mimetype, + size: file.size, + key: key, }, - }); + }; + return this.model.update({ ...updateArgs, include: { document: true } }); } /** - * @description : Delete a file + * @description : Delete a file key and archive */ - public async delete(uid: string): Promise { - return this.model.update({ + public async deleteKeyAndArchive(uid: string): Promise { + const updateArgs: Prisma.FilesUpdateArgs = { where: { uid: uid, }, data: { key: null, - archived_at: new Date(Date.now()) - } - }); + archived_at: new Date(Date.now()), + }, + }; + return this.model.update({ ...updateArgs, include: { document: true } }); } /** * @description : Find unique file */ - public async findOneByUid(uid: string): Promise { - const fileEntity = await this.model.findUnique({ + public async findOneByUid(uid: string, query?: Prisma.FilesInclude) { + return this.model.findUnique({ where: { uid: uid, }, + include: query, }); + } - if (!fileEntity) { - throw new Error("File not found"); - } + /** + * @description : Find unique file with office + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { document: { include: { folder: { include: { office: true } } } } }, + }); + } - return fileEntity; + /** + * @description : Find unique file with document + */ + public async findOneByUidWithDocument(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { document: true }, + }); } } diff --git a/src/common/repositories/OfficeFoldersHasCustomerRepository.ts b/src/common/repositories/OfficeFoldersHasCustomerRepository.ts deleted file mode 100644 index 2d4b403d..00000000 --- a/src/common/repositories/OfficeFoldersHasCustomerRepository.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Database from "@Common/databases/database"; -import { OfficeFolderHasCustomers } from "@prisma/client"; -import BaseRepository from "@Repositories/BaseRepository"; -import { Service } from "typedi"; - -@Service() -export default class OfficeFoldersHasCustomerRepository extends BaseRepository { - constructor(private database: Database) { - super(); - } - protected get model() { - return this.database.getClient().officeFolderHasCustomers; - } - protected get instanceDb() { - return this.database.getClient(); - } - - /** - * @description : Find many relations - */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); - return this.model.findMany(query); - } - - /** - * @description : Find a unique relation between an office folder and customers - */ - public async findOneByUid(uid: string): Promise { - const officeFolderHasCustomersEntity = await this.model.findUnique({ - where: { - uid: uid, - }, - }); - - if (!officeFolderHasCustomersEntity) { - throw new Error("relation between office folder and customer not found"); - } - - return officeFolderHasCustomersEntity; - } -} diff --git a/src/common/repositories/OfficeFoldersHasStakeholderRepository.ts b/src/common/repositories/OfficeFoldersHasStakeholderRepository.ts deleted file mode 100644 index 02b2bb11..00000000 --- a/src/common/repositories/OfficeFoldersHasStakeholderRepository.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Database from "@Common/databases/database"; -import { OfficeFolderHasStakeholders } from "@prisma/client"; -import BaseRepository from "@Repositories/BaseRepository"; -import { Service } from "typedi"; - -@Service() -export default class OfficeFoldersHasStakeholderRepository extends BaseRepository { - constructor(private database: Database) { - super(); - } - protected get model() { - return this.database.getClient().officeFolderHasStakeholders; - } - protected get instanceDb() { - return this.database.getClient(); - } - - /** - * @description : Find many relations - */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); - return this.model.findMany(query); - } - - /** - * @description : Find a unique relation between an office folder and stakeholders - */ - public async findOneByUid(uid: string): Promise { - const officeFolderHasStakeholdersEntity = await this.model.findUnique({ - where: { - uid: uid, - }, - }); - - if (!officeFolderHasStakeholdersEntity) { - throw new Error("relation between office folder and stakeholder not found"); - } - - return officeFolderHasStakeholdersEntity; - } -} diff --git a/src/common/repositories/OfficeFoldersRepository.ts b/src/common/repositories/OfficeFoldersRepository.ts index 18f6e894..d391ef92 100644 --- a/src/common/repositories/OfficeFoldersRepository.ts +++ b/src/common/repositories/OfficeFoldersRepository.ts @@ -19,7 +19,7 @@ export default class OfficeFoldersRepository extends BaseRepository { /** * @description : Find many office folders */ - public async findMany(query: any): Promise { + public async findMany(query: Prisma.OfficeFoldersFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -36,7 +36,7 @@ export default class OfficeFoldersRepository extends BaseRepository { status: EFolderStatus.LIVE, deed: { connect: { - uid: officeFolder.deed?.uid + uid: officeFolder.deed?.uid, }, }, office: { @@ -44,22 +44,15 @@ export default class OfficeFoldersRepository extends BaseRepository { uid: officeFolder.office!.uid, }, }, - }, - include: { - office_folder_has_stakeholder: true, + stakeholders: { + connect: officeFolder.stakeholders?.map((stakeholder) => ({ + uid: stakeholder.uid!, + })), + }, }, }; - if (officeFolder.office_folder_has_stakeholder) { - createArgs.data.office_folder_has_stakeholder = { - createMany: { - data: officeFolder.office_folder_has_stakeholder.map((relation) => ({ - user_stakeholder_uid: relation.user_stakeholder.uid!, - })), - skipDuplicates: true, - }, - }; - } - return this.model.create(createArgs); + + return this.model.create({ ...createArgs, include: { stakeholders: true } }); } /** @@ -76,68 +69,56 @@ export default class OfficeFoldersRepository extends BaseRepository { description: officeFolder.description, status: EFolderStatus[officeFolder.status as keyof typeof EFolderStatus], archived_description: officeFolder.archived_description, - }, - include: { - office_folder_has_stakeholder: true, - office_folder_has_customers: true, - documents: true, + stakeholders: { + set: officeFolder.stakeholders?.map((stakeholder) => ({ + uid: stakeholder.uid!, + })), + }, + customers: { + set: officeFolder.customers?.map((customer) => ({ + uid: customer.uid!, + })), + }, + documents: { + set: officeFolder.documents?.map((document) => ({ + uid: document.uid!, + })), + }, }, }; - if (officeFolder.office_folder_has_stakeholder) { - updateArgs.data.office_folder_has_stakeholder = { - deleteMany: { office_folder_uid: officeFolderuid }, - createMany: { - data: officeFolder.office_folder_has_stakeholder.map((relation) => ({ - user_stakeholder_uid: relation.user_stakeholder.uid!, - })), - skipDuplicates: true, - }, - }; - } - if (officeFolder.office_folder_has_customers) { - updateArgs.data.office_folder_has_customers = { - deleteMany: { office_folder_uid: officeFolderuid }, - createMany: { - data: officeFolder.office_folder_has_customers.map((relation) => ({ - customer_uid: relation.customer.uid!, - })), - skipDuplicates: true, - }, - }; - } - if (officeFolder.documents) { - updateArgs.data.documents = { - createMany: { - data: officeFolder.documents.map((relation) => ({ - document_type_uid: relation.document_type!.uid!, - depositor_uid: relation.depositor!.uid!, - })), - skipDuplicates: true, - }, - }; - } - return this.model.update(updateArgs); + + return this.model.update({ + ...updateArgs, + include: { + stakeholders: true, + customers: true, + documents: true, + }, + }); } /** * @description : Find one office folder */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.OfficeFoldersFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.OfficeFoldersInclude) { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const officeFolderEntity = await this.model.findUnique(findOneArgs); + include: query, + }); + } - if (!officeFolderEntity) { - throw new Error("office folder not found"); - } - - return officeFolderEntity; + /** + * @description : Find one office folder + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { office: true }, + }); } /** diff --git a/src/common/repositories/OfficeRolesRepository.ts b/src/common/repositories/OfficeRolesRepository.ts new file mode 100644 index 00000000..f96a9926 --- /dev/null +++ b/src/common/repositories/OfficeRolesRepository.ts @@ -0,0 +1,105 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { OfficeRoles, Prisma } from "@prisma/client"; +import { OfficeRole } from "le-coffre-resources/dist/SuperAdmin"; + +@Service() +export default class OfficeRolesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().officeRoles; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many officeRoles + */ + public async findMany(query: Prisma.OfficeRolesFindManyArgs) { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Create new officeRole with rules + */ + public async create(officeRole: OfficeRole): Promise { + const createArgs: Prisma.OfficeRolesCreateArgs = { + data: { + name: officeRole.name, + office: { + connect: { + uid: officeRole.office.uid, + }, + }, + rules: { + connect: officeRole.rules?.map((rule) => ({ + uid: rule.uid!, + })), + }, + }, + }; + + return this.model.create({ ...createArgs, include: { rules: true } }); + } + + /** + * @description : Update data of a officeRole with rules + */ + public async update(officeRole: OfficeRole): Promise { + const updateArgs: Prisma.OfficeRolesUpdateArgs = { + where: { + uid: officeRole.uid, + }, + data: { + name: officeRole.name, + rules: { + set: officeRole.rules?.map((rule) => ({ + uid: rule.uid!, + })), + }, + }, + }; + + return this.model.update({ ...updateArgs, include: { rules: true } }); + } + + /** + * @description : Find one officeRole + */ + public async findOneByUid(uid: string, query?: Prisma.OfficeRolesInclude) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: query, + }); + } + + /** + * @description : Find one officeRole with office + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { office: true }, + }); + } + + /** + * @description : Delete a officeRole + */ + public async delete(uid: string): Promise { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/repositories/OfficesRepository.ts b/src/common/repositories/OfficesRepository.ts index 7595a1f5..cdc85202 100644 --- a/src/common/repositories/OfficesRepository.ts +++ b/src/common/repositories/OfficesRepository.ts @@ -19,8 +19,10 @@ export default class OfficesRepository extends BaseRepository { /** * @description : Find many users */ - public async findMany(query: any): Promise { - query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + public async findMany(query: Prisma.OfficesFindManyArgs) { + if(query){ + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + } return this.model.findMany(query); } @@ -29,7 +31,7 @@ export default class OfficesRepository extends BaseRepository { * @description : Create an office */ public async create(office: OfficeRessource): Promise { - return this.model.create({ + const createArgs: Prisma.OfficesCreateArgs = { data: { idNot: office.idNot, name: office.name, @@ -43,14 +45,15 @@ export default class OfficesRepository extends BaseRepository { }, office_status: EOfficeStatus.DESACTIVATED, }, - }); + }; + return this.model.create(createArgs); } /** * @description : Update data from an office */ public async update(uid: string, office: OfficeRessource): Promise { - return this.model.update({ + const updateArgs: Prisma.OfficesUpdateArgs = { where: { uid: uid, }, @@ -65,27 +68,29 @@ export default class OfficesRepository extends BaseRepository { }, office_status: EOfficeStatus[office.office_status as keyof typeof EOfficeStatus], }, + }; + return this.model.update(updateArgs); + } + + /** + * @description : Find one office + */ + public async findOneByUid(uid: string, query?: Prisma.OfficesInclude) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: query, }); } /** * @description : Find one office */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.OfficesFindUniqueArgs = { - where: { - uid: uid, - }, - }; - if (query) { - findOneArgs.include = query; - } - const officeEntity = await this.model.findUnique(findOneArgs); - - if (!officeEntity) { - throw new Error("office not found"); - } - - return officeEntity; + public async findOneByProvider(providerName: string, id: string, query?: Prisma.OfficesInclude) { + return this.model.findUnique({ + where: { [providerName]: id }, + include: query, + }); } } diff --git a/src/common/repositories/RolesRepository.ts b/src/common/repositories/RolesRepository.ts new file mode 100644 index 00000000..5467f0a0 --- /dev/null +++ b/src/common/repositories/RolesRepository.ts @@ -0,0 +1,90 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Roles, Prisma } from "@prisma/client"; +import { Role } from "le-coffre-resources/dist/SuperAdmin"; + +@Service() +export default class RolesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().roles; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many roles + */ + public async findMany(query: Prisma.RolesFindManyArgs) { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Create new role with rules + */ + public async create(role: Role): Promise { + const createArgs: Prisma.RolesCreateArgs = { + data: { + name: role.name, + label: role.label, + rules: { + connect: role.rules?.map((rule) => ({ + uid: rule.uid!, + })), + }, + }, + }; + + return this.model.create(createArgs); + } + + /** + * @description : Update data of a role with rules + */ + public async update(role: Role): Promise { + const updateArgs: Prisma.RolesUpdateArgs = { + where: { + uid: role.uid, + }, + data: { + name: role.name, + label: role.label, + rules: { + set: role.rules?.map((rule) => ({ + uid: rule.uid!, + })), + }, + }, + }; + + return this.model.update(updateArgs); + } + + /** + * @description : Find one role + */ + public async findOneByUid(uid: string, query?: Prisma.RolesInclude) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: query, + }); + } + + /** + * @description : Delete a role + */ + public async delete(uid: string): Promise { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/repositories/RulesRepository.ts b/src/common/repositories/RulesRepository.ts new file mode 100644 index 00000000..281e505b --- /dev/null +++ b/src/common/repositories/RulesRepository.ts @@ -0,0 +1,80 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Rules, Prisma } from "@prisma/client"; +import { Rule } from "le-coffre-resources/dist/SuperAdmin"; + +@Service() +export default class RulesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().rules; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many rules + */ + public async findMany(query: Prisma.RulesFindManyArgs) { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Create new rule + */ + public async create(rule: Rule): Promise { + const createArgs: Prisma.RulesCreateArgs = { + data: { + name: rule.name, + label: rule.label + }, + }; + + return this.model.create(createArgs); + } + + /** + * @description : Update data of a rule + */ + public async update(rule: Rule): Promise { + const updateArgs: Prisma.RulesUpdateArgs = { + where: { + uid: rule.uid, + }, + data: { + name: rule.name, + label: rule.label + }, + }; + + return this.model.update(updateArgs); + } + + /** + * @description : Find one rule + */ + public async findOneByUid(uid: string, query?: Prisma.RulesInclude) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: query, + }); + } + + /** + * @description : Delete a rule + */ + public async delete(uid: string): Promise { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/repositories/UsersRepository.ts b/src/common/repositories/UsersRepository.ts index b7643e18..739aea8f 100644 --- a/src/common/repositories/UsersRepository.ts +++ b/src/common/repositories/UsersRepository.ts @@ -1,8 +1,8 @@ import Database from "@Common/databases/database"; import BaseRepository from "@Repositories/BaseRepository"; import { Service } from "typedi"; -import { Addresses, Contacts, ECivility, Offices, Prisma, Users } from "@prisma/client"; -import User from "le-coffre-resources/dist/SuperAdmin"; +import { ECivility, Prisma, Users } from "@prisma/client"; +import User, { Role } from "le-coffre-resources/dist/SuperAdmin"; @Service() export default class UsersRepository extends BaseRepository { @@ -19,7 +19,7 @@ export default class UsersRepository extends BaseRepository { /** * @description : Find many users */ - public async findMany(query: Prisma.UsersFindManyArgs): Promise { + public async findMany(query: Prisma.UsersFindManyArgs) { query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); return this.model.findMany(query); } @@ -55,10 +55,14 @@ export default class UsersRepository extends BaseRepository { first_name: user.contact!.first_name, last_name: user.contact!.last_name, email: user.contact!.email, - phone_number: user.contact!.phone_number, + phone_number: user.contact?.phone_number, cell_phone_number: user.contact!.cell_phone_number, - civility: ECivility[user.contact!.civility as keyof typeof ECivility], - address: {}, + civility: ECivility[user.contact?.civility as keyof typeof ECivility], + }, + }, + role: { + connect: { + uid: user.role!.uid, }, }, }, @@ -70,89 +74,152 @@ export default class UsersRepository extends BaseRepository { city: user.contact!.address.city, }; } - return this.model.create({ ...createArgs, include: { contact: true, office_membership: { include: { address: true } } } }); + if (user.office_role) { + createArgs.data.office_role = { + connect: { + uid: user.office_role.uid, + }, + }; + } + return this.model.create(createArgs); } /** * @description : Update data from a user */ - public async update( - uid: string, - user: User, - ): Promise< - Users & { - contact: Contacts; - office_membership: Offices & { - address: Addresses; - }; - } - > { + + public async update(uid: string, user: User): Promise { const updateArgs: Prisma.UsersUpdateArgs = { where: { uid: uid, }, data: { idNot: user.idNot, - office_membership: { - connectOrCreate: { - where: { - idNot: user.office_membership!.idNot, - }, - create: { - idNot: user.office_membership!.idNot, - name: user.office_membership!.name, - crpcen: user.office_membership!.crpcen, - address: { - create: { - address: user.office_membership!.address!.address, - zip_code: user.office_membership!.address!.zip_code, - city: user.office_membership!.address!.city, - }, - }, - }, - }, - }, contact: { update: { - first_name: user.contact!.first_name, - last_name: user.contact!.last_name, - email: user.contact!.email, - phone_number: user.contact!.phone_number, - cell_phone_number: user.contact!.cell_phone_number, - civility: ECivility[user.contact!.civility as keyof typeof ECivility], - address: {}, + first_name: user.contact?.first_name, + last_name: user.contact?.last_name, + email: user.contact?.email, + phone_number: user.contact?.phone_number, + cell_phone_number: user.contact?.cell_phone_number, + civility: ECivility[user.contact?.civility as keyof typeof ECivility], }, }, }, }; - if (user.contact!.address) { - updateArgs.data.contact!.update!.address!.update = { - address: user.contact!.address!.address, - zip_code: user.contact!.address!.zip_code, - city: user.contact!.address!.city, + + if(user.office_membership) { + updateArgs.data.office_membership = { + connect: { + idNot: user.office_membership?.idNot, + }, }; } + + if (user.contact?.address) { + updateArgs.data.contact!.update!.address!.update = { + address: user.contact?.address?.address, + zip_code: user.contact?.address?.zip_code, + city: user.contact?.address?.city, + }; + } + + if(user.office_role) { + updateArgs.data.office_role = { + connect: { + uid: user.office_role.uid, + }, + }; + } + + if(user.role) { + updateArgs.data.role = { + connect: { + uid: user.role.uid, + }, + }; + } + + return this.model.update({ ...updateArgs, include: { contact: true, office_membership: { include: { address: true } } } }); + } + + /** + * @description : Update role from a user + */ + public async updateRole(uid: string, user: User): Promise { + const updateArgs: Prisma.UsersUpdateArgs = { + where: { + uid: uid, + }, + data: {} + }; + + if(user.office_role) { + updateArgs.data.office_role = { + connect: { + uid: user.office_role.uid, + }, + }; + } + + if(user.role) { + updateArgs.data.role = { + connect: { + uid: user.role.uid, + }, + }; + } + return this.model.update({ ...updateArgs, include: { contact: true, office_membership: { include: { address: true } } } }); } /** * @description : Find one user */ - public async findOneByUid(uid: string, query?: any): Promise { - const findOneArgs: Prisma.UsersFindUniqueArgs = { + public async findOneByUid(uid: string, query?: Prisma.UsersInclude): Promise { + return this.model.findUnique({ where: { uid: uid, }, - }; - if (query) { - findOneArgs.include = query; - } - const userEntity = await this.model.findUnique(findOneArgs); + include: query, + }); + } - if (!userEntity) { - throw new Error("User not found"); - } + /** + * @description : Find one user with office + */ + public async findOneByUidWithOffice(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { office_membership: true }, + }); + } - return userEntity; + /** + * @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 + */ + public async findOneByProvider(providerName: string, id: string) { + return this.model.findUnique({ + where: { [providerName]: id }, + include: { + role: { include: { rules: true } }, + office_role: { include: { rules: true } }, + office_membership: true, + }, + }); } } diff --git a/src/common/repositories/VotesRepository.ts b/src/common/repositories/VotesRepository.ts new file mode 100644 index 00000000..a9bf7746 --- /dev/null +++ b/src/common/repositories/VotesRepository.ts @@ -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 { + 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 { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: query, + }); + } + + /** + * @description : delete a vote + */ + public async delete(uid: string): Promise { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/system/OpenIdInterface.ts b/src/common/system/OpenIdInterface.ts new file mode 100644 index 00000000..997a903e --- /dev/null +++ b/src/common/system/OpenIdInterface.ts @@ -0,0 +1,30 @@ +export type Payload = { + sub: string; + email: string; +}; + +export type Tokens = { + access_token: string; + expires_in: number; + id_token: string; + token_type: string; +}; + +export type OpenIdConfig = { + authorization_endpoint: string; + token_endpoint: string; + userinfo_endpoint: string; + claims_supported: string[]; + end_session_endpoint: string; + grant_types_supported: string[]; + response_types_supported: string[]; + scopes_supported: string[]; + issuer: string; + jwks_uri: string; +}; + +export default interface OpenIdInterface { + getOpenIdConfig(): Promise; + verifyIdToken(signingKey: string): Promise; + getSigningKeys(jwksUri: string): Promise; +} diff --git a/src/common/system/controller-pattern/BaseController.ts b/src/common/system/controller-pattern/BaseController.ts index 3b128b1f..39bd4be7 100644 --- a/src/common/system/controller-pattern/BaseController.ts +++ b/src/common/system/controller-pattern/BaseController.ts @@ -20,15 +20,23 @@ export default abstract class BaseController { return this.httpResponse(response, HttpCodes.BAD_REQUEST, responseData); } + protected httpValidationError(response: Response, responseData: IResponseData = "Http Validation Error") { + return this.httpResponse(response, HttpCodes.VALIDATION_ERROR, responseData); + } + protected httpNotFoundRequest(response: Response, responseData: IResponseData = "Not Found") { return this.httpResponse(response, HttpCodes.NOT_FOUND, responseData); } - protected httpInternaleError(response: Response, responseData: IResponseData = "http Internal Server Error") { + protected httpInternalError(response: Response, responseData: IResponseData = "http Internal Server Error") { return this.httpResponse(response, HttpCodes.INTERNAL_ERROR, responseData); } - protected httpNotImplemented(response: Response, responseData: IResponseData = "http Internal Server Error") { + protected httpUnauthorized(response: Response, responseData: IResponseData = "http Unauthorized Request") { + return this.httpResponse(response, HttpCodes.UNAUTHORIZED, responseData); + } + + protected httpNotImplemented(response: Response, responseData: IResponseData = "Not implemented") { return this.httpResponse(response, HttpCodes.NOT_IMPLEMENTED, responseData); } diff --git a/src/common/system/controller-pattern/HttpCodes.ts b/src/common/system/controller-pattern/HttpCodes.ts index 8ca2500b..648c30b1 100644 --- a/src/common/system/controller-pattern/HttpCodes.ts +++ b/src/common/system/controller-pattern/HttpCodes.ts @@ -2,9 +2,11 @@ enum HttpCodes { SUCCESS = 200, CREATED = 201, BAD_REQUEST = 400, + VALIDATION_ERROR = 409, INTERNAL_ERROR = 500, UNKNOWN_ERROR = 520, NOT_IMPLEMENTED = 501, NOT_FOUND = 404, + UNAUTHORIZED = 401, } export default HttpCodes; diff --git a/src/common/system/database/DbProvider.ts b/src/common/system/database/DbProvider.ts index fa640f45..c84b75e9 100644 --- a/src/common/system/database/DbProvider.ts +++ b/src/common/system/database/DbProvider.ts @@ -9,7 +9,7 @@ dotenv.config(); export default class DbProvider { protected readonly variables = Container.get(BackendVariables); - protected url = `postgres://${this.variables.DATABASE_USERNAME}:${this.variables.DATABASE_PASSWORD}@${this.variables.DATABASE_HOST}:${this.variables.DATABASE_PORT}/${this.variables.DATABASE_NAME}`; + protected url = this.variables.DATABASE_URL; protected client = new PrismaClient({ datasources: { db: { diff --git a/src/entries/App.ts b/src/entries/App.ts index da76f6ae..ab68ded6 100644 --- a/src/entries/App.ts +++ b/src/entries/App.ts @@ -5,25 +5,29 @@ import ExpressServer from "@Common/system/ExpressServer"; import routes from "@App/index"; import cors from "cors"; import bodyParser from "body-parser"; -// import TezosLink from "@Common/databases/TezosLink"; import errorHandler from "@App/middlewares/ErrorHandler"; import { BackendVariables } from "@Common/config/variables/Variables"; -import fileHandler from "@App/middlewares/FileHandler"; +import multer from "multer"; + +const storage = multer.memoryStorage(); (async () => { try { const variables = await Container.get(BackendVariables).validate(); - const port = variables.APP_PORT; const rootUrl = variables.APP_ROOT_URL; const label = variables.APP_LABEL ?? "Unknown Service"; - // Container.get(TezosLink).connect(); Container.get(ExpressServer).init({ label, port: parseInt(port), rootUrl, - middlwares: [cors({ origin: "*" }), fileHandler, bodyParser.urlencoded({ extended: true }), bodyParser.json()], + middlwares: [ + cors({ origin: "*" }), + multer({ storage: storage }).single("file"), + bodyParser.urlencoded({ extended: true }), + bodyParser.json(), + ], errorHandler, }); diff --git a/src/entries/Cron.ts b/src/entries/Cron.ts new file mode 100644 index 00000000..3ca7e3df --- /dev/null +++ b/src/entries/Cron.ts @@ -0,0 +1,16 @@ +import "module-alias/register"; +import "reflect-metadata"; +import { Container } from "typedi"; +import { BackendVariables } from "@Common/config/variables/Variables"; +import CronService from "@Services/common/CronService/CronService"; + +(async () => { + try { + const variables = await Container.get(BackendVariables).validate(); + if(variables.ENV === "stg"){ + Container.get(CronService).sendMails(); + } + } catch (e) { + console.error(e); + } +})(); \ No newline at end of file diff --git a/src/services/admin/CustomersService/CustomersService.ts b/src/services/admin/CustomersService/CustomersService.ts new file mode 100644 index 00000000..7656bed2 --- /dev/null +++ b/src/services/admin/CustomersService/CustomersService.ts @@ -0,0 +1,52 @@ +import { Customers, Prisma } from "@prisma/client"; +import CustomersRepository from "@Repositories/CustomersRepository"; +import BaseService from "@Services/BaseService"; +import { Customer } from "le-coffre-resources/dist/Admin"; +import { Service } from "typedi"; + +@Service() +export default class CustomersService extends BaseService { + constructor(private customerRepository: CustomersRepository) { + super(); + } + + /** + * @description : Get all Customers + * @throws {Error} If Customers cannot be get + */ + public async get(query: Prisma.CustomersFindManyArgs): Promise { + return this.customerRepository.findMany(query); + } + + /** + * @description : Create a new customer + * @throws {Error} If customer cannot be created + */ + public async create(customerEntity: Customer): Promise { + return this.customerRepository.create(customerEntity); + } + + /** + * @description : Modify a customer + * @throws {Error} If customer cannot be modified + */ + public async update(uid: string, customerEntity: Customer): Promise { + return this.customerRepository.update(uid, customerEntity); + } + + /** + * @description : Get a customer by uid + * @throws {Error} If customer cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.CustomersInclude): Promise { + return this.customerRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a customer by contact uid + * @throws {Error} If customer cannot be get by contact uid + */ + public async getByContact(contactUid: string): Promise { + return this.customerRepository.findOneByContact(contactUid); + } +} diff --git a/src/services/admin/DeedTypesService/DeedTypesService.ts b/src/services/admin/DeedTypesService/DeedTypesService.ts new file mode 100644 index 00000000..35daf668 --- /dev/null +++ b/src/services/admin/DeedTypesService/DeedTypesService.ts @@ -0,0 +1,52 @@ +import { DeedTypes, Prisma } from "@prisma/client"; +import DeedTypesRepository from "@Repositories/DeedTypesRepository"; +import BaseService from "@Services/BaseService"; +import { DeedType } from "le-coffre-resources/dist/Admin"; +import { Service } from "typedi"; + +@Service() +export default class DeedTypesService extends BaseService { + constructor(private deedTypeRepository: DeedTypesRepository) { + super(); + } + + /** + * @description : Get all deed-types + * @throws {Error} If deed-types cannot be get + */ + public async get(query: Prisma.DeedTypesFindManyArgs) { + return this.deedTypeRepository.findMany(query); + } + + /** + * @description : Create a new deed-type + * @throws {Error} If deed-type cannot be created + */ + public async create(deedTypeEntity: DeedType): Promise { + return this.deedTypeRepository.create(deedTypeEntity); + } + + /** + * @description : Modify a deed-type + * @throws {Error} If deed-type cannot be modifified + */ + public async update(uid: string, deedTypeEntity: DeedType): Promise { + return this.deedTypeRepository.update(uid, deedTypeEntity); + } + + /** + * @description : Get a deedtype by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.DeedTypesInclude): Promise { + return this.deedTypeRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a deedtype by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.deedTypeRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/admin/DeedsService/DeedsService.ts b/src/services/admin/DeedsService/DeedsService.ts new file mode 100644 index 00000000..56d88427 --- /dev/null +++ b/src/services/admin/DeedsService/DeedsService.ts @@ -0,0 +1,48 @@ +import { Deeds, Prisma } from "@prisma/client"; +import DeedsRepository from "@Repositories/DeedsRepository"; +import BaseService from "@Services/BaseService"; +import { Deed } from "le-coffre-resources/dist/Admin"; +import { Service } from "typedi"; + +@Service() +export default class DeedsService extends BaseService { + constructor(private deedRepository: DeedsRepository) { + super(); + } + + /** + * @description : Get all deeds + * @throws {Error} If deeds cannot be get + */ + public async get(query: Prisma.DeedsFindManyArgs) { + return this.deedRepository.findMany(query); + } + + /** + * @description : Create a new deed with document types + * @throws {Error} If deeds cannot be created + */ + public async create(deed: Deed): Promise { + return this.deedRepository.create(deed); + } + + /** + * @description : Update data of a deed with document types + * @throws {Error} If deeds cannot be updated with document types or one of them + */ + public async update(uid: string, deed: Deed): Promise { + return this.deedRepository.update(uid, deed); + } + + /** + * @description : Get a deed by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.DeedsInclude) { + return this.deedRepository.findOneByUid(uid, query); + } + + public async getOneByUidWithOffice(uid: string) { + return this.deedRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/admin/DocumentTypesService/DocumentTypesService.ts b/src/services/admin/DocumentTypesService/DocumentTypesService.ts new file mode 100644 index 00000000..30d56724 --- /dev/null +++ b/src/services/admin/DocumentTypesService/DocumentTypesService.ts @@ -0,0 +1,52 @@ +import { DocumentTypes, Prisma } from "@prisma/client"; +import DocumentTypesRepository from "@Repositories/DocumentTypesRepository"; +import BaseService from "@Services/BaseService"; +import { DocumentType } from "le-coffre-resources/dist/Admin"; +import { Service } from "typedi"; + +@Service() +export default class DocumentTypesService extends BaseService { + constructor(private documentTypeRepository: DocumentTypesRepository) { + super(); + } + + /** + * @description : Get all document-types + * @throws {Error} If document-types cannot be get + */ + public async get(query: Prisma.DocumentTypesFindManyArgs) { + return this.documentTypeRepository.findMany(query); + } + + /** + * @description : Create a new document-type + * @throws {Error} If document-types cannot be created + */ + public async create(documentTypeEntity: DocumentType): Promise { + return this.documentTypeRepository.create(documentTypeEntity); + } + + /** + * @description : Modify a document-type + * @throws {Error} If document-type cannot be modified + */ + public async update(uid: string, documentTypeEntity: DocumentType): Promise { + return this.documentTypeRepository.update(uid, documentTypeEntity); + } + + /** + * @description : Get a document-type by uid + * @throws {Error} If document-type is not found + */ + public async getByUid(uid: string, query?: Prisma.DocumentTypesInclude) { + return this.documentTypeRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a document-type by uid with relations + * @throws {Error} If document-type is not found + */ + public async getByUidWithOffice(uid: string) { + return this.documentTypeRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/admin/DocumentsService/DocumentsService.ts b/src/services/admin/DocumentsService/DocumentsService.ts new file mode 100644 index 00000000..c8e7aa0b --- /dev/null +++ b/src/services/admin/DocumentsService/DocumentsService.ts @@ -0,0 +1,75 @@ +import { Documents, Prisma } from "@prisma/client"; +import { Document } from "le-coffre-resources/dist/Admin"; +import DocumentsRepository from "@Repositories/DocumentsRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class DocumentsService extends BaseService { + constructor(private documentsRepository: DocumentsRepository) { + super(); + } + + /** + * @description : Get all documents + * @throws {Error} If documents cannot be get + */ + public async get(query: Prisma.DocumentsFindManyArgs) { + return this.documentsRepository.findMany(query); + } + + /** + * @description : Create a new document + * @throws {Error} If document cannot be created + */ + public async create(document: Document): Promise { + return this.documentsRepository.create(document); + } + + /** + * @description : Create new documents + * @throws {Error} If documents or one of them cannot be created + */ + public async createMany(documents: Document[]): Promise { + return this.documentsRepository.createMany(documents); + } + + /** + * @description : Modify a document + * @throws {Error} If document cannot be modified + */ + public async update(uid: string, document: Partial, refused_reason?: string): Promise { + return this.documentsRepository.update(uid, document, refused_reason); + } + + /** + * @description : Delete a document + * @throws {Error} If document cannot be deleted + */ + public async delete(uid: string): Promise { + const documentEntity = await this.documentsRepository.findOneByUid(uid, { files: true }); + if (!documentEntity) throw new Error("document not found"); + const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); + + if (document.files && document.files.length !== 0) { + throw new Error("Can't delete a document with file"); + } + return this.documentsRepository.delete(uid); + } + + /** + * @description : Get a document by uid + * @throws {Error} If document cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.DocumentsInclude): Promise { + return this.documentsRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a document by uid + * @throws {Error} If document cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.documentsRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts b/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts new file mode 100644 index 00000000..8d474aef --- /dev/null +++ b/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts @@ -0,0 +1,79 @@ +import { OfficeFolders } from ".prisma/client"; +import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; +import BaseService from "@Services/BaseService"; +import { OfficeFolder } from "le-coffre-resources/dist/Admin"; +import { Service } from "typedi"; +import DeedTypesService from "../DeedTypesService/DeedTypesService"; +import DeedsRepository from "@Repositories/DeedsRepository"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class OfficeFoldersService extends BaseService { + constructor( + private officeFoldersRepository: OfficeFoldersRepository, + private deedTypeService: DeedTypesService, + private deedRepository: DeedsRepository, + ) { + super(); + } + + /** + * @description : Get all folders + * @throws {Error} If folders cannot be get + */ + public async get(query: Prisma.OfficeFoldersFindManyArgs) { + return this.officeFoldersRepository.findMany(query); + } + + /** + * @description : Create a new folder + * @throws {Error} If folder cannot be created + */ + public async create(officeFolderEntity: OfficeFolder): Promise { + const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); + if (!deedType) throw new Error("deed type not found"); + if (deedType.archived_at) throw new Error("deed type is archived"); + const deed = await this.deedRepository.create(officeFolderEntity.deed!); + officeFolderEntity.deed!.uid = deed.uid; + return this.officeFoldersRepository.create(officeFolderEntity); + } + + /** + * @description : Modify a folder + * @throws {Error} If folder cannot be modified + */ + public async update(officeFolderuid: string, officeFolderEntity: OfficeFolder): Promise { + return this.officeFoldersRepository.update(officeFolderuid, officeFolderEntity); + } + + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.OfficeFoldersInclude) { + return this.officeFoldersRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.officeFoldersRepository.findOneByUidWithOffice(uid); + } + + /** + * @description : Delete a folder + * @throws {Error} If document cannot be deleted + */ + public async delete(uid: string): Promise { + const officeFolderEntity = await this.officeFoldersRepository.findOneByUid(uid, { customers: true }); + if (!officeFolderEntity) throw new Error("office folder not found"); + const officeFolder = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll" }); + + if (officeFolder.customers?.length) { + throw new Error("This folder is used by customers"); + } + return this.officeFoldersRepository.delete(uid); + } +} diff --git a/src/services/admin/OfficeRolesService/OfficeRolesService.ts b/src/services/admin/OfficeRolesService/OfficeRolesService.ts new file mode 100644 index 00000000..6ddbf1e5 --- /dev/null +++ b/src/services/admin/OfficeRolesService/OfficeRolesService.ts @@ -0,0 +1,52 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import OfficeRolesRepository from "@Repositories/OfficeRolesRepository"; +import { OfficeRole } from "le-coffre-resources/dist/Admin"; +import { Prisma, OfficeRoles } from "@prisma/client"; + +@Service() +export default class OfficeRolesService extends BaseService { + constructor(private officeRoleRepository: OfficeRolesRepository) { + super(); + } + + /** + * @description : Get all office roles + * @throws {Error} If office roles cannot be get + */ + public get(query: Prisma.OfficeRolesFindManyArgs) { + return this.officeRoleRepository.findMany(query); + } + + /** + * @description : Create a officeRole + * @throws {Error} If officeRole couldn't be created + */ + public create(officeRoleEntity: OfficeRole): Promise { + return this.officeRoleRepository.create(officeRoleEntity); + } + + /** + * @description : Modify a officeRole + * @throws {Error} If officeRole modification failed + */ + public update(officeRoleEntity: OfficeRole): Promise { + return this.officeRoleRepository.update(officeRoleEntity); + } + + /** + * @description : Get a officeRole by uid + * @throws {Error} If officeRole cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.OfficeRolesInclude) { + return this.officeRoleRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a officeRole by uid + * @throws {Error} If officeRole cannot be get by uid + */ + public getByUidWithOffice(uid: string) { + return this.officeRoleRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/admin/OfficesService/OfficesService.ts b/src/services/admin/OfficesService/OfficesService.ts new file mode 100644 index 00000000..af25083b --- /dev/null +++ b/src/services/admin/OfficesService/OfficesService.ts @@ -0,0 +1,27 @@ +import { Prisma } from "@prisma/client"; +import OfficesRepository from "@Repositories/OfficesRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class OfficesService extends BaseService { + constructor(private officeRepository: OfficesRepository) { + super(); + } + + /** + * @description : Get all offices + * @throws {Error} If offices cannot be get + */ + public async get(query: Prisma.OfficesFindManyArgs) { + return this.officeRepository.findMany(query); + } + + /** + * @description : Get a office by uid + * @throws {Error} If office cannot be get + */ + public async getByUid(uid: string, query?: Prisma.OfficesInclude) { + return this.officeRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/admin/RolesService/RolesService.ts b/src/services/admin/RolesService/RolesService.ts new file mode 100644 index 00000000..2e4032d0 --- /dev/null +++ b/src/services/admin/RolesService/RolesService.ts @@ -0,0 +1,45 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import RolesRepository from "@Repositories/RolesRepository"; +import { Role } from "le-coffre-resources/dist/Admin"; +import { Prisma, Roles } from "@prisma/client"; + +@Service() +export default class RolesService extends BaseService { + constructor(private roleRepository: RolesRepository) { + super(); + } + + /** + * @description : Get all roles + * @throws {Error} If roles cannot be get + */ + public get(query: Prisma.RolesFindManyArgs) { + return this.roleRepository.findMany(query); + } + + /** + * @description : Create a role + * @throws {Error} If role couldn't be created + */ + public create(roleEntity: Role): Promise { + return this.roleRepository.create(roleEntity); + } + + /** + * @description : Modify a role + * @throws {Error} If role modification failed + */ + public update(roleEntity: Role): Promise { + return this.roleRepository.update(roleEntity); + } + + /** + * @description : Get a role by uid + * @throws {Error} If role cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.RolesInclude) { + return this.roleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/admin/RulesService/RulesService.ts b/src/services/admin/RulesService/RulesService.ts new file mode 100644 index 00000000..28c60784 --- /dev/null +++ b/src/services/admin/RulesService/RulesService.ts @@ -0,0 +1,45 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import RulesRepository from "@Repositories/RulesRepository"; +import { Rule } from "le-coffre-resources/dist/Admin"; +import { Prisma, Rules } from "@prisma/client"; + +@Service() +export default class RulesService extends BaseService { + constructor(private ruleRepository: RulesRepository) { + super(); + } + + /** + * @description : Get all rules + * @throws {Error} If rules cannot be get + */ + public get(query: Prisma.RulesFindManyArgs) { + return this.ruleRepository.findMany(query); + } + + /** + * @description : Create a rule + * @throws {Error} If rule couldn't be created + */ + public create(ruleEntity: Rule): Promise { + return this.ruleRepository.create(ruleEntity); + } + + /** + * @description : Modify a rule + * @throws {Error} If rule modification failed + */ + public update(ruleEntity: Rule): Promise { + return this.ruleRepository.update(ruleEntity); + } + + /** + * @description : Get a rule by uid + * @throws {Error} If rule cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.RulesInclude) { + return this.ruleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/admin/UsersService/UsersService.ts b/src/services/admin/UsersService/UsersService.ts new file mode 100644 index 00000000..6167352e --- /dev/null +++ b/src/services/admin/UsersService/UsersService.ts @@ -0,0 +1,69 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import UsersRepository from "@Repositories/UsersRepository"; +import User from "le-coffre-resources/dist/Admin"; +import { Prisma, Users } from "@prisma/client"; + +@Service() +export default class UsersService extends BaseService { + constructor(private userRepository: UsersRepository) { + super(); + } + + /** + * @description : Get all users + * @throws {Error} If users cannot be get + */ + public get(query: Prisma.UsersFindManyArgs) { + return this.userRepository.findMany(query); + } + + /** + * @description : Create a user + * @throws {Error} If user couldn't be created + */ + public create(userEntity: User): Promise { + return this.userRepository.create(userEntity); + } + + /** + * @description : Modify a user + * @throws {Error} If user modification failed + */ + public async update(uid: string, userEntity: User): Promise { + return this.userRepository.updateRole(uid, userEntity); + } + + /** + * @description : Get a user by uid + * @throws {Error} If user cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.UsersInclude) { + return this.userRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a user by uid with office + * @throws {Error} If user cannot be get by uid + */ + public getByUidWithOffice(uid: string) { + return this.userRepository.findOneByUidWithOffice(uid); + } + + /** + * @description : Get a user by uid with office + * @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 + */ + public getByProvider(providerName: string, id: string) { + return this.userRepository.findOneByProvider(providerName, id); + } +} diff --git a/src/services/common/AuthService/AuthService.ts b/src/services/common/AuthService/AuthService.ts new file mode 100644 index 00000000..4410cd35 --- /dev/null +++ b/src/services/common/AuthService/AuthService.ts @@ -0,0 +1,96 @@ +import jwt, { VerifyCallback } from "jsonwebtoken"; +import BaseService from "@Services/BaseService"; +import { BackendVariables } from "@Common/config/variables/Variables"; +import { Service } from "typedi"; +import UsersService from "@Services/super-admin/UsersService/UsersService"; +import CustomersService from "@Services/super-admin/CustomersService/CustomersService"; +import ContactService from "../ContactService"; +import { ECustomerStatus } from "@prisma/client"; + +enum PROVIDER_OPENID { + idNot = "idNot", +} + +interface ICustomerJwtPayload { + customerId: string; + email: string; +} + + +interface IUserJwtPayload { + userId: string; + openId: { + providerName: PROVIDER_OPENID; + userId: string | number; + }; + office_Id: string; + role: string; + rules: string[]; +} + +@Service() +export default class AuthService extends BaseService { + constructor(protected variables: BackendVariables, private userService: UsersService, private customerService: CustomersService, private contactService: ContactService) { + super(); + } + + public async getCustomerJwtPayload(email:string): Promise { + const contact = await this.contactService.getByEmail(email); + if (!contact) return null; + const customer = await this.customerService.getByUid(contact.customers!.uid, { contact: true }); + if (!customer) return null; + + if(customer.status === ECustomerStatus["PENDING"]) { + customer.status = ECustomerStatus["VALIDATED"]; + this.customerService.update(customer.uid, customer); + } + + return { + customerId: customer.uid, + email: contact.email, + }; + } + + public async getUserJwtPayload(id: string, providerName: PROVIDER_OPENID = PROVIDER_OPENID.idNot): Promise { + const user = await this.userService.getByProvider(providerName, id); + + if (!user) return null; + + const rules: string[] = []; + + user.role.rules.forEach((rule) => { + rules.push(rule.name); + }); + + if (user.office_role) { + user.office_role.rules.forEach((rule) => { + if(!rules.includes(rule.name)) { + rules.push(rule.name); + } + }); + } + + return { + userId: user.uid, + openId: { providerName: providerName, userId: user.idNot }, + office_Id: user.office_membership.uid, + role: user.role.name, + rules: rules, + }; + } + public generateAccessToken(user: any): string { + return jwt.sign({ ...user }, this.variables.ACCESS_TOKEN_SECRET, { expiresIn: "1h" }); + } + + public generateRefreshToken(user: any): string { + return jwt.sign({ ...user }, this.variables.REFRESH_TOKEN_SECRET, { expiresIn: "1h" }); + } + + public verifyAccessToken(token: string, callback?: VerifyCallback) { + return jwt.verify(token, this.variables.ACCESS_TOKEN_SECRET, callback); + } + + public verifyRefreshToken(token: string, callback?: VerifyCallback) { + return jwt.verify(token, this.variables.REFRESH_TOKEN_SECRET, callback); + } +} diff --git a/src/services/common/ContactService.ts b/src/services/common/ContactService.ts new file mode 100644 index 00000000..e1cc6c19 --- /dev/null +++ b/src/services/common/ContactService.ts @@ -0,0 +1,19 @@ +import { Contacts, Customers } from "@prisma/client"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import ContactRepository from "@Repositories/ContactRepository"; + +@Service() +export default class DocumentsService extends BaseService { + constructor(private contactRepository: ContactRepository) { + super(); + } + + /** + * @description : Get a contact by email + * @throws {Error} If contact cannot be get by email + */ + public async getByEmail(email: string): Promise<(Contacts & {customers: Customers | null}) | null> { + return this.contactRepository.findOneByEmail(email); + } +} diff --git a/src/services/common/CronService/CronService.ts b/src/services/common/CronService/CronService.ts new file mode 100644 index 00000000..321e0a91 --- /dev/null +++ b/src/services/common/CronService/CronService.ts @@ -0,0 +1,24 @@ +import { Service } from "typedi"; +import { CronJob } from "cron"; +import MailchimpService from "../MailchimpService/MailchimpService"; + + +@Service() +export default class CronService { + constructor(private mailchimpService: MailchimpService) {} + + public async sendMails() { + const cronJob = new CronJob("*/15 * * * * *", async () => { + try { + await this.mailchimpService.sendEmails(); + } catch (e) { + console.error(e); + } + }); + + // Start job + if (!cronJob.running) { + cronJob.start(); + } + } +} diff --git a/src/services/private-services/CryptoService/CryptoService.ts b/src/services/common/CryptoService/CryptoService.ts similarity index 94% rename from src/services/private-services/CryptoService/CryptoService.ts rename to src/services/common/CryptoService/CryptoService.ts index 5ac62af1..893f62c5 100644 --- a/src/services/private-services/CryptoService/CryptoService.ts +++ b/src/services/common/CryptoService/CryptoService.ts @@ -5,7 +5,6 @@ import crypto from "crypto"; @Service() export default class CryptoService extends BaseService { - private static readonly CRYPTO_ALGORITHM = "aes-256-ctr"; constructor(protected variables: BackendVariables) { @@ -13,7 +12,7 @@ export default class CryptoService extends BaseService { } private getKey(key: string) { - return crypto.createHash('sha256').update(String(key)).digest('base64').slice(0, 32); + return crypto.createHash("sha256").update(String(key)).digest("base64").slice(0, 32); } /** @@ -29,7 +28,7 @@ export default class CryptoService extends BaseService { const result = Buffer.concat([iv, cipher.update(buffer), cipher.final()]); return result; } - + /** * @description : decrypt data with an initialization vector * @throws {Error} If data cannot be decrypted diff --git a/src/services/common/FilesService/FilesService.ts b/src/services/common/FilesService/FilesService.ts new file mode 100644 index 00000000..2ec4e6b5 --- /dev/null +++ b/src/services/common/FilesService/FilesService.ts @@ -0,0 +1,111 @@ +import FilesRepository from "@Repositories/FilesRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import { File } from "le-coffre-resources/dist/SuperAdmin"; +import CryptoService from "../CryptoService/CryptoService"; +import IpfsService from "../IpfsService/IpfsService"; +import { BackendVariables } from "@Common/config/variables/Variables"; +import { Readable } from "stream"; +import { v4 } from "uuid"; +import { Files, Prisma } from "@prisma/client"; +import fetch from "node-fetch"; + +@Service() +export default class FilesService extends BaseService { + constructor( + private filesRepository: FilesRepository, + private ipfsService: IpfsService, + private variables: BackendVariables, + private cryptoService: CryptoService, + ) { + super(); + } + + /** + * @description : Get all files + * @throws {Error} If files cannot be ge + */ + public async get(query: Prisma.FilesFindManyArgs) { + return this.filesRepository.findMany(query); + } + + /** + * @description : Get a file by uid + * @throws {Error} If project cannot be created + */ + public async getByUid(uid: string, query?: Prisma.FilesInclude) { + return this.filesRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a file by uid with office + * @throws {Error} If project cannot be created + */ + public async getByUidWithOffice(uid: string) { + return this.filesRepository.findOneByUidWithOffice(uid); + } + + /** + * @description : Get a file by uid with document + * @throws {Error} If project cannot be created + */ + public async getByUidWithDocument(uid: string) { + return this.filesRepository.findOneByUidWithDocument(uid); + } + + /** + * @description : view a file + * @throws {Error} If file cannot be deleted + */ + public async download(uid: string) { + const file = await this.filesRepository.findOneByUid(uid); + if (!file?.key) return null; + const fileResult = await fetch(file.file_path); + const fileArrayBuffer = await fileResult.arrayBuffer(); + return { file: file, buffer: await this.cryptoService.decrypt(Buffer.from(fileArrayBuffer), file.key) }; + } + + /** + * @description : Create a new file + * @throws {Error} If file cannot be created + */ + public async create(file: File, fileData: Express.Multer.File) { + const key = v4(); + const encryptedFile = await this.cryptoService.encrypt(fileData.buffer, key); + const upload = await this.ipfsService.pinFile(Readable.from(encryptedFile), fileData.originalname); + let fileToCreate: File = file; + fileToCreate.file_name = fileData.originalname; + fileToCreate.file_path = this.variables.PINATA_GATEWAY.concat(upload.IpfsHash); + fileToCreate.mimetype = fileData.mimetype; + fileToCreate.size = fileData.size; + fileToCreate.archived_at = null; + + return this.filesRepository.create(fileToCreate, key); + } + + /** + * @description : Modify a new file + * @throws {Error} If file cannot be modified + */ + public async update(uid: string, file: File): Promise { + const key = v4(); + return this.filesRepository.update(uid, file, key); + } + + /** + * @description : Delete a file key and archive + * @throws {Error} If file key cannot be deleted or archived + */ + public async deleteKeyAndArchive(uid: string): Promise { + try { + const fileToUnpin = await this.filesRepository.findOneByUid(uid); + if (!fileToUnpin) throw new Error("file not found"); + const fileHash = fileToUnpin.file_path.substring(this.variables.PINATA_GATEWAY.length); + await this.ipfsService.unpinFile(fileHash); + } catch (error) { + console.error(error); + } + + return this.filesRepository.deleteKeyAndArchive(uid); + } +} diff --git a/src/services/private-services/IpfsService/IpfsService.ts b/src/services/common/IpfsService/IpfsService.ts similarity index 83% rename from src/services/private-services/IpfsService/IpfsService.ts rename to src/services/common/IpfsService/IpfsService.ts index cc0f3df7..87a77b56 100644 --- a/src/services/private-services/IpfsService/IpfsService.ts +++ b/src/services/common/IpfsService/IpfsService.ts @@ -9,7 +9,7 @@ export default class FilesService extends BaseService { private ipfsClient: pinataSDK; constructor(protected variables: BackendVariables) { super(); - this.ipfsClient = new pinataSDK({ pinataApiKey: variables.PINATA_API_KEY, pinataSecretApiKey: variables.PINATA_API_SECRET }) + this.ipfsClient = new pinataSDK({ pinataApiKey: variables.PINATA_API_KEY, pinataSecretApiKey: variables.PINATA_API_SECRET }); } /** @@ -17,7 +17,7 @@ export default class FilesService extends BaseService { * @throws {Error} If file cannot be pinned */ public async pinFile(stream: Readable, fileName: string) { - return this.ipfsClient.pinFileToIPFS(stream, {pinataMetadata : {name: fileName}}); + return this.ipfsClient.pinFileToIPFS(stream, { pinataMetadata: { name: fileName } }); } /** diff --git a/src/services/common/MailchimpService/MailchimpService.ts b/src/services/common/MailchimpService/MailchimpService.ts new file mode 100644 index 00000000..a14b0b9b --- /dev/null +++ b/src/services/common/MailchimpService/MailchimpService.ts @@ -0,0 +1,116 @@ +import EmailRepository from "@Repositories/EmailRepository"; +import BaseService from "@Services/BaseService"; +import { Emails } from "@prisma/client"; +import { Service } from "typedi"; +import MailchimpClient from "@mailchimp/mailchimp_transactional"; +import { BackendVariables } from "@Common/config/variables/Variables"; + +@Service() +export default class MailchimpService extends BaseService { + private static readonly from = "vincent.alamelle@smart-chain.fr"; + + constructor(private emailRepository: EmailRepository, protected variables: BackendVariables) { + super(); + } + + /** + * @description : Get all emails + * @throws {Error} If emails cannot be get + */ + public async get(query: any): Promise { + return this.emailRepository.findMany(query); + } + + /** + * @description : Create a new email + * @throws {Error} If email cannot be created + */ + public async create(emailEntity: Emails): Promise { + emailEntity.from = MailchimpService.from; + return this.emailRepository.create(emailEntity); + } + + /** + * @description : Modify an email + * @throws {Error} If email cannot be modified + */ + public async update(uid: string, emailEntity: Emails): Promise { + return this.emailRepository.update(uid, emailEntity); + } + + /** + * @description : Get a email by uid + * @throws {Error} If email cannot be get + */ + public async getByUid(uid: string, query?: any): Promise { + return this.emailRepository.findOneByUid(uid); + } + + /** + * @description : Function called by cron to send emails + * @throws {Error} If email cannot be sent + */ + public async sendEmails() { + const emailsToSend = await this.get({ where: { sentAt: null } }); + const currentDate = new Date(); + let nextTrySendDate = null; + + for (const email of emailsToSend) { + //If tries exceed 10, we stop trying to send the email + if (email.nbTrySend && email.nbTrySend > 9) continue; + + //If email has never been sent, we send it + if (email.nbTrySend == 0) { + nextTrySendDate = currentDate; + } + //If email has already been sent, we send it again every nbTrySend^2 minutes + else { + nextTrySendDate = new Date(email.lastTrySendDate!); + nextTrySendDate.setMinutes(nextTrySendDate.getMinutes() + Math.pow(email.nbTrySend!, 2)); + } + + //If the next try send date is passed, we send the email + if (currentDate >= nextTrySendDate) { + try { + await this.sendEmail(email); + email.sentAt = currentDate; + } catch (error) { + email.lastTrySendDate = currentDate; + email.nbTrySend = email.nbTrySend! + 1; + } + await this.update(email.uid, email); + } + } + } + + private async sendEmail(email: Emails) { + const apiKey = this.variables.MAILCHIMP_API_KEY; + const mailchimpApiClient = MailchimpClient(apiKey!); + + await mailchimpApiClient.messages.sendTemplate({ + template_name: email.templateName, + template_content: [], + message: { + global_merge_vars: this.buildVariables(email.templateVariables), + from_email: email.from!, + from_name: "LeCoffre.io", + subject: email.subject, + to: [ + { + email: email.to, + type: "to", + }, + ], + }, + }); + } + + private buildVariables(templateVariables: any) { + return Object.keys(templateVariables).map((key) => { + return { + name: key, + content: templateVariables[key], + }; + }); + } +} diff --git a/src/services/private-services/NotificationsService/NotificationsService.ts b/src/services/common/NotificationsService/NotificationsService.ts similarity index 100% rename from src/services/private-services/NotificationsService/NotificationsService.ts rename to src/services/common/NotificationsService/NotificationsService.ts diff --git a/src/services/common/OpenIdService/OpenIdService.ts b/src/services/common/OpenIdService/OpenIdService.ts new file mode 100644 index 00000000..6f34bc58 --- /dev/null +++ b/src/services/common/OpenIdService/OpenIdService.ts @@ -0,0 +1,55 @@ +import jwt from "jsonwebtoken"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +export type Tokens = { + access_token: string; + expires_in: number; + id_token: string; + token_type: string; +}; + +export type OpenIdConfig = { + authorization_endpoint: string; + token_endpoint: string; + userinfo_endpoint: string; + claims_supported: string[]; + end_session_endpoint: string; + grant_types_supported: string[]; + response_types_supported: string[]; + scopes_supported: string[]; + issuer: string; + jwks_uri: string; +}; + +@Service() +export default class OpenIdService extends BaseService { + protected authorizationServerUrl: string; + constructor(authorizationServerUrl: string) { + super(); + this.authorizationServerUrl = authorizationServerUrl; + } + + public async getOpenIdConfig(): Promise { + const response = await fetch(this.authorizationServerUrl + "/.well-known/openid-configuration"); + return await response.json(); + } + + public async getSigningKey(kid: string): Promise { + const jwksUri = (await this.getOpenIdConfig()).jwks_uri; + const response = await fetch(jwksUri); + const jwks = await response.json(); + const signingKey = jwks.keys.find((key: any) => key.kid === kid); + if (!signingKey) return null; + return signingKey; + } + + /** + * @throws Error + */ + public async verifyIdToken(idToken: string, kid: string) { + const signingKey = await this.getSigningKey(kid); + if (!signingKey) throw new Error("Signing key not found"); + return jwt.verify(idToken, signingKey); + } +} diff --git a/src/services/customer/CustomersService/CustomersService.ts b/src/services/customer/CustomersService/CustomersService.ts new file mode 100644 index 00000000..38509164 --- /dev/null +++ b/src/services/customer/CustomersService/CustomersService.ts @@ -0,0 +1,35 @@ +import { Customers, Prisma } from "@prisma/client"; +import CustomersRepository from "@Repositories/CustomersRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class CustomersService extends BaseService { + constructor(private customerRepository: CustomersRepository) { + super(); + } + + /** + * @description : Get all Customers + * @throws {Error} If Customers cannot be get + */ + public async get(query: Prisma.CustomersFindManyArgs): Promise { + return this.customerRepository.findMany(query); + } + + /** + * @description : Get a customer by uid + * @throws {Error} If customer cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.CustomersInclude): Promise { + return this.customerRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a customer by contact uid + * @throws {Error} If customer cannot be get by contact uid + */ + public async getByContact(contactUid: string): Promise { + return this.customerRepository.findOneByContact(contactUid); + } +} diff --git a/src/services/customer/DocumentsService/DocumentsService.ts b/src/services/customer/DocumentsService/DocumentsService.ts index b5d470e0..26c45c6a 100644 --- a/src/services/customer/DocumentsService/DocumentsService.ts +++ b/src/services/customer/DocumentsService/DocumentsService.ts @@ -1,4 +1,4 @@ -import { Documents, Prisma } from "@prisma/client"; +import { Documents } from "@prisma/client"; import { Document } from "le-coffre-resources/dist/Customer"; import DocumentsRepository from "@Repositories/DocumentsRepository"; import BaseService from "@Services/BaseService"; @@ -14,47 +14,23 @@ export default class DocumentsService extends BaseService { * @description : Get all documents * @throws {Error} If documents cannot be get */ - public async get(query: any) { + public async get(query: any): Promise { return this.documentsRepository.findMany(query); } - /** - * @description : Create a new document - * @throws {Error} If document cannot be created - */ - public async create(document: Document): Promise { - return this.documentsRepository.create(document); - } - - /** - * @description : Create new documents - * @throws {Error} If documents or one of them cannot be created - */ - public async createMany(documents: Document[]): Promise { - return this.documentsRepository.createMany(documents); - } - /** * @description : Modify a document * @throws {Error} If document cannot be modified */ - public async update(uid: string, document: Document): Promise { + public async update(uid: string, document: Document): Promise { return this.documentsRepository.update(uid, document); } - /** - * @description : Delete a document - * @throws {Error} If document cannot be deleted - */ - public async delete(uid: string): Promise { - return this.documentsRepository.delete(uid); - } - /** * @description : Get a document by uid * @throws {Error} If document cannot be get by uid */ - public async getByUid(uid: string, query?: any) { + public async getByUid(uid: string, query?: any): Promise { return this.documentsRepository.findOneByUid(uid, query); } } diff --git a/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts b/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts new file mode 100644 index 00000000..6afdede7 --- /dev/null +++ b/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts @@ -0,0 +1,29 @@ +import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class OfficeFoldersService extends BaseService { + constructor( + private officeFoldersRepository: OfficeFoldersRepository, + ) { + super(); + } + + /** + * @description : Get all folders + * @throws {Error} If folders cannot be get + */ + public async get(query: Prisma.OfficeFoldersFindManyArgs) { + return this.officeFoldersRepository.findMany(query); + } + + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.OfficeFoldersInclude) { + return this.officeFoldersRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/notary/CustomersService/CustomersService.ts b/src/services/notary/CustomersService/CustomersService.ts new file mode 100644 index 00000000..72e6923d --- /dev/null +++ b/src/services/notary/CustomersService/CustomersService.ts @@ -0,0 +1,52 @@ +import { Customers, Prisma } from "@prisma/client"; +import CustomersRepository from "@Repositories/CustomersRepository"; +import BaseService from "@Services/BaseService"; +import { Customer } from "le-coffre-resources/dist/Notary"; +import { Service } from "typedi"; + +@Service() +export default class CustomersService extends BaseService { + constructor(private customerRepository: CustomersRepository) { + super(); + } + + /** + * @description : Get all Customers + * @throws {Error} If Customers cannot be get + */ + public async get(query: Prisma.CustomersFindManyArgs): Promise { + return this.customerRepository.findMany(query); + } + + /** + * @description : Create a new customer + * @throws {Error} If customer cannot be created + */ + public async create(customerEntity: Customer): Promise { + return this.customerRepository.create(customerEntity); + } + + /** + * @description : Modify a customer + * @throws {Error} If customer cannot be modified + */ + public async update(uid: string, customerEntity: Customer): Promise { + return this.customerRepository.update(uid, customerEntity); + } + + /** + * @description : Get a customer by uid + * @throws {Error} If customer cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.CustomersInclude): Promise { + return this.customerRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a customer by contact uid + * @throws {Error} If customer cannot be get by contact uid + */ + public async getByContact(contactUid: string): Promise { + return this.customerRepository.findOneByContact(contactUid); + } +} diff --git a/src/services/notary/DeedTypesService/DeedTypesService.ts b/src/services/notary/DeedTypesService/DeedTypesService.ts new file mode 100644 index 00000000..fa4a5551 --- /dev/null +++ b/src/services/notary/DeedTypesService/DeedTypesService.ts @@ -0,0 +1,52 @@ +import { DeedTypes, Prisma } from "@prisma/client"; +import DeedTypesRepository from "@Repositories/DeedTypesRepository"; +import BaseService from "@Services/BaseService"; +import { DeedType } from "le-coffre-resources/dist/Notary"; +import { Service } from "typedi"; + +@Service() +export default class DeedTypesService extends BaseService { + constructor(private deedTypeRepository: DeedTypesRepository) { + super(); + } + + /** + * @description : Get all deed-types + * @throws {Error} If deed-types cannot be get + */ + public async get(query: Prisma.DeedTypesFindManyArgs) { + return this.deedTypeRepository.findMany(query); + } + + /** + * @description : Create a new deed-type + * @throws {Error} If deed-type cannot be created + */ + public async create(deedTypeEntity: DeedType): Promise { + return this.deedTypeRepository.create(deedTypeEntity); + } + + /** + * @description : Modify a deed-type + * @throws {Error} If deed-type cannot be modifified + */ + public async update(uid: string, deedTypeEntity: DeedType): Promise { + return this.deedTypeRepository.update(uid, deedTypeEntity); + } + + /** + * @description : Get a deedtype by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.DeedTypesInclude): Promise { + return this.deedTypeRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a deedtype by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.deedTypeRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/notary/DeedsService/DeedsService.ts b/src/services/notary/DeedsService/DeedsService.ts new file mode 100644 index 00000000..47f18cdd --- /dev/null +++ b/src/services/notary/DeedsService/DeedsService.ts @@ -0,0 +1,48 @@ +import { Deeds, Prisma } from "@prisma/client"; +import DeedsRepository from "@Repositories/DeedsRepository"; +import BaseService from "@Services/BaseService"; +import { Deed } from "le-coffre-resources/dist/Notary"; +import { Service } from "typedi"; + +@Service() +export default class DeedsService extends BaseService { + constructor(private deedRepository: DeedsRepository) { + super(); + } + + /** + * @description : Get all deeds + * @throws {Error} If deeds cannot be get + */ + public async get(query: Prisma.DeedsFindManyArgs) { + return this.deedRepository.findMany(query); + } + + /** + * @description : Create a new deed with document types + * @throws {Error} If deeds cannot be created + */ + public async create(deed: Deed): Promise { + return this.deedRepository.create(deed); + } + + /** + * @description : Update data of a deed with document types + * @throws {Error} If deeds cannot be updated with document types or one of them + */ + public async update(uid: string, deed: Deed): Promise { + return this.deedRepository.update(uid, deed); + } + + /** + * @description : Get a deed by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.DeedsInclude) { + return this.deedRepository.findOneByUid(uid, query); + } + + public async getOneByUidWithOffice(uid: string) { + return this.deedRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/notary/DocumentTypesService/DocumentTypesService.ts b/src/services/notary/DocumentTypesService/DocumentTypesService.ts new file mode 100644 index 00000000..fb55f818 --- /dev/null +++ b/src/services/notary/DocumentTypesService/DocumentTypesService.ts @@ -0,0 +1,52 @@ +import { DocumentTypes, Prisma } from "@prisma/client"; +import DocumentTypesRepository from "@Repositories/DocumentTypesRepository"; +import BaseService from "@Services/BaseService"; +import { DocumentType } from "le-coffre-resources/dist/Notary"; +import { Service } from "typedi"; + +@Service() +export default class DocumentTypesService extends BaseService { + constructor(private documentTypeRepository: DocumentTypesRepository) { + super(); + } + + /** + * @description : Get all document-types + * @throws {Error} If document-types cannot be get + */ + public async get(query: Prisma.DocumentTypesFindManyArgs) { + return this.documentTypeRepository.findMany(query); + } + + /** + * @description : Create a new document-type + * @throws {Error} If document-types cannot be created + */ + public async create(documentTypeEntity: DocumentType): Promise { + return this.documentTypeRepository.create(documentTypeEntity); + } + + /** + * @description : Modify a document-type + * @throws {Error} If document-type cannot be modified + */ + public async update(uid: string, documentTypeEntity: DocumentType): Promise { + return this.documentTypeRepository.update(uid, documentTypeEntity); + } + + /** + * @description : Get a document-type by uid + * @throws {Error} If document-type is not found + */ + public async getByUid(uid: string, query?: Prisma.DocumentTypesInclude) { + return this.documentTypeRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a document-type by uid with relations + * @throws {Error} If document-type is not found + */ + public async getByUidWithOffice(uid: string) { + return this.documentTypeRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/notary/DocumentsService/DocumentsService.ts b/src/services/notary/DocumentsService/DocumentsService.ts new file mode 100644 index 00000000..649ad2bf --- /dev/null +++ b/src/services/notary/DocumentsService/DocumentsService.ts @@ -0,0 +1,75 @@ +import { Documents, Prisma } from "@prisma/client"; +import { Document } from "le-coffre-resources/dist/Notary"; +import DocumentsRepository from "@Repositories/DocumentsRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class DocumentsService extends BaseService { + constructor(private documentsRepository: DocumentsRepository) { + super(); + } + + /** + * @description : Get all documents + * @throws {Error} If documents cannot be get + */ + public async get(query: Prisma.DocumentsFindManyArgs) { + return this.documentsRepository.findMany(query); + } + + /** + * @description : Create a new document + * @throws {Error} If document cannot be created + */ + public async create(document: Document): Promise { + return this.documentsRepository.create(document); + } + + /** + * @description : Create new documents + * @throws {Error} If documents or one of them cannot be created + */ + public async createMany(documents: Document[]): Promise { + return this.documentsRepository.createMany(documents); + } + + /** + * @description : Modify a document + * @throws {Error} If document cannot be modified + */ + public async update(uid: string, document: Partial, refused_reason?: string): Promise { + return this.documentsRepository.update(uid, document, refused_reason); + } + + /** + * @description : Delete a document + * @throws {Error} If document cannot be deleted + */ + public async delete(uid: string): Promise { + const documentEntity = await this.documentsRepository.findOneByUid(uid, { files: true }); + if (!documentEntity) throw new Error("document not found"); + const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); + + if (document.files && document.files.length !== 0) { + throw new Error("Can't delete a document with file"); + } + return this.documentsRepository.delete(uid); + } + + /** + * @description : Get a document by uid + * @throws {Error} If document cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.DocumentsInclude): Promise { + return this.documentsRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a document by uid + * @throws {Error} If document cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.documentsRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts b/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts new file mode 100644 index 00000000..97fa5680 --- /dev/null +++ b/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts @@ -0,0 +1,79 @@ +import { OfficeFolders } from ".prisma/client"; +import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; +import BaseService from "@Services/BaseService"; +import { OfficeFolder } from "le-coffre-resources/dist/Notary"; +import { Service } from "typedi"; +import DeedTypesService from "../DeedTypesService/DeedTypesService"; +import DeedsRepository from "@Repositories/DeedsRepository"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class OfficeFoldersService extends BaseService { + constructor( + private officeFoldersRepository: OfficeFoldersRepository, + private deedTypeService: DeedTypesService, + private deedRepository: DeedsRepository, + ) { + super(); + } + + /** + * @description : Get all folders + * @throws {Error} If folders cannot be get + */ + public async get(query: Prisma.OfficeFoldersFindManyArgs) { + return this.officeFoldersRepository.findMany(query); + } + + /** + * @description : Create a new folder + * @throws {Error} If folder cannot be created + */ + public async create(officeFolderEntity: OfficeFolder): Promise { + const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); + if (!deedType) throw new Error("deed type not found"); + if (deedType.archived_at) throw new Error("deed type is archived"); + const deed = await this.deedRepository.create(officeFolderEntity.deed!); + officeFolderEntity.deed!.uid = deed.uid; + return this.officeFoldersRepository.create(officeFolderEntity); + } + + /** + * @description : Modify a folder + * @throws {Error} If folder cannot be modified + */ + public async update(officeFolderuid: string, officeFolderEntity: OfficeFolder): Promise { + return this.officeFoldersRepository.update(officeFolderuid, officeFolderEntity); + } + + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUid(uid: string, query?: Prisma.OfficeFoldersInclude) { + return this.officeFoldersRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.officeFoldersRepository.findOneByUidWithOffice(uid); + } + + /** + * @description : Delete a folder + * @throws {Error} If document cannot be deleted + */ + public async delete(uid: string): Promise { + const officeFolderEntity = await this.officeFoldersRepository.findOneByUid(uid, { customers: true }); + if (!officeFolderEntity) throw new Error("office folder not found"); + const officeFolder = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll" }); + + if (officeFolder.customers?.length) { + throw new Error("This folder is used by customers"); + } + return this.officeFoldersRepository.delete(uid); + } +} diff --git a/src/services/notary/OfficeRolesService/OfficeRolesService.ts b/src/services/notary/OfficeRolesService/OfficeRolesService.ts new file mode 100644 index 00000000..242f92ab --- /dev/null +++ b/src/services/notary/OfficeRolesService/OfficeRolesService.ts @@ -0,0 +1,35 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import OfficeRolesRepository from "@Repositories/OfficeRolesRepository"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class OfficeRolesService extends BaseService { + constructor(private officeRoleRepository: OfficeRolesRepository) { + super(); + } + + /** + * @description : Get all office roles + * @throws {Error} If office roles cannot be get + */ + public get(query: Prisma.OfficeRolesFindManyArgs) { + return this.officeRoleRepository.findMany(query); + } + + /** + * @description : Get a officeRole by uid + * @throws {Error} If officeRole cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.OfficeRolesInclude) { + return this.officeRoleRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a officeRole by uid + * @throws {Error} If officeRole cannot be get by uid + */ + public getByUidWithOffice(uid: string) { + return this.officeRoleRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/notary/OfficesService/OfficesService.ts b/src/services/notary/OfficesService/OfficesService.ts new file mode 100644 index 00000000..af25083b --- /dev/null +++ b/src/services/notary/OfficesService/OfficesService.ts @@ -0,0 +1,27 @@ +import { Prisma } from "@prisma/client"; +import OfficesRepository from "@Repositories/OfficesRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class OfficesService extends BaseService { + constructor(private officeRepository: OfficesRepository) { + super(); + } + + /** + * @description : Get all offices + * @throws {Error} If offices cannot be get + */ + public async get(query: Prisma.OfficesFindManyArgs) { + return this.officeRepository.findMany(query); + } + + /** + * @description : Get a office by uid + * @throws {Error} If office cannot be get + */ + public async getByUid(uid: string, query?: Prisma.OfficesInclude) { + return this.officeRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/notary/RolesService/RolesService.ts b/src/services/notary/RolesService/RolesService.ts new file mode 100644 index 00000000..6e652687 --- /dev/null +++ b/src/services/notary/RolesService/RolesService.ts @@ -0,0 +1,27 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import RolesRepository from "@Repositories/RolesRepository"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class RolesService extends BaseService { + constructor(private roleRepository: RolesRepository) { + super(); + } + + /** + * @description : Get all roles + * @throws {Error} If roles cannot be get + */ + public get(query: Prisma.RolesFindManyArgs) { + return this.roleRepository.findMany(query); + } + + /** + * @description : Get a role by uid + * @throws {Error} If role cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.RolesInclude) { + return this.roleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/notary/RulesService/RulesService.ts b/src/services/notary/RulesService/RulesService.ts new file mode 100644 index 00000000..c59c9133 --- /dev/null +++ b/src/services/notary/RulesService/RulesService.ts @@ -0,0 +1,27 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import RulesRepository from "@Repositories/RulesRepository"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class RulesService extends BaseService { + constructor(private ruleRepository: RulesRepository) { + super(); + } + + /** + * @description : Get all rules + * @throws {Error} If rules cannot be get + */ + public get(query: Prisma.RulesFindManyArgs) { + return this.ruleRepository.findMany(query); + } + + /** + * @description : Get a rule by uid + * @throws {Error} If rule cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.RulesInclude) { + return this.ruleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/notary/UsersService/UsersService.ts b/src/services/notary/UsersService/UsersService.ts new file mode 100644 index 00000000..5efbfff9 --- /dev/null +++ b/src/services/notary/UsersService/UsersService.ts @@ -0,0 +1,43 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import UsersRepository from "@Repositories/UsersRepository"; +import { Prisma } from "@prisma/client"; + +@Service() +export default class UsersService extends BaseService { + constructor(private userRepository: UsersRepository) { + super(); + } + + /** + * @description : Get all users + * @throws {Error} If users cannot be get + */ + public get(query: Prisma.UsersFindManyArgs) { + return this.userRepository.findMany(query); + } + + /** + * @description : Get a user by uid + * @throws {Error} If user cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.UsersInclude) { + return this.userRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a user by uid with office + * @throws {Error} If user cannot be get by uid + */ + public getByUidWithOffice(uid: string) { + return this.userRepository.findOneByUidWithOffice(uid); + } + + /** + * @description : Get a user by uid + * @throws {Error} If user cannot be get by uid + */ + public getByProvider(providerName: string, id: string) { + return this.userRepository.findOneByProvider(providerName, id); + } +} diff --git a/src/services/private-services/AddressesService/AddressesService.ts b/src/services/private-services/AddressesService/AddressesService.ts deleted file mode 100644 index 41e53765..00000000 --- a/src/services/private-services/AddressesService/AddressesService.ts +++ /dev/null @@ -1,26 +0,0 @@ -import AddressesRepository from "@Repositories/AddressesRepository"; -import BaseService from "@Services/BaseService"; -import { Service } from "typedi"; - -@Service() -export default class AddressesService extends BaseService { - constructor(private addressRepository: AddressesRepository) { - super(); - } - - /** - * @description : Get all addresses - * @throws {Error} If addresses cannot be get - */ - public async get(query: any) { - return this.addressRepository.findMany(query); - } - - /** - * @description : Get a address by uid - * @throws {Error} If address cannot be get - */ - public async getByUid(uid: string) { - return this.addressRepository.findOneByUid(uid); - } -} diff --git a/src/services/private-services/AuthService/AuthService.ts b/src/services/private-services/AuthService/AuthService.ts deleted file mode 100644 index ab528ec4..00000000 --- a/src/services/private-services/AuthService/AuthService.ts +++ /dev/null @@ -1,53 +0,0 @@ -import jwt from "jsonwebtoken"; -import BaseService from "@Services/BaseService"; -import "reflect-metadata"; -import { BackendVariables } from "@Common/config/variables/Variables"; -import Container, { Service } from "typedi"; - -type IdNotTokens = { - access_token: string; - id_token: string; -}; - -@Service() -export default class AuthService extends BaseService { - protected readonly variables = Container.get(BackendVariables); - private constructor() { - super(); - } - - /** - * @description : Get IdNot id_token and access_token - * @throws {Error} If jwt pair cannot be get - */ - public async getUserFromIdNotTokens(code: string) { - const tokens = await this.getIdNotTokens(code); - return jwt.decode(tokens.id_token); - } - - private async getIdNotTokens(code: string): Promise { - const url = new URL( - this.variables.IDNOT_CONNEXION_URL.concat("?") + - new URLSearchParams({ - client_id: this.variables.IDNOT_CLIENT_ID, - client_secret: this.variables.IDNOT_CLIENT_SECRET, - redirect_uri: this.variables.IDNOT_REDIRECT_URL, - code: code, - grant_type: "authorization_code", - }), - ); - try { - const headers = new Headers({ - "Content-Type": "application/x-www-form-urlencoded", - }); - const res = await fetch(url, { - method: "POST", - headers: headers, - }); - const data = await res.json(); - return data as IdNotTokens; - } catch (error) { - throw new Error(); - } - } -} diff --git a/src/services/private-services/ContactsService/ContactsService.ts b/src/services/private-services/ContactsService/ContactsService.ts deleted file mode 100644 index 4d381a84..00000000 --- a/src/services/private-services/ContactsService/ContactsService.ts +++ /dev/null @@ -1,26 +0,0 @@ -import ContactsRepository from "@Repositories/ContactsRepository"; -import BaseService from "@Services/BaseService"; -import { Service } from "typedi"; - -@Service() -export default class ContactsService extends BaseService { - constructor(private contactRepository: ContactsRepository) { - super(); - } - - /** - * @description : Get all contacts - * @throws {Error} If contacts cannot be get - */ - public async get(query: any) { - return this.contactRepository.findMany(query); - } - - /** - * @description : Get a contact by uid - * @throws {Error} If contact cannot be get - */ - public async getByUid(uid: string) { - return this.contactRepository.findOneByUid(uid); - } -} diff --git a/src/services/private-services/FilesService/FilesService.ts b/src/services/private-services/FilesService/FilesService.ts deleted file mode 100644 index 88e5948b..00000000 --- a/src/services/private-services/FilesService/FilesService.ts +++ /dev/null @@ -1,88 +0,0 @@ -import FilesRepository from "@Repositories/FilesRepository"; -import BaseService from "@Services/BaseService"; -import { Service } from "typedi"; -import { File } from "le-coffre-resources/dist/SuperAdmin"; -import CryptoService from "../CryptoService/CryptoService"; -import IpfsService from "../IpfsService/IpfsService"; -import { BackendVariables } from "@Common/config/variables/Variables"; -import { Readable } from "stream"; -import { v4 } from "uuid"; - -@Service() -export default class FilesService extends BaseService { - constructor( - private filesRepository: FilesRepository, - private ipfsService: IpfsService, - private variables: BackendVariables, - private cryptoService: CryptoService, - ) { - super(); - } - - /** - * @description : Get all files - * @throws {Error} If files cannot be ge - */ - public async get(query: any) { - return this.filesRepository.findMany(query); - } - - /** - * @description : Get a file by uid - * @throws {Error} If project cannot be created - */ - public async getByUid(uid: string) { - return this.filesRepository.findOneByUid(uid); - } - - /** - * @description : view a file - * @throws {Error} If file cannot be deleted - */ - public async updload(uid: string) { - const file = await this.filesRepository.findOneByUid(uid); - if (!file.key) throw new Error("file deleted"); - const fileResult = await fetch(file.file_path); - const fileContent = await fileResult.arrayBuffer(); - return await this.cryptoService.decrypt(Buffer.from(fileContent), file.key); - } - - /** - * @description : Create a new file - * @throws {Error} If file cannot be created - */ - public async create(file: File, fileData: Express.Multer.File) { - const key = v4(); - const encryptedFile = await this.cryptoService.encrypt(fileData.buffer, key); - //const encryptedFileName = await this.cryptoService.encrypt(Buffer.from(fileData.originalname, 'utf-8'), key); - const upload = await this.ipfsService.pinFile(Readable.from(encryptedFile), fileData.originalname); - file.file_name = fileData.originalname; //encryptedFileName.toString('utf-8') - file.file_path = this.variables.PINATA_GATEWAY.concat(upload.IpfsHash); - - return this.filesRepository.create(file, key); - } - - /** - * @description : Modify a new file - * @throws {Error} If file cannot be modified - */ - public async update(uid: string, file: File) { - return this.filesRepository.update(uid, file); - } - - /** - * @description : Delete a file - * @throws {Error} If file cannot be deleted - */ - public async delete(uid: string) { - try { - const fileToUnpin = await this.filesRepository.findOneByUid(uid); - const fileHash = fileToUnpin.file_path.substring(this.variables.PINATA_GATEWAY.length); - await this.ipfsService.unpinFile(fileHash); - } catch(error) { - console.error(error); - } - - return this.filesRepository.delete(uid); - } -} diff --git a/src/services/super-admin/AppointmentsService/AppointmentsService.ts b/src/services/super-admin/AppointmentsService/AppointmentsService.ts new file mode 100644 index 00000000..45d8b481 --- /dev/null +++ b/src/services/super-admin/AppointmentsService/AppointmentsService.ts @@ -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 { + 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 { + 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); + } + + +} diff --git a/src/services/super-admin/CustomersService/CustomersService.ts b/src/services/super-admin/CustomersService/CustomersService.ts index 80765051..5501e1cb 100644 --- a/src/services/super-admin/CustomersService/CustomersService.ts +++ b/src/services/super-admin/CustomersService/CustomersService.ts @@ -38,7 +38,15 @@ export default class CustomersService extends BaseService { * @description : Get a customer by uid * @throws {Error} If customer cannot be get by uid */ - public async getByUid(uid: string, query?: any): Promise { + public async getByUid(uid: string, query?: Prisma.CustomersInclude): Promise { return this.customerRepository.findOneByUid(uid, query); } + + /** + * @description : Get a customer by contact uid + * @throws {Error} If customer cannot be get by contact uid + */ + public async getByContact(contactUid: string): Promise { + return this.customerRepository.findOneByContact(contactUid); + } } diff --git a/src/services/super-admin/DeedTypesService/DeedTypesService.ts b/src/services/super-admin/DeedTypesService/DeedTypesService.ts index da71909e..4c94017e 100644 --- a/src/services/super-admin/DeedTypesService/DeedTypesService.ts +++ b/src/services/super-admin/DeedTypesService/DeedTypesService.ts @@ -1,4 +1,4 @@ -import { DeedTypes } from "@prisma/client"; +import { DeedTypes, Prisma } from "@prisma/client"; import DeedTypesRepository from "@Repositories/DeedTypesRepository"; import BaseService from "@Services/BaseService"; import { DeedType } from "le-coffre-resources/dist/SuperAdmin"; @@ -6,9 +6,7 @@ import { Service } from "typedi"; @Service() export default class DeedTypesService extends BaseService { - constructor( - private deedTypeRepository: DeedTypesRepository, - ) { + constructor(private deedTypeRepository: DeedTypesRepository) { super(); } @@ -16,7 +14,7 @@ export default class DeedTypesService extends BaseService { * @description : Get all deed-types * @throws {Error} If deed-types cannot be get */ - public async get(query: any): Promise { + public async get(query: Prisma.DeedTypesFindManyArgs) { return this.deedTypeRepository.findMany(query); } @@ -40,7 +38,15 @@ export default class DeedTypesService extends BaseService { * @description : Get a deedtype by uid * @throws {Error} If deed-type cannot be get by uid */ - public async getByUid(uid: string, query?: any) { + public async getByUid(uid: string, query?: Prisma.DeedTypesInclude): Promise { return this.deedTypeRepository.findOneByUid(uid, query); } + + /** + * @description : Get a deedtype by uid + * @throws {Error} If deed-type cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.deedTypeRepository.findOneByUidWithOffice(uid); + } } diff --git a/src/services/super-admin/DeedsService/DeedsService.ts b/src/services/super-admin/DeedsService/DeedsService.ts index 93a6c6bd..82e01e05 100644 --- a/src/services/super-admin/DeedsService/DeedsService.ts +++ b/src/services/super-admin/DeedsService/DeedsService.ts @@ -1,4 +1,4 @@ -import { Deeds } from "@prisma/client"; +import { Deeds, Prisma } from "@prisma/client"; import DeedsRepository from "@Repositories/DeedsRepository"; import BaseService from "@Services/BaseService"; import { Deed } from "le-coffre-resources/dist/SuperAdmin"; @@ -14,7 +14,7 @@ export default class DeedsService extends BaseService { * @description : Get all deeds * @throws {Error} If deeds cannot be get */ - public async get(query: any) { + public async get(query: Prisma.DeedsFindManyArgs) { return this.deedRepository.findMany(query); } @@ -38,7 +38,11 @@ export default class DeedsService extends BaseService { * @description : Get a deed by uid * @throws {Error} If deed-type cannot be get by uid */ - public async getByUid(uid: string, query?: any) { + public async getByUid(uid: string, query?: Prisma.DeedsInclude) { return this.deedRepository.findOneByUid(uid, query); } + + public async getByUidWithOffice(uid: string) { + return this.deedRepository.findOneByUidWithOffice(uid); + } } diff --git a/src/services/super-admin/DocumentTypesService/DocumentTypesService.ts b/src/services/super-admin/DocumentTypesService/DocumentTypesService.ts index dacfe17f..835c3485 100644 --- a/src/services/super-admin/DocumentTypesService/DocumentTypesService.ts +++ b/src/services/super-admin/DocumentTypesService/DocumentTypesService.ts @@ -1,4 +1,4 @@ -import { DocumentTypes } from "@prisma/client"; +import { DocumentTypes, Prisma } from "@prisma/client"; import DocumentTypesRepository from "@Repositories/DocumentTypesRepository"; import BaseService from "@Services/BaseService"; import { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; @@ -14,7 +14,7 @@ export default class DocumentTypesService extends BaseService { * @description : Get all document-types * @throws {Error} If document-types cannot be get */ - public async get(query: any) { + public async get(query: Prisma.DocumentTypesFindManyArgs) { return this.documentTypeRepository.findMany(query); } @@ -38,7 +38,15 @@ export default class DocumentTypesService extends BaseService { * @description : Get a document-type by uid * @throws {Error} If document-type is not found */ - public async getByUid(uid: string, query?: any) { + public async getByUid(uid: string, query?: Prisma.DocumentTypesInclude): Promise { return this.documentTypeRepository.findOneByUid(uid, query); } + + /** + * @description : Get a document-type by uid with relations + * @throws {Error} If document-type is not found + */ + public async getByUidWithOffice(uid: string) { + return this.documentTypeRepository.findOneByUidWithOffice(uid); + } } diff --git a/src/services/super-admin/DocumentsService/DocumentsService.ts b/src/services/super-admin/DocumentsService/DocumentsService.ts index 81a0d8bc..e488b1be 100644 --- a/src/services/super-admin/DocumentsService/DocumentsService.ts +++ b/src/services/super-admin/DocumentsService/DocumentsService.ts @@ -14,7 +14,7 @@ export default class DocumentsService extends BaseService { * @description : Get all documents * @throws {Error} If documents cannot be get */ - public async get(query: any) { + public async get(query: Prisma.DocumentsFindManyArgs) { return this.documentsRepository.findMany(query); } @@ -30,7 +30,7 @@ export default class DocumentsService extends BaseService { * @description : Create new documents * @throws {Error} If documents or one of them cannot be created */ - public async createMany(documents: Document[]): Promise { + public async createMany(documents: Document[]): Promise { return this.documentsRepository.createMany(documents); } @@ -38,7 +38,7 @@ export default class DocumentsService extends BaseService { * @description : Modify a document * @throws {Error} If document cannot be modified */ - public async update(uid: string, document: Document, refused_reason?: string): Promise { + public async update(uid: string, document: Partial, refused_reason?: string): Promise { return this.documentsRepository.update(uid, document, refused_reason); } @@ -46,11 +46,11 @@ export default class DocumentsService extends BaseService { * @description : Delete a document * @throws {Error} If document cannot be deleted */ - public async delete(uid: string): Promise { - const documentEntity = await this.documentsRepository.findOneByUid(uid, { files: true }); - + public async delete(uid: string): Promise { + const documentEntity = await this.documentsRepository.findOneByUid(uid, { files: true }); + if (!documentEntity) throw new Error("document not found"); const document = Document.hydrate(documentEntity, { strategy: "excludeAll" }); - + if (document.files && document.files.length !== 0) { throw new Error("Can't delete a document with file"); } @@ -61,7 +61,15 @@ export default class DocumentsService extends BaseService { * @description : Get a document by uid * @throws {Error} If document cannot be get by uid */ - public async getByUid(uid: string, query?: any) { + public async getByUid(uid: string, query?: Prisma.DocumentsInclude): Promise { return this.documentsRepository.findOneByUid(uid, query); } + + /** + * @description : Get a document by uid + * @throws {Error} If document cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.documentsRepository.findOneByUidWithOffice(uid); + } } diff --git a/src/services/super-admin/LiveVoteService/LiveVoteService.ts b/src/services/super-admin/LiveVoteService/LiveVoteService.ts new file mode 100644 index 00000000..5576bb28 --- /dev/null +++ b/src/services/super-admin/LiveVoteService/LiveVoteService.ts @@ -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 { + 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 { + 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!, { 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(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(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 { + const appointment = await this.getAppointmentWithVotes(vote); + + if (appointment) { + const appointmentEntity = Appointment.hydrate(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); + } +} diff --git a/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts b/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts index 128070e4..846a5982 100644 --- a/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts @@ -1,18 +1,18 @@ -import { OfficeFolders } from ".prisma/client"; +import { OfficeFolders } from ".prisma/client"; import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; import { Service } from "typedi"; import DeedTypesService from "../DeedTypesService/DeedTypesService"; import DeedsRepository from "@Repositories/DeedsRepository"; - +import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository + private deedRepository: DeedsRepository, ) { super(); } @@ -21,7 +21,7 @@ export default class OfficeFoldersService extends BaseService { * @description : Get all folders * @throws {Error} If folders cannot be get */ - public async get(query: any) { + public async get(query: Prisma.OfficeFoldersFindManyArgs) { return this.officeFoldersRepository.findMany(query); } @@ -31,7 +31,8 @@ export default class OfficeFoldersService extends BaseService { */ public async create(officeFolderEntity: OfficeFolder): Promise { const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if(deedType.archived_at) throw new Error('deed type is archived'); + if (!deedType) throw new Error("deed type not found"); + if (deedType.archived_at) throw new Error("deed type is archived"); const deed = await this.deedRepository.create(officeFolderEntity.deed!); officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); @@ -49,19 +50,28 @@ export default class OfficeFoldersService extends BaseService { * @description : Get a folder by uid * @throws {Error} If folder cannot be get by uid */ - public async getByUid(uid: string, query?: any) { + public async getByUid(uid: string, query?: Prisma.OfficeFoldersInclude) { return this.officeFoldersRepository.findOneByUid(uid, query); } + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUidWithOffice(uid: string) { + return this.officeFoldersRepository.findOneByUidWithOffice(uid); + } + /** * @description : Delete a folder * @throws {Error} If document cannot be deleted */ - public async delete(uid: string): Promise { - const officeFolderEntity = await this.officeFoldersRepository.findOneByUid(uid, { office_folder_has_customers: true }); + public async delete(uid: string): Promise { + const officeFolderEntity = await this.officeFoldersRepository.findOneByUid(uid, { customers: true }); + if (!officeFolderEntity) throw new Error("office folder not found"); const officeFolder = OfficeFolder.hydrate(officeFolderEntity, { strategy: "excludeAll" }); - - if (officeFolder.office_folder_has_customers && officeFolder.office_folder_has_customers.length !== 0) { + + if (officeFolder.customers?.length) { throw new Error("This folder is used by customers"); } return this.officeFoldersRepository.delete(uid); diff --git a/src/services/super-admin/OfficeRolesService/OfficeRolesService.ts b/src/services/super-admin/OfficeRolesService/OfficeRolesService.ts new file mode 100644 index 00000000..1dac2ba3 --- /dev/null +++ b/src/services/super-admin/OfficeRolesService/OfficeRolesService.ts @@ -0,0 +1,52 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; +import OfficeRolesRepository from "@Repositories/OfficeRolesRepository"; +import { OfficeRole } from "le-coffre-resources/dist/SuperAdmin"; +import { Prisma, OfficeRoles } from "@prisma/client"; + +@Service() +export default class OfficeRolesService extends BaseService { + constructor(private officeRoleRepository: OfficeRolesRepository) { + super(); + } + + /** + * @description : Get all office roles + * @throws {Error} If office roles cannot be get + */ + public get(query: Prisma.OfficeRolesFindManyArgs) { + return this.officeRoleRepository.findMany(query); + } + + /** + * @description : Create a officeRole + * @throws {Error} If officeRole couldn't be created + */ + public create(officeRoleEntity: OfficeRole): Promise { + return this.officeRoleRepository.create(officeRoleEntity); + } + + /** + * @description : Modify a officeRole + * @throws {Error} If officeRole modification failed + */ + public update(officeRoleEntity: OfficeRole): Promise { + return this.officeRoleRepository.update(officeRoleEntity); + } + + /** + * @description : Get a officeRole by uid + * @throws {Error} If officeRole cannot be get by uid + */ + public getByUid(uid: string, query?: Prisma.OfficeRolesInclude) { + return this.officeRoleRepository.findOneByUid(uid, query); + } + + /** + * @description : Get a officeRole by uid + * @throws {Error} If officeRole cannot be get by uid + */ + public getByUidWithOffice(uid: string) { + return this.officeRoleRepository.findOneByUidWithOffice(uid); + } +} diff --git a/src/services/super-admin/OfficesService/OfficesService.ts b/src/services/super-admin/OfficesService/OfficesService.ts index 4de766be..441da71b 100644 --- a/src/services/super-admin/OfficesService/OfficesService.ts +++ b/src/services/super-admin/OfficesService/OfficesService.ts @@ -38,7 +38,7 @@ export default class OfficesService extends BaseService { * @description : Get a office by uid * @throws {Error} If office cannot be get */ - public async getByUid(uid: string, query?: any): Promise { + public async getByUid(uid: string, query?: any): Promise { return this.officeRepository.findOneByUid(uid, query); } } diff --git a/src/services/super-admin/RolesService/RolesService.ts b/src/services/super-admin/RolesService/RolesService.ts new file mode 100644 index 00000000..b26dd317 --- /dev/null +++ b/src/services/super-admin/RolesService/RolesService.ts @@ -0,0 +1,45 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import RolesRepository from "@Repositories/RolesRepository"; +import { Role } from "le-coffre-resources/dist/SuperAdmin"; +import { Prisma, Roles } from "@prisma/client"; + +@Service() +export default class RolesService extends BaseService { + constructor(private roleRepository: RolesRepository) { + super(); + } + + /** + * @description : Get all roles + * @throws {Error} If roles cannot be get + */ + public get(query: Prisma.RolesFindManyArgs): Promise { + return this.roleRepository.findMany(query); + } + + /** + * @description : Create a role + * @throws {Error} If role couldn't be created + */ + public create(roleEntity: Role): Promise { + return this.roleRepository.create(roleEntity); + } + + /** + * @description : Modify a role + * @throws {Error} If role modification failed + */ + public update(roleEntity: Role): Promise { + return this.roleRepository.update(roleEntity); + } + + /** + * @description : Get a role by uid + * @throws {Error} If role cannot be get by uid + */ + public getByUid(uid: string, query?: any): Promise { + return this.roleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/super-admin/RulesService/RulesService.ts b/src/services/super-admin/RulesService/RulesService.ts new file mode 100644 index 00000000..053c2cce --- /dev/null +++ b/src/services/super-admin/RulesService/RulesService.ts @@ -0,0 +1,45 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import RulesRepository from "@Repositories/RulesRepository"; +import { Rule } from "le-coffre-resources/dist/SuperAdmin"; +import { Prisma, Rules } from "@prisma/client"; + +@Service() +export default class RulesService extends BaseService { + constructor(private ruleRepository: RulesRepository) { + super(); + } + + /** + * @description : Get all rules + * @throws {Error} If rules cannot be get + */ + public get(query: Prisma.RulesFindManyArgs): Promise { + return this.ruleRepository.findMany(query); + } + + /** + * @description : Create a rule + * @throws {Error} If rule couldn't be created + */ + public create(ruleEntity: Rule): Promise { + return this.ruleRepository.create(ruleEntity); + } + + /** + * @description : Modify a rule + * @throws {Error} If rule modification failed + */ + public update(ruleEntity: Rule): Promise { + return this.ruleRepository.update(ruleEntity); + } + + /** + * @description : Get a rule by uid + * @throws {Error} If rule cannot be get by uid + */ + public getByUid(uid: string, query?: any): Promise { + return this.ruleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/super-admin/UsersService/UsersService.ts b/src/services/super-admin/UsersService/UsersService.ts index fcdbf428..241cb1e4 100644 --- a/src/services/super-admin/UsersService/UsersService.ts +++ b/src/services/super-admin/UsersService/UsersService.ts @@ -3,7 +3,7 @@ import "reflect-metadata"; import { Service } from "typedi"; import UsersRepository from "@Repositories/UsersRepository"; import User from "le-coffre-resources/dist/SuperAdmin"; -import {Prisma, Users } from "@prisma/client"; +import { Prisma, Users } from "@prisma/client"; @Service() export default class UsersService extends BaseService { @@ -15,7 +15,7 @@ export default class UsersService extends BaseService { * @description : Get all users * @throws {Error} If users cannot be get */ - public get(query: Prisma.UsersFindManyArgs): Promise { + public get(query: Prisma.UsersFindManyArgs) { return this.userRepository.findMany(query); } @@ -39,7 +39,31 @@ export default class UsersService extends BaseService { * @description : Get a user by uid * @throws {Error} If user cannot be get by uid */ - public getByUid(uid: string, query?: any): Promise { + public getByUid(uid: string, query?: Prisma.UsersInclude) { return this.userRepository.findOneByUid(uid, query); } + + /** + * @description : Get a user by uid with office + * @throws {Error} If user cannot be get by uid + */ + public getByUidWithOffice(uid: string) { + 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 + */ + public getByProvider(providerName: string, id: string) { + return this.userRepository.findOneByProvider(providerName, id); + } } diff --git a/src/services/super-admin/VotesService/VotesService.ts b/src/services/super-admin/VotesService/VotesService.ts new file mode 100644 index 00000000..fa32fb4d --- /dev/null +++ b/src/services/super-admin/VotesService/VotesService.ts @@ -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); + } +} diff --git a/src/test/config/Init.ts b/src/test/config/Init.ts index 033fc8f1..c3921d70 100644 --- a/src/test/config/Init.ts +++ b/src/test/config/Init.ts @@ -1,5 +1,17 @@ -import { Customers, DeedTypes, DocumentTypes, ECivility, ECustomerStatus, Offices, PrismaClient, Users } from "@prisma/client"; -import User, { Customer, DeedType, DocumentType, Office } from "le-coffre-resources/dist/SuperAdmin"; +import { + Customers, + DeedTypes, + DocumentTypes, + ECivility, + ECustomerStatus, + Offices, + Prisma, + PrismaClient, + Roles, + Rules, + Users, +} from "@prisma/client"; +import User, { Customer, DeedType, DocumentType, Office, Role, Rule } from "le-coffre-resources/dist/SuperAdmin"; const prisma = new PrismaClient(); @@ -32,90 +44,122 @@ export const initDocumentType = (documentType: DocumentType, office: Office): Pr }); }; -export const initDeedType = (deedType: DeedType, office: Office, documentTypes?: string[]): Promise => { - return prisma.deedTypes.create({ +export const initDeedType = (deedType: DeedType): Promise => { + const createArgs: Prisma.DeedTypesCreateArgs = { data: { name: deedType.name, description: deedType.description, - archived_at: null, - office_uid: office.uid!, - deed_type_has_document_types: { - createMany: { - data: documentTypes!.map((documentType) => ({ - document_type_uid: documentType, - })), - skipDuplicates: true, + office: { + connect: { + uid: deedType.office!.uid, + }, + }, + }, + }; + if (deedType.document_types) { + createArgs.data.document_types = { + connect: deedType.document_types.map((documentType) => ({ + uid: documentType.uid, + })), + }; + } + return prisma.deedTypes.create(createArgs); +}; + +export const initCustomers = (customer: Customer): Promise => { + return prisma.customers.create({ + data: { + status: ECustomerStatus.PENDING, + contact: { + create: { + first_name: customer.contact!.first_name, + last_name: customer.contact!.last_name, + email: customer.contact!.email, + phone_number: customer.contact!.phone_number, + cell_phone_number: customer.contact!?.cell_phone_number, + civility: ECivility[customer.contact!.civility as keyof typeof ECivility], + address: { + create: { + address: customer.contact!.address!.address, + zip_code: customer.contact!.address!.zip_code, + city: customer.contact!.address!.city, + }, + }, }, }, }, }); }; -export const initCustomers = (customer: Customer): Promise => { - return prisma.customers.create({ +export const initRules = (rule: Rule): Promise => { + return prisma.rules.create({ data: { - status: ECustomerStatus.PENDING, - contact: { - create: { - first_name: customer.contact!.first_name, - last_name: customer.contact!.last_name, - email: customer.contact!.email, - phone_number: customer.contact!.phone_number, - cell_phone_number: customer.contact!?.cell_phone_number, - civility: ECivility[customer.contact!.civility as keyof typeof ECivility], - address: { - create: { - address: customer.contact!.address!.address, - zip_code: customer.contact!.address!.zip_code, - city: customer.contact!.address!.city, - }, - }, - }, - }, - }, + name: rule.name, + label: rule.label, + }, + }); +}; + +export const initRoles = (role: Role): Promise => { + return prisma.roles.create({ + data: { + name: role.name, + label: role.label, + }, }); }; export const initUsers = (user: User): Promise => { return prisma.users.create({ data: { - idNot: user.idNot, - office_membership: { - connectOrCreate: { - where: { - idNot: user.office_membership!.idNot, - }, - create: { - idNot: user.office_membership!.idNot, - name: user.office_membership!.name, - crpcen: user.office_membership!.crpcen, - address: { - create: { - address: user.office_membership!.address!.address, - zip_code: user.office_membership!.address!.zip_code, - city: user.office_membership!.address!.city, - }, - }, - }, - }, - }, - contact: { - create: { - first_name: user.contact!.first_name, - last_name: user.contact!.last_name, - email: user.contact!.email, - phone_number: user.contact!.phone_number, - cell_phone_number: user.contact!.cell_phone_number, - civility: ECivility[user.contact!.civility as keyof typeof ECivility], - address: { - create: { - address: user.contact!.address!.address, - zip_code: user.contact!.address!.zip_code, - city: user.contact!.address!.city, - }, - }, - }, - }, - }, - }); + idNot: user.idNot, + office_membership: { + connectOrCreate: { + where: { + idNot: user.office_membership!.idNot, + }, + create: { + idNot: user.office_membership!.idNot, + name: user.office_membership!.name, + crpcen: user.office_membership!.crpcen, + address: { + create: { + address: user.office_membership!.address!.address, + zip_code: user.office_membership!.address!.zip_code, + city: user.office_membership!.address!.city, + }, + }, + }, + }, + }, + contact: { + create: { + first_name: user.contact!.first_name, + last_name: user.contact!.last_name, + email: user.contact!.email, + phone_number: user.contact!.phone_number, + cell_phone_number: user.contact!.cell_phone_number, + civility: ECivility[user.contact!.civility as keyof typeof ECivility], + address: { + create: { + address: user.contact!.address!.address, + zip_code: user.contact!.address!.zip_code, + city: user.contact!.address!.city, + }, + }, + }, + }, + role: { + connectOrCreate: { + where: { + uid: user.role!.uid, + }, + create: { + name: user.role!.name, + label: user.role!.label + }, + }, + }, + }, + }); }; diff --git a/src/test/config/MockedData.ts b/src/test/config/MockedData.ts index 051fe912..8496964a 100644 --- a/src/test/config/MockedData.ts +++ b/src/test/config/MockedData.ts @@ -1,4 +1,4 @@ -import { EOfficeStatus } from "le-coffre-resources/dist/Customer/Office"; +import { EOfficeStatus } from "le-coffre-resources/dist/Notary/Office"; import User, { Address, Contact, Office, DeedType, DocumentType, Customer, OfficeFolder, Deed } from "le-coffre-resources/dist/SuperAdmin"; export const userAddress: Address = { @@ -144,14 +144,7 @@ export const deedType: DeedType = { office: office, created_at: null, updated_at: null, - deed_type_has_document_types: [ - { - document_type: documentType, - deed_type: new DeedType(), - created_at: null, - updated_at: null, - }, - ], + document_types: [documentType], }; export const deedType_: DeedType = { @@ -197,34 +190,8 @@ export const officeFolder: OfficeFolder = { status: "ARCHIVED", deed: deed, office: office, - office_folder_has_customers: [ - { - customer: customer, - office_folder: new OfficeFolder(), - created_at: null, - updated_at: null, - }, - { - customer: customer_, - office_folder: new OfficeFolder(), - created_at: null, - updated_at: null, - }, - ], - office_folder_has_stakeholder: [ - { - user_stakeholder: user, - office_folder: new OfficeFolder(), - created_at: null, - updated_at: null, - }, - { - user_stakeholder: user_, - office_folder: new OfficeFolder(), - created_at: null, - updated_at: null, - }, - ], + customers: [customer, customer_], + stakeholders: [user, user_], created_at: null, updated_at: null, }; diff --git a/src/test/services/super-admin/CustomersService.test.ts b/src/test/services/super-admin/CustomersService.test.ts index 7ea5944c..4b3f383e 100644 --- a/src/test/services/super-admin/CustomersService.test.ts +++ b/src/test/services/super-admin/CustomersService.test.ts @@ -151,7 +151,7 @@ describe("test update function", () => { describe("test get function", () => { it("should return an array of Customers", async () => { - const req = {} + const req = {}; const customers = await CustomersServiceTest.get(req); // verify result typing diff --git a/src/test/services/super-admin/DeedService.test.ts b/src/test/services/super-admin/DeedService.test.ts index 6e67e3fd..2628cff0 100644 --- a/src/test/services/super-admin/DeedService.test.ts +++ b/src/test/services/super-admin/DeedService.test.ts @@ -16,7 +16,7 @@ beforeAll(async () => { office.uid = (await initOffice(office)).uid; documentType.uid = (await initDocumentType(documentType, office)).uid; documentType_.uid = (await initDocumentType(documentType_, office)).uid; - deedType.uid = (await initDeedType(deedType, office, [documentType.uid])).uid; + deedType.uid = (await initDeedType(deedType)).uid; }); afterAll(async () => { @@ -46,9 +46,9 @@ describe("test create function", () => { }); it("should have by default the same document types as its deed type ", async () => { - const deedWithDocumentTypes = await prisma.deeds.findFirstOrThrow({ include: { deed_has_document_types: true } }); - expect(deedWithDocumentTypes.deed_has_document_types.length).toEqual(1); - expect(deedWithDocumentTypes.deed_has_document_types[0]?.document_type_uid).toEqual(documentType.uid); + const deedWithDocumentTypes = await prisma.deeds.findFirstOrThrow({ include: { document_types: true } }); + expect(deedWithDocumentTypes.document_types.length).toEqual(1); + expect(deedWithDocumentTypes.document_types[0]?.uid).toEqual(documentType.uid); }); it("should create a the same deed based on existing deed type", async () => { @@ -83,20 +83,7 @@ describe("test update function", () => { const deedUid = (await prisma.deeds.findFirstOrThrow({ where: { deed_type_uid: deedType.uid } })).uid; let deedToUpdate: Deed = JSON.parse(JSON.stringify(deed)); - deedToUpdate.deed_has_document_types = [ - { - document_type: documentType, - deed: new Deed(), - created_at: null, - updated_at: null, - }, - { - document_type: documentType_, - deed: new Deed(), - created_at: null, - updated_at: null, - }, - ]; + deedToUpdate.document_types = [documentType, documentType_]; await DeedServiceTest.update(deedUid, deedToUpdate); @@ -105,30 +92,17 @@ describe("test update function", () => { uid: deedUid, }, include: { - deed_has_document_types: true, + document_types: true, }, }); - expect(deedUpdated.deed_has_document_types.length).toEqual(2); + expect(deedUpdated.document_types.length).toEqual(2); }); it("should not add document types to a deed type that already has those document types ", async () => { const deedUid = (await prisma.deeds.findFirstOrThrow({ where: { deed_type_uid: deedType.uid } })).uid; let deedToUpdate: Deed = JSON.parse(JSON.stringify(deed)); - deedToUpdate.deed_has_document_types = [ - { - document_type: documentType, - deed: new Deed(), - created_at: null, - updated_at: null, - }, - { - document_type: documentType_, - deed: new Deed(), - created_at: null, - updated_at: null, - }, - ]; + deedToUpdate.document_types = [documentType, documentType_]; await DeedServiceTest.update(deedUid, deedToUpdate); @@ -137,10 +111,10 @@ describe("test update function", () => { uid: deedUid, }, include: { - deed_has_document_types: true, + document_types: true, }, }); - expect(deedUpdated.deed_has_document_types.length).toEqual(2); + expect(deedUpdated.document_types.length).toEqual(2); }); it("should delete document types from a deed", async () => { @@ -148,7 +122,7 @@ describe("test update function", () => { let deedToUpdate: Deed = JSON.parse(JSON.stringify(deed)); // set relation between deed and document types empty - deedToUpdate.deed_has_document_types = []; + deedToUpdate.document_types = []; await DeedServiceTest.update(deedUid, deedToUpdate); @@ -157,10 +131,10 @@ describe("test update function", () => { uid: deedUid, }, include: { - deed_has_document_types: true, + document_types: true, }, }); - expect(deedUpdated.deed_has_document_types.length).toEqual(0); + expect(deedUpdated.document_types.length).toEqual(0); }); }); diff --git a/src/test/services/super-admin/DeedTypesService.test.ts b/src/test/services/super-admin/DeedTypesService.test.ts index af923ad1..8e66eb54 100644 --- a/src/test/services/super-admin/DeedTypesService.test.ts +++ b/src/test/services/super-admin/DeedTypesService.test.ts @@ -188,20 +188,7 @@ describe("test update function", () => { const deedTypeUid = (await prisma.deedTypes.findFirstOrThrow({ where: { name: deedType.name, office_uid: office.uid } })).uid; let deedTypeToUpdate: DeedType = JSON.parse(JSON.stringify(deedType)); - deedTypeToUpdate.deed_type_has_document_types = [ - { - document_type: documentType, - deed_type: new DeedType(), - created_at: null, - updated_at: null, - }, - { - document_type: documentType_, - deed_type: new DeedType(), - created_at: null, - updated_at: null, - }, - ]; + deedTypeToUpdate.document_types = [documentType, documentType_]; await DeedTypeServiceTest.update(deedTypeUid, deedTypeToUpdate); @@ -210,30 +197,17 @@ describe("test update function", () => { uid: deedTypeUid, }, include: { - deed_type_has_document_types: true, + document_types: true, }, }); - expect(deedTypeUpdated.deed_type_has_document_types.length).toEqual(2); + expect(deedTypeUpdated.document_types.length).toEqual(2); }); it("should not add document types to a deed type that already has those document types ", async () => { const deedTypeUid = (await prisma.deedTypes.findFirstOrThrow({ where: { name: deedType.name, office_uid: office.uid } })).uid; let deedTypeToUpdate: DeedType = JSON.parse(JSON.stringify(deedType)); - deedTypeToUpdate.deed_type_has_document_types = [ - { - document_type: documentType, - deed_type: new DeedType(), - created_at: null, - updated_at: null, - }, - { - document_type: documentType_, - deed_type: new DeedType(), - created_at: null, - updated_at: null, - }, - ]; + deedTypeToUpdate.document_types = [documentType, documentType_]; await DeedTypeServiceTest.update(deedTypeUid, deedTypeToUpdate); @@ -242,10 +216,10 @@ describe("test update function", () => { uid: deedTypeUid, }, include: { - deed_type_has_document_types: true, + document_types: true, }, }); - expect(deedTypeUpdated.deed_type_has_document_types.length).toEqual(2); + expect(deedTypeUpdated.document_types.length).toEqual(2); }); it("should delete document types from a deed", async () => { @@ -253,7 +227,7 @@ describe("test update function", () => { let deedTypeToUpdate: DeedType = JSON.parse(JSON.stringify(deedType)); // set relation between deed and document types empty - deedTypeToUpdate.deed_type_has_document_types = []; + deedTypeToUpdate.document_types = []; await DeedTypeServiceTest.update(deedTypeUid, deedTypeToUpdate); @@ -262,10 +236,10 @@ describe("test update function", () => { uid: deedTypeUid, }, include: { - deed_type_has_document_types: true, + document_types: true, }, }); - expect(deedTypeUpdated.deed_type_has_document_types.length).toEqual(0); + expect(deedTypeUpdated.document_types.length).toEqual(0); }); }); @@ -295,7 +269,7 @@ describe("test get function", () => { }); it("should return an array of DeedTypes per offices", async () => { - const deedTypesForFirstOffice = await DeedTypeServiceTest.get({ where: { office: {uid: office.uid} }, orderBy: { name: "asc" } }); + const deedTypesForFirstOffice = await DeedTypeServiceTest.get({ where: { office: { uid: office.uid } }, orderBy: { name: "asc" } }); expect(deedTypesForFirstOffice.length).toEqual(1); @@ -305,7 +279,10 @@ describe("test get function", () => { expect(deedTypesForFirstOffice[0]?.archived_at).toBeNull(); expect(deedTypesForFirstOffice[0]?.office_uid).toEqual(office.uid); - const deedTypesForSecondOffice = await DeedTypeServiceTest.get({ where: { office: {uid: office_.uid} }, orderBy: { name: "asc" } }); + const deedTypesForSecondOffice = await DeedTypeServiceTest.get({ + where: { office: { uid: office_.uid } }, + orderBy: { name: "asc" }, + }); expect(deedTypesForSecondOffice.length).toEqual(2); diff --git a/src/test/services/super-admin/DocumentTypesService.test.ts b/src/test/services/super-admin/DocumentTypesService.test.ts index b6d98045..821a455f 100644 --- a/src/test/services/super-admin/DocumentTypesService.test.ts +++ b/src/test/services/super-admin/DocumentTypesService.test.ts @@ -241,7 +241,10 @@ describe("test get function", () => { }); it("should return an array of DocumentTypes per offices", async () => { - const documentTypesForFirstOffice = await DocumentTypesServiceTest.get({ where: { office: {uid : office.uid }}, orderBy: { name: "asc" } }); + const documentTypesForFirstOffice = await DocumentTypesServiceTest.get({ + where: { office: { uid: office.uid } }, + orderBy: { name: "asc" }, + }); expect(documentTypesForFirstOffice.length).toEqual(1); @@ -252,7 +255,10 @@ describe("test get function", () => { expect(documentTypesForFirstOffice[0]?.archived_at).toBeNull(); expect(documentTypesForFirstOffice[0]?.office_uid).toEqual(office.uid); - const documentTypesForSecondOffice = await DocumentTypesServiceTest.get({ where: { office: {uid : office_.uid }}, orderBy: { name: "asc" } }); + const documentTypesForSecondOffice = await DocumentTypesServiceTest.get({ + where: { office: { uid: office_.uid } }, + orderBy: { name: "asc" }, + }); expect(documentTypesForSecondOffice.length).toEqual(2); diff --git a/src/test/services/super-admin/OfficeFolderService.test.ts b/src/test/services/super-admin/OfficeFolderService.test.ts index c0c52549..909a6ddd 100644 --- a/src/test/services/super-admin/OfficeFolderService.test.ts +++ b/src/test/services/super-admin/OfficeFolderService.test.ts @@ -1,7 +1,18 @@ import "module-alias/register"; import "reflect-metadata"; -import { OfficeFolderHasCustomers, OfficeFolderHasStakeholders, PrismaClient } from "prisma/prisma-client"; -import { customer, customer_, deedType, documentType, documentType_, office, officeFolder, officeFolder_, user, user_ } from "@Test/config/MockedData"; +import { PrismaClient } from "prisma/prisma-client"; +import { + customer, + customer_, + deedType, + documentType, + documentType_, + office, + officeFolder, + officeFolder_, + user, + user_, +} from "@Test/config/MockedData"; import Container from "typedi"; import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import OfficeFolderService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; @@ -12,13 +23,17 @@ import DeedsRepository from "@Repositories/DeedsRepository"; const prisma = new PrismaClient(); -const OfficeFolderServiceTest = new OfficeFolderService(Container.get(OfficeFoldersRepository), Container.get(DeedTypesService), Container.get(DeedsRepository)); +const OfficeFolderServiceTest = new OfficeFolderService( + Container.get(OfficeFoldersRepository), + Container.get(DeedTypesService), + Container.get(DeedsRepository), +); beforeAll(async () => { office.uid = (await initOffice(office)).uid; documentType.uid = (await initDocumentType(documentType, office)).uid; documentType_.uid = (await initDocumentType(documentType_, office)).uid; - deedType.uid = (await initDeedType(deedType, office, [documentType.uid])).uid; + deedType.uid = (await initDeedType(deedType)).uid; user.uid = (await initUsers(user)).uid; user_.uid = (await initUsers(user_)).uid; customer.uid = (await initCustomers(customer)).uid; @@ -48,7 +63,7 @@ describe("test create function", () => { }); it("should not create a new office folder if deed type is archived", async () => { - let officeFolderWithArchivatedDeedType: OfficeFolder = JSON.parse(JSON.stringify(officeFolder)); + let officeFolderWithArchivatedDeedType: OfficeFolder = JSON.parse(JSON.stringify(officeFolder)); // try to create a new deed with unknown deed type async function createOfficeFolderWithArchivedDeedType() { await OfficeFolderServiceTest.create(officeFolderWithArchivatedDeedType); @@ -72,40 +87,9 @@ describe("test create function", () => { it("should contains stakeholders", async () => { const officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_stakeholder: true }, + include: { stakeholders: true }, }); - const stakeholderRelation = await prisma.officeFolderHasStakeholders.findUniqueOrThrow({ - where: { - office_folder_uid_user_stakeholder_uid: { - user_stakeholder_uid: user.uid!, - office_folder_uid: officeFolderCreated.uid, - }, - }, - }); - const stakeholderRelation_ = await prisma.officeFolderHasStakeholders.findUniqueOrThrow({ - where: { - office_folder_uid_user_stakeholder_uid: { - user_stakeholder_uid: user_.uid!, - office_folder_uid: officeFolderCreated.uid, - }, - }, - }); - expect(officeFolderCreated.office_folder_has_stakeholder.length).toEqual(2); - const stakeholder: OfficeFolderHasStakeholders = { - uid: stakeholderRelation.uid, - office_folder_uid: officeFolderCreated.uid, - user_stakeholder_uid: user.uid!, - created_at: officeFolderCreated.created_at, - updated_at: officeFolderCreated.updated_at, - }; - const stakeholder_: OfficeFolderHasStakeholders = { - uid: stakeholderRelation_.uid, - office_folder_uid: officeFolderCreated.uid, - user_stakeholder_uid: user_.uid!, - created_at: officeFolderCreated.created_at, - updated_at: officeFolderCreated.updated_at, - }; - expect(officeFolderCreated.office_folder_has_stakeholder).toEqual(expect.arrayContaining([stakeholder, stakeholder_])); + expect(officeFolderCreated.stakeholders).toEqual([user, user_]); }); it("should not create a new office folder with folder number already created", async () => { @@ -131,123 +115,51 @@ describe("test create function", () => { describe("test update function", () => { it("should add customers", async () => { let officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_customers: true }, + include: { customers: true }, }); - expect(officeFolderCreated.office_folder_has_customers).toEqual([]); + expect(officeFolderCreated.customers).toEqual([]); // mocked data contains the customers await OfficeFolderServiceTest.update(officeFolderCreated.uid, officeFolder); - const customerRelation = await prisma.officeFolderHasCustomers.findUniqueOrThrow({ - where: { - office_folder_uid_customer_uid: { - customer_uid: customer.uid!, - office_folder_uid: officeFolderCreated.uid, - }, - }, - }); - const customerRelation_ = await prisma.officeFolderHasCustomers.findUniqueOrThrow({ - where: { - office_folder_uid_customer_uid: { - customer_uid: customer_.uid!, - office_folder_uid: officeFolderCreated.uid, - }, - }, - }); - officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_customers: true }, + include: { customers: true }, }); - expect(officeFolderCreated.office_folder_has_customers.length).toEqual(2); - const officeFolderHasCustomer: OfficeFolderHasCustomers = { - uid: customerRelation.uid, - office_folder_uid: officeFolderCreated.uid, - customer_uid: customer.uid!, - created_at: customerRelation.created_at, - updated_at: customerRelation.updated_at, - }; - const officeFolderHasCustomer_: OfficeFolderHasCustomers = { - uid: customerRelation_.uid, - office_folder_uid: officeFolderCreated.uid, - customer_uid: customer_.uid!, - created_at: customerRelation_.created_at, - updated_at: customerRelation_.updated_at, - }; - expect(officeFolderCreated.office_folder_has_customers).toEqual( - expect.arrayContaining([officeFolderHasCustomer, officeFolderHasCustomer_]), - ); + expect(officeFolderCreated.customers.length).toEqual([customer, customer_].length); }); it("should remove customers", async () => { let officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_customers: true }, + include: { customers: true }, }); - expect(officeFolderCreated.office_folder_has_customers.length).toEqual(2); + expect(officeFolderCreated.customers.length).toEqual(2); let officeFolderWithLessCustomers: OfficeFolder = JSON.parse(JSON.stringify(officeFolder)); - officeFolderWithLessCustomers.office_folder_has_customers!.pop(); + officeFolderWithLessCustomers.customers!.pop(); // mocked data contains the customers await OfficeFolderServiceTest.update(officeFolderCreated.uid, officeFolderWithLessCustomers); - const customerRelation = await prisma.officeFolderHasCustomers.findUniqueOrThrow({ - where: { - office_folder_uid_customer_uid: { - customer_uid: customer.uid!, - office_folder_uid: officeFolderCreated.uid, - }, - }, - }); - - officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_customers: true }, - }); - - expect(officeFolderCreated.office_folder_has_customers.length).toEqual(1); - const officeFolderHasCustomer: OfficeFolderHasCustomers = { - uid: customerRelation.uid, - office_folder_uid: officeFolderCreated.uid, - customer_uid: customer.uid!, - created_at: customerRelation.created_at, - updated_at: customerRelation.updated_at, - }; - expect(officeFolderCreated.office_folder_has_customers).toEqual([officeFolderHasCustomer]); + expect(officeFolderCreated.customers.length).toEqual([customer]); }); it("should remove stakeholders", async () => { let officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_stakeholder: true }, + include: { stakeholders: true }, }); - expect(officeFolderCreated.office_folder_has_stakeholder.length).toEqual(2); + expect(officeFolderCreated.stakeholders.length).toEqual(2); let officeFolderWithLessStakeholders: OfficeFolder = JSON.parse(JSON.stringify(officeFolder)); - officeFolderWithLessStakeholders.office_folder_has_stakeholder!.pop(); + officeFolderWithLessStakeholders.stakeholders!.pop(); // mocked data contains the customers await OfficeFolderServiceTest.update(officeFolderCreated.uid, officeFolderWithLessStakeholders); - const stakeholderRelation = await prisma.officeFolderHasStakeholders.findUniqueOrThrow({ - where: { - office_folder_uid_user_stakeholder_uid: { - user_stakeholder_uid: user.uid!, - office_folder_uid: officeFolderCreated.uid, - }, - }, - }); - officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({ - include: { office_folder_has_stakeholder: true }, + include: { stakeholders: true }, }); - expect(officeFolderCreated.office_folder_has_stakeholder.length).toEqual(1); - const officeFolderHasStakeholder: OfficeFolderHasStakeholders = { - uid: stakeholderRelation.uid, - office_folder_uid: officeFolderCreated.uid, - user_stakeholder_uid: user.uid!, - created_at: stakeholderRelation.created_at, - updated_at: stakeholderRelation.updated_at, - }; - expect(officeFolderCreated.office_folder_has_stakeholder).toEqual([officeFolderHasStakeholder]); + expect(officeFolderCreated.stakeholders).toEqual([user]); }); it("should archivate an office folder", async () => { const officeFolderCreated = await prisma.officeFolders.findFirstOrThrow({}); diff --git a/tsconfig.json b/tsconfig.json index b0dd3f39..bd89006e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -69,7 +69,7 @@ "@ControllerPattern/*": [ "src/common/system/controller-pattern/*" ], - "@Test/*":[ + "@Test/*": [ "src/test/*" ], }, @@ -90,13 +90,12 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "allowJs": true, - "isolatedModules": true + "isolatedModules": true, }, "include": [ "**/*.ts", - "**/*.tsx", - "src/app/api/admin/UsersController.ts" -, "src/common/databases/seeders/seeder.ts" ], + "**/*.tsx", "src/services/common/TestService", + ], "exclude": [ "node_modules" ]