Preprod (#190)
This commit is contained in:
commit
a525214c62
3
.github/workflows/ppd.yml
vendored
3
.github/workflows/ppd.yml
vendored
@ -210,7 +210,8 @@ jobs:
|
|||||||
env_string=$(echo $env_string | sed 's/ $//')
|
env_string=$(echo $env_string | sed 's/ $//')
|
||||||
scw container container update ${{ env.CONTAINER_ID }} $env_string
|
scw container container update ${{ env.CONTAINER_ID }} $env_string
|
||||||
env:
|
env:
|
||||||
ENV_VARS: ${{ secrets.ENV_LECOFFRE }}
|
ENV_VARS: ${{ secrets.ENV }}
|
||||||
|
|
||||||
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
|
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
|
||||||
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
|
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
|
||||||
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
|
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
|
||||||
|
3
.github/workflows/prd.yml
vendored
3
.github/workflows/prd.yml
vendored
@ -208,7 +208,8 @@ jobs:
|
|||||||
env_string=$(echo $env_string | sed 's/ $//')
|
env_string=$(echo $env_string | sed 's/ $//')
|
||||||
scw container container update ${{ env.CONTAINER_ID }} $env_string
|
scw container container update ${{ env.CONTAINER_ID }} $env_string
|
||||||
env:
|
env:
|
||||||
ENV_VARS: ${{ secrets.ENV_LECOFFRE }}
|
ENV_VARS: ${{ secrets.ENV }}
|
||||||
|
|
||||||
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
|
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
|
||||||
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
|
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
|
||||||
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
|
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
|
||||||
|
5
.github/workflows/stg.yml
vendored
5
.github/workflows/stg.yml
vendored
@ -208,8 +208,9 @@ jobs:
|
|||||||
env_string=$(echo $env_string | sed 's/ $//')
|
env_string=$(echo $env_string | sed 's/ $//')
|
||||||
scw container container update ${{ env.CONTAINER_ID }} $env_string
|
scw container container update ${{ env.CONTAINER_ID }} $env_string
|
||||||
env:
|
env:
|
||||||
ENV_VARS: ${{ secrets.ENV_LECOFFRE }}
|
ENV_VARS: ${{ secrets.ENV }}
|
||||||
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
|
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
|
||||||
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
|
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
|
||||||
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
|
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
|
||||||
SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID_LECOFFRE }}
|
SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID_LECOFFRE }}
|
||||||
|
|
||||||
|
@ -15,13 +15,6 @@ RUN ssh-keyscan github.com smart-chain-fr/leCoffre-resources.git >> /root/.ssh/k
|
|||||||
|
|
||||||
RUN npm install --frozen-lockfile
|
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 tsconfig.json tsconfig.json
|
||||||
COPY src src
|
COPY src src
|
||||||
|
|
||||||
@ -35,11 +28,12 @@ WORKDIR leCoffre
|
|||||||
|
|
||||||
RUN adduser -D lecoffreuser --uid 10000 && chown -R lecoffreuser .
|
RUN adduser -D lecoffreuser --uid 10000 && chown -R lecoffreuser .
|
||||||
|
|
||||||
COPY --from=builder --chown=lecoffreuser leCoffre/node_modules ./node_modules
|
COPY --from=deps --chown=lecoffreuser leCoffre/node_modules ./node_modules
|
||||||
COPY --from=builder --chown=lecoffreuser leCoffre/dist dist
|
COPY --from=deps --chown=lecoffreuser leCoffre/dist dist
|
||||||
COPY --from=builder --chown=lecoffreuser leCoffre/package.json ./package.json
|
COPY --from=deps --chown=lecoffreuser leCoffre/package.json ./package.json
|
||||||
COPY --from=builder --chown=lecoffreuser leCoffre/src/common/databases ./src/common/databases
|
COPY --from=deps --chown=lecoffreuser leCoffre/src/common/databases ./src/common/databases
|
||||||
|
|
||||||
|
RUN apk update && apk add chromium
|
||||||
USER lecoffreuser
|
USER lecoffreuser
|
||||||
|
|
||||||
CMD ["npm", "run", "cron"]
|
CMD ["npm", "run", "cron"]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
dockerPullSecret: docker-pull-secret
|
-tpdockerPullSecret: docker-pull-secret
|
||||||
|
|
||||||
scwSecretKey: AgChoEnPitXp4Ny/rVMEcevaWKNVpyj2cJYAcq+yFqKwVwnLB+ffDvwqz9XBHu+6d4Nyyjkf37zUAMoaM21lEDWA7x3zfG2/D/j+rvX1qxzZgLD0mjBk7fGElVm332I6JA83oInes8AMMYEDPLElzHnpKRb9KtkIP4NzgOcCeW0ijft3N7Vroez6LEHsBPCA1I9XjKSkGEDvrO0MhWX3iJOlfz+SPMfJAV7rPawOs0ZmohTHrPW8qIvGDn8HCzKyU8zRBoMt+Ogpf5pH4U3JryEFuqD61KAQgablAM8edPIvsgNno9HAEuC2QtRLYA9aUhuKdaKuS58c9P2E80PHWXIlbpFCg6EugQTgNfnYp+3qDUNz8edeCfapYLvF4s9eCMGyMsGnpDR8EDNOyuGy7Y3l7okX8Xqu464gMp9E+hX7bHkcD6a4xfyIgJcWxsku0tm1TH1dpn4M1UXRuyZZif8P08nuE6MTUL67sAR9J1lpn4lVEL4kflk0pP2tZ5ncgPQFafJrRz05krMb0eU5tb2H4gs7ao/LL6idWo8MM9K1yr8lIuT5x2WW5CX+RjA+i50ex114V6vX3PNP5oVyt+DynTUB9QmXzVm3oLfDc3Cae1uqh7X0CFd+xiztJBtg0VtJaD/xUJcuWfY4cV2lERo9fRrykltzlJqiXHO4nowt8OtN0BcViVV8NJhPhYFzyb4ympxpOlTjm3GETuT2TYhUqdgS9nzleEAbOmOHZdIO2COunPE=
|
scwSecretKey: AgChoEnPitXp4Ny/rVMEcevaWKNVpyj2cJYAcq+yFqKwVwnLB+ffDvwqz9XBHu+6d4Nyyjkf37zUAMoaM21lEDWA7x3zfG2/D/j+rvX1qxzZgLD0mjBk7fGElVm332I6JA83oInes8AMMYEDPLElzHnpKRb9KtkIP4NzgOcCeW0ijft3N7Vroez6LEHsBPCA1I9XjKSkGEDvrO0MhWX3iJOlfz+SPMfJAV7rPawOs0ZmohTHrPW8qIvGDn8HCzKyU8zRBoMt+Ogpf5pH4U3JryEFuqD61KAQgablAM8edPIvsgNno9HAEuC2QtRLYA9aUhuKdaKuS58c9P2E80PHWXIlbpFCg6EugQTgNfnYp+3qDUNz8edeCfapYLvF4s9eCMGyMsGnpDR8EDNOyuGy7Y3l7okX8Xqu464gMp9E+hX7bHkcD6a4xfyIgJcWxsku0tm1TH1dpn4M1UXRuyZZif8P08nuE6MTUL67sAR9J1lpn4lVEL4kflk0pP2tZ5ncgPQFafJrRz05krMb0eU5tb2H4gs7ao/LL6idWo8MM9K1yr8lIuT5x2WW5CX+RjA+i50ex114V6vX3PNP5oVyt+DynTUB9QmXzVm3oLfDc3Cae1uqh7X0CFd+xiztJBtg0VtJaD/xUJcuWfY4cV2lERo9fRrykltzlJqiXHO4nowt8OtN0BcViVV8NJhPhYFzyb4ympxpOlTjm3GETuT2TYhUqdgS9nzleEAbOmOHZdIO2COunPE=
|
||||||
|
|
||||||
@ -18,10 +18,10 @@ lecoffreBack:
|
|||||||
limits:
|
limits:
|
||||||
memory: 2Gi
|
memory: 2Gi
|
||||||
ingress:
|
ingress:
|
||||||
host: api.ppd.lecoffre.smart-chain.fr
|
host: api-tp.ppd.lecoffre.smart-chain.fr
|
||||||
tls:
|
tls:
|
||||||
hosts:
|
hosts:
|
||||||
- api.ppd.lecoffre.smart-chain.fr
|
- api-tp.ppd.lecoffre.smart-chain.fr
|
||||||
secretName: api-tls
|
secretName: api-tls
|
||||||
annotations:
|
annotations:
|
||||||
kubernetes.io/ingress.class: nginx
|
kubernetes.io/ingress.class: nginx
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
"file-type-checker": "^1.0.8",
|
"file-type-checker": "^1.0.8",
|
||||||
"fp-ts": "^2.16.1",
|
"fp-ts": "^2.16.1",
|
||||||
"jsonwebtoken": "^9.0.0",
|
"jsonwebtoken": "^9.0.0",
|
||||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.119",
|
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.132",
|
||||||
"module-alias": "^2.2.2",
|
"module-alias": "^2.2.2",
|
||||||
"monocle-ts": "^2.3.13",
|
"monocle-ts": "^2.3.13",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
@ -70,6 +70,7 @@
|
|||||||
"prisma-query": "^2.0.0",
|
"prisma-query": "^2.0.0",
|
||||||
"puppeteer": "^21.3.4",
|
"puppeteer": "^21.3.4",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"stripe": "^14.22.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typedi": "^0.10.0",
|
"typedi": "^0.10.0",
|
||||||
|
@ -29,7 +29,7 @@ export default class OfficeRolesController extends ApiController {
|
|||||||
let query: Prisma.OfficeRolesFindManyArgs = {};
|
let query: Prisma.OfficeRolesFindManyArgs = {};
|
||||||
if (req.query["q"]) {
|
if (req.query["q"]) {
|
||||||
query = JSON.parse(req.query["q"] as string);
|
query = JSON.parse(req.query["q"] as string);
|
||||||
if(query.where?.uid) {
|
if (query.where?.uid) {
|
||||||
this.httpBadRequest(response, "You can't filter by uid");
|
this.httpBadRequest(response, "You can't filter by uid");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -75,6 +75,17 @@ export default class OfficeRolesController extends ApiController {
|
|||||||
//init IOfficeRole resource with request body values
|
//init IOfficeRole resource with request body values
|
||||||
const officeRoleEntity = OfficeRole.hydrate<OfficeRole>(req.body);
|
const officeRoleEntity = OfficeRole.hydrate<OfficeRole>(req.body);
|
||||||
|
|
||||||
|
const allRules = await this.rulesService.get({
|
||||||
|
where: {
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
namespace: "global",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
officeRoleEntity.rules = allRules;
|
||||||
//validate officeRole
|
//validate officeRole
|
||||||
await validateOrReject(officeRoleEntity, { groups: ["createOfficeRole"] });
|
await validateOrReject(officeRoleEntity, { groups: ["createOfficeRole"] });
|
||||||
|
|
||||||
@ -113,24 +124,27 @@ export default class OfficeRolesController extends ApiController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.body.rules) {
|
if (req.body.rules) {
|
||||||
const allRules = await this.rulesService.get({
|
const allRules = await this.rulesService.get({
|
||||||
where: {
|
where: {
|
||||||
OR: [
|
namespace: "global",
|
||||||
{
|
},
|
||||||
namespace: "notary",
|
});
|
||||||
},
|
|
||||||
{
|
const specificRules = await this.rulesService.get({
|
||||||
namespace: "collaborator",
|
where: {
|
||||||
},
|
namespace: "collaborator",
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
req.body.rules = req.body.rules.filter((rule: any) => {
|
req.body.rules = req.body.rules.filter((rule: any) => {
|
||||||
const ruleFound = allRules.find((r) => r.uid === rule.uid && (r.namespace === "notary" || r.namespace === "collaborator"));
|
const ruleFound = specificRules.find(
|
||||||
|
(r) => r.uid === rule.uid && (r.namespace === "collaborator"),
|
||||||
|
);
|
||||||
return ruleFound;
|
return ruleFound;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
req.body.rules = req.body.rules.concat(allRules);
|
||||||
}
|
}
|
||||||
//init IOfficeRole resource with request body values
|
//init IOfficeRole resource with request body values
|
||||||
const officeRoleEntity = OfficeRole.hydrate<OfficeRole>(req.body);
|
const officeRoleEntity = OfficeRole.hydrate<OfficeRole>(req.body);
|
||||||
|
49
src/app/api/admin/RulesGroupsController.ts
Normal file
49
src/app/api/admin/RulesGroupsController.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Controller, Get} from "@ControllerPattern/index";
|
||||||
|
import { Response, Request } from "express";
|
||||||
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { RulesGroup } from "le-coffre-resources/dist/Admin";
|
||||||
|
import roleHandler from "@App/middlewares/RolesHandler";
|
||||||
|
import authHandler from "@App/middlewares/AuthHandler";
|
||||||
|
import RulesGroupsService from "@Services/admin/RulesGroupsService/RulesGroupsService";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
@Service()
|
||||||
|
export default class RulesRoupsController extends ApiController {
|
||||||
|
constructor(private rulesGroupsService: RulesGroupsService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get all subscriptions
|
||||||
|
*/
|
||||||
|
@Get("/api/v1/admin/rules-groups", [authHandler, roleHandler] )
|
||||||
|
protected async get(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
//get query
|
||||||
|
let query: Prisma.RulesGroupsFindManyArgs = {};
|
||||||
|
if (req.query["q"]) {
|
||||||
|
query = JSON.parse(req.query["q"] as string);
|
||||||
|
if (query.where?.uid) {
|
||||||
|
this.httpBadRequest(response, "You can't filter by uid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//call service to get prisma entity
|
||||||
|
const rulesGroupsEntities = await this.rulesGroupsService.get(query);
|
||||||
|
|
||||||
|
//Hydrate ressource with prisma entity
|
||||||
|
const rulesGroups = RulesGroup.hydrateArray<RulesGroup>(rulesGroupsEntities, { strategy: "excludeAll" });
|
||||||
|
|
||||||
|
//success
|
||||||
|
this.httpSuccess(response, rulesGroups);
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
98
src/app/api/admin/StripeController.ts
Normal file
98
src/app/api/admin/StripeController.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import authHandler from "@App/middlewares/AuthHandler";
|
||||||
|
import ruleHandler from "@App/middlewares/RulesHandler";
|
||||||
|
// import roleHandler from "@App/middlewares/RolesHandler";
|
||||||
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
|
import { Controller, Get, Post} from "@ControllerPattern/index";
|
||||||
|
import StripeService from "@Services/common/StripeService/StripeService";
|
||||||
|
import { validateOrReject } from "class-validator";
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Subscription } from "le-coffre-resources/dist/Admin";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
@Service()
|
||||||
|
export default class StripeController extends ApiController {
|
||||||
|
constructor(private stripeService: StripeService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Create a new checkout session
|
||||||
|
*/
|
||||||
|
@Post("/api/v1/admin/stripe", [authHandler, ruleHandler])
|
||||||
|
protected async createStripeSubscriptionCheckout(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const officeId: string = req.body.user.office_Id;
|
||||||
|
|
||||||
|
//add office id to request body
|
||||||
|
req.body.office = { uid: officeId };
|
||||||
|
|
||||||
|
//init Subscription resource with request body values
|
||||||
|
const subscriptionEntity = Subscription.hydrate<Subscription>(req.body, { strategy: "excludeAll" });
|
||||||
|
|
||||||
|
await validateOrReject(subscriptionEntity, { groups: ["createSubscription"], forbidUnknownValues: false });
|
||||||
|
|
||||||
|
const stripeSession = await this.stripeService.createCheckoutSession(subscriptionEntity);
|
||||||
|
|
||||||
|
this.httpCreated(response, stripeSession);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("/api/v1/admin/stripe/:uid")
|
||||||
|
protected async getStripeSubscriptionByUid(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const uid = req.params["uid"];
|
||||||
|
if (!uid) {
|
||||||
|
this.httpBadRequest(response, "No uid provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stripe_subscription = await this.stripeService.getStripeSubscriptionByUid(uid);
|
||||||
|
|
||||||
|
this.httpSuccess(response, stripe_subscription);
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("/api/v1/admin/stripe/:uid/client-portal", [authHandler, ruleHandler])
|
||||||
|
protected async getClientPortalSession(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const uid = req.params["uid"];
|
||||||
|
if (!uid) {
|
||||||
|
this.httpBadRequest(response, "No uid provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const client_portal = await this.stripeService.createClientPortalSession(uid);
|
||||||
|
|
||||||
|
this.httpSuccess(response, client_portal);
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("/api/v1/admin/stripe/:uid/customer")
|
||||||
|
protected async getCustomerBySubscription(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const uid = req.params["uid"];
|
||||||
|
if (!uid) {
|
||||||
|
this.httpBadRequest(response, "No uid provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customer = await this.stripeService.getCustomerBySubscription(uid);
|
||||||
|
this.httpSuccess(response, customer);
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
src/app/api/admin/SubscriptionsController.ts
Normal file
144
src/app/api/admin/SubscriptionsController.ts
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import { Controller, Get, Post, Put } from "@ControllerPattern/index";
|
||||||
|
import { Response, Request } from "express";
|
||||||
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import SubscriptionsService from "@Services/admin/SubscriptionsService/SubscriptionsService.ts";
|
||||||
|
import { Subscription } from "le-coffre-resources/dist/Admin";
|
||||||
|
import ObjectHydrate from "@Common/helpers/ObjectHydrate";
|
||||||
|
import authHandler from "@App/middlewares/AuthHandler";
|
||||||
|
import EmailBuilder from "@Common/emails/EmailBuilder";
|
||||||
|
import ruleHandler from "@App/middlewares/RulesHandler";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
@Service()
|
||||||
|
export default class SubscriptionsController extends ApiController {
|
||||||
|
constructor(private subscriptionsService: SubscriptionsService, private emailBuilder: EmailBuilder) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get all subscriptions
|
||||||
|
*/
|
||||||
|
@Get("/api/v1/admin/subscriptions", [authHandler, ruleHandler])
|
||||||
|
protected async get(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
//get query
|
||||||
|
let query: Prisma.SubscriptionsFindManyArgs = {};
|
||||||
|
if (req.query["q"]) {
|
||||||
|
query = JSON.parse(req.query["q"] as string);
|
||||||
|
if (query.where?.uid) {
|
||||||
|
this.httpBadRequest(response, "You can't filter by uid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//call service to get prisma entity
|
||||||
|
const subscriptionsEntities = await this.subscriptionsService.get(query);
|
||||||
|
|
||||||
|
//Hydrate ressource with prisma entity
|
||||||
|
const subscriptions = Subscription.hydrateArray<Subscription>(subscriptionsEntities, { strategy: "excludeAll" });
|
||||||
|
|
||||||
|
//success
|
||||||
|
this.httpSuccess(response, subscriptions);
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get a specific subscription by uid
|
||||||
|
*/
|
||||||
|
@Get("/api/v1/admin/subscriptions/: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 subscriptionEntity = await this.subscriptionsService.getByUid(uid, query);
|
||||||
|
|
||||||
|
//Hydrate resource with prisma entity
|
||||||
|
const subscription = ObjectHydrate.hydrate<Subscription>(new Subscription(), subscriptionEntity!, { strategy: "excludeAll" });
|
||||||
|
|
||||||
|
//success
|
||||||
|
this.httpSuccess(response, subscription);
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Update a subscription
|
||||||
|
*/
|
||||||
|
@Put("/api/v1/admin/subscriptions/: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 subscriptionFound = await this.subscriptionsService.getByUid(uid);
|
||||||
|
|
||||||
|
if (!subscriptionFound) {
|
||||||
|
this.httpNotFoundRequest(response, "subscription not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//init Subscription resource with request body values
|
||||||
|
const subscriptionEntity = Subscription.hydrate<Subscription>(req.body);
|
||||||
|
|
||||||
|
//call service to get prisma entity
|
||||||
|
const subscriptionEntityUpdated = await this.subscriptionsService.update(uid, subscriptionEntity);
|
||||||
|
|
||||||
|
//Hydrate ressource with prisma entity
|
||||||
|
const subscription = Subscription.hydrate<Subscription>(subscriptionEntityUpdated, {
|
||||||
|
strategy: "excludeAll",
|
||||||
|
});
|
||||||
|
|
||||||
|
//success
|
||||||
|
this.httpSuccess(response, subscription);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Invite collaborators to a subscription
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Post("/api/v1/admin/subscriptions/invite", [authHandler, ruleHandler])
|
||||||
|
protected async inviteCollaborators(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
//get email list from body
|
||||||
|
const emails: [string] = req.body.emails;
|
||||||
|
if (!emails || emails.length < 1){
|
||||||
|
this.httpBadRequest(response, "No emails provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//create emails for asked document
|
||||||
|
await this.emailBuilder.sendInvitationEmails(emails);
|
||||||
|
|
||||||
|
//success
|
||||||
|
this.httpSuccess(response, {message: "Invitations sent"});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,8 @@ import { Controller, Get } from "@ControllerPattern/index";
|
|||||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import IdNotService from "@Services/common/IdNotService/IdNotService";
|
import IdNotService from "@Services/common/IdNotService/IdNotService";
|
||||||
|
import userHandler from "@App/middlewares/OfficeMembershipHandlers/UserHandler";
|
||||||
|
import authHandler from "@App/middlewares/AuthHandler";
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
@Service()
|
@Service()
|
||||||
@ -11,16 +13,17 @@ export default class UserController extends ApiController {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get("/api/v1/idnot/office/:uid/office-memberships")
|
@Get("/api/v1/idnot/office/:uid/office-memberships", [authHandler, userHandler])
|
||||||
protected async getOfficeMemberships(req: Request, response: Response) {
|
protected async getOfficeMemberships(req: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
const uid = req.params["uid"];
|
const uid = req.params["uid"];
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
this.httpBadRequest(response, "uid is required");
|
this.httpBadRequest(response, "uid is required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const officeMemberships = await this.idNotService.getOfficeMemberships(uid);
|
const officeMemberships = await this.idNotService.getOfficeMemberships(uid);
|
||||||
|
|
||||||
this.httpSuccess(response, officeMemberships);
|
this.httpSuccess(response, officeMemberships);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -2,17 +2,28 @@ import { Response, Request } from "express";
|
|||||||
import { Controller, Post } from "@ControllerPattern/index";
|
import { Controller, Post } from "@ControllerPattern/index";
|
||||||
import ApiController from "@Common/system/controller-pattern/ApiController";
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import AuthService, { IUserJwtPayload } from "@Services/common/AuthService/AuthService";
|
import AuthService, { IUserJwtPayload, PROVIDER_OPENID } from "@Services/common/AuthService/AuthService";
|
||||||
|
|
||||||
import IdNotService from "@Services/common/IdNotService/IdNotService";
|
import IdNotService from "@Services/common/IdNotService/IdNotService";
|
||||||
import WhitelistService from "@Services/common/WhitelistService/WhitelistService";
|
import User, { RulesGroup } from "le-coffre-resources/dist/Admin";
|
||||||
import User from "le-coffre-resources/dist/SuperAdmin";
|
|
||||||
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
import UsersService from "@Services/super-admin/UsersService/UsersService";
|
||||||
|
import SubscriptionsService from "@Services/admin/SubscriptionsService/SubscriptionsService.ts";
|
||||||
|
import { ESubscriptionStatus } from "@prisma/client";
|
||||||
|
import SeatsService from "@Services/admin/SeatsService/SeatsService";
|
||||||
|
import { EType } from "le-coffre-resources/dist/Admin/Subscription";
|
||||||
|
import RulesGroupsService from "@Services/admin/RulesGroupsService/RulesGroupsService";
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
@Service()
|
@Service()
|
||||||
export default class UserController extends ApiController {
|
export default class UserController extends ApiController {
|
||||||
constructor(private authService: AuthService, private idNotService: IdNotService, private whitelistService: WhitelistService, private userService: UsersService) {
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private idNotService: IdNotService,
|
||||||
|
private userService: UsersService,
|
||||||
|
private subscriptionsService: SubscriptionsService,
|
||||||
|
private seatsService: SeatsService,
|
||||||
|
private rulesGroupsService: RulesGroupsService,
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,59 +36,108 @@ export default class UserController extends ApiController {
|
|||||||
protected async getUserInfosFromIdnot(req: Request, response: Response) {
|
protected async getUserInfosFromIdnot(req: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
const code = req.params["code"];
|
const code = req.params["code"];
|
||||||
|
|
||||||
if (!code) throw new Error("code is required");
|
if (!code) throw new Error("code is required");
|
||||||
|
|
||||||
const idNotToken = await this.idNotService.getIdNotToken(code);
|
const idNotToken = await this.idNotService.getIdNotToken(code);
|
||||||
|
|
||||||
if(!idNotToken) {
|
if (!idNotToken) {
|
||||||
this.httpValidationError(response, "IdNot token undefined");
|
this.httpValidationError(response, "IdNot token undefined");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.idNotService.getOrCreateUser(idNotToken);
|
const user = await this.idNotService.getOrCreateUser(idNotToken);
|
||||||
|
|
||||||
if(!user) {
|
if (!user) {
|
||||||
this.httpUnauthorized(response, "Email not found");
|
this.httpUnauthorized(response, "User not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.idNotService.updateUser(user.uid);
|
await this.idNotService.updateUser(user.uid);
|
||||||
|
|
||||||
//Whitelist feature
|
//Whitelist feature
|
||||||
//Get user with contact
|
//Get user with contact
|
||||||
const prismaUser = await this.userService.getByUid(user.uid, {contact: true });
|
const prismaUser = await this.userService.getByUid(user.uid, { contact: true, role: true, office_membership: true});
|
||||||
|
|
||||||
if (!prismaUser) {
|
if (!prismaUser) {
|
||||||
this.httpNotFoundRequest(response, "user not found");
|
this.httpNotFoundRequest(response, "user not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Hydrate user to be able to use his contact
|
|
||||||
const userHydrated = User.hydrate<User>(prismaUser, { strategy: "excludeAll" });
|
|
||||||
|
|
||||||
if(!userHydrated.contact?.email || userHydrated.contact?.email === "") {
|
//Hydrate user to be able to use his contact
|
||||||
|
const userHydrated = User.hydrate<User>(prismaUser, { strategy: "excludeAll" });
|
||||||
|
|
||||||
|
if (!userHydrated.contact?.email || userHydrated.contact?.email === "") {
|
||||||
this.httpUnauthorized(response, "Email not found");
|
this.httpUnauthorized(response, "Email not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let isSubscribed = false;
|
||||||
|
|
||||||
|
const subscriptions = await this.subscriptionsService.get({ where: { office_uid: userHydrated.office_membership?.uid } });
|
||||||
|
|
||||||
|
if (!subscriptions || subscriptions.length === 0 || subscriptions[0]?.status === ESubscriptionStatus.INACTIVE) {
|
||||||
|
isSubscribed = false;
|
||||||
|
}
|
||||||
|
else if (subscriptions[0]?.type === EType.Unlimited) {
|
||||||
|
isSubscribed = true;
|
||||||
|
} else {
|
||||||
|
const hasSeat = await this.subscriptionsService.get({
|
||||||
|
where: { status: ESubscriptionStatus.ACTIVE, seats: { some: { user_uid: userHydrated.uid } } },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasSeat && hasSeat.length > 0) {
|
||||||
|
isSubscribed = true;
|
||||||
|
} else {
|
||||||
|
const nbMaxSeats = subscriptions[0]!.nb_seats;
|
||||||
|
|
||||||
|
const nbCurrentSeats = await this.seatsService.get({ where: { subscription_uid: subscriptions[0]!.uid } });
|
||||||
|
|
||||||
|
//if nbMaxSeats < nbCurrentSeats, create a new seat for the user
|
||||||
|
if (nbMaxSeats > nbCurrentSeats.length) {
|
||||||
|
const seatAdded = await this.seatsService.create(user.uid, subscriptions[0]!.uid);
|
||||||
|
if (seatAdded) {
|
||||||
|
isSubscribed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Check if user is whitelisted
|
//Check if user is whitelisted
|
||||||
|
// const isWhitelisted = await this.whitelistService.getByEmail(userHydrated.contact!.email);
|
||||||
const isWhitelisted = await this.whitelistService.getByEmail(userHydrated.contact!.email);
|
|
||||||
|
//When we'll switch to idNotId whitelisting
|
||||||
|
// const isWhitelisted = await this.userWhitelistService.getByIdNotId(user.idNot);
|
||||||
|
|
||||||
//If not whitelisted, return 409 Not whitelisted
|
//If not whitelisted, return 409 Not whitelisted
|
||||||
if (!isWhitelisted || isWhitelisted.length === 0) {
|
// if (!isWhitelisted || isWhitelisted.length === 0) {
|
||||||
this.httpNotWhitelisted(response);
|
// this.httpNotWhitelisted(response);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
await this.idNotService.updateOffice(user.office_uid);
|
||||||
|
|
||||||
|
const payload = await this.authService.getUserJwtPayload(user.idNot);
|
||||||
|
if(!payload) return;
|
||||||
|
|
||||||
|
if(!isSubscribed && userHydrated.role?.name === "admin" || userHydrated.role?.name === "super-admin"){
|
||||||
|
const manageSubscriptionRulesEntity = await this.rulesGroupsService.get({ where: { uid: "94343601-04c8-44ef-afb9-3047597528a9" }, include: { rules: true } });
|
||||||
|
|
||||||
|
const manageSubscriptionRules = RulesGroup.hydrateArray<RulesGroup>(manageSubscriptionRulesEntity, { strategy: "excludeAll" });
|
||||||
|
if(!manageSubscriptionRules[0]) return;
|
||||||
|
|
||||||
|
payload.rules = manageSubscriptionRules[0].rules!.map((rule) => rule.name) || [];
|
||||||
|
|
||||||
|
isSubscribed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSubscribed) {
|
||||||
|
this.httpUnauthorized(response, "User not subscribed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await this.idNotService.updateOffice(user.office_uid);
|
|
||||||
|
|
||||||
const payload = await this.authService.getUserJwtPayload(user.idNot);
|
|
||||||
const accessToken = this.authService.generateAccessToken(payload);
|
const accessToken = this.authService.generateAccessToken(payload);
|
||||||
const refreshToken = this.authService.generateRefreshToken(payload);
|
const refreshToken = this.authService.generateRefreshToken(payload);
|
||||||
|
|
||||||
this.httpSuccess(response, { accessToken, refreshToken });
|
this.httpSuccess(response, { accessToken, refreshToken });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -98,21 +158,24 @@ export default class UserController extends ApiController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let accessToken;
|
let accessToken;
|
||||||
this.authService.verifyRefreshToken(token, (err, userPayload) => {
|
this.authService.verifyRefreshToken(token, async (err, userPayload) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
this.httpUnauthorized(response);
|
this.httpUnauthorized(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = userPayload as IUserJwtPayload;
|
const openId = (userPayload as IUserJwtPayload).openId.userId;
|
||||||
|
if (!openId) return;
|
||||||
|
const newUserPayload = await this.authService.getUserJwtPayload(openId.toString(), PROVIDER_OPENID.idNot);
|
||||||
|
const user = newUserPayload as IUserJwtPayload;
|
||||||
delete user.iat;
|
delete user.iat;
|
||||||
delete user.exp;
|
delete user.exp;
|
||||||
accessToken = this.authService.generateAccessToken(user);
|
accessToken = this.authService.generateAccessToken(user);
|
||||||
|
this.httpSuccess(response, { accessToken });
|
||||||
});
|
});
|
||||||
|
|
||||||
//success
|
//success
|
||||||
this.httpSuccess(response, { accessToken });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
this.httpInternalError(response);
|
this.httpInternalError(response);
|
||||||
|
@ -7,6 +7,7 @@ import OfficerRibService from "@Services/common/OfficeRibService/OfficeRibServic
|
|||||||
import authHandler from "@App/middlewares/AuthHandler";
|
import authHandler from "@App/middlewares/AuthHandler";
|
||||||
import OfficesService from "@Services/notary/OfficesService/OfficesService";
|
import OfficesService from "@Services/notary/OfficesService/OfficesService";
|
||||||
import { Office as OfficeResource } from "le-coffre-resources/dist/Notary";
|
import { Office as OfficeResource } from "le-coffre-resources/dist/Notary";
|
||||||
|
import ruleHandler from "@App/middlewares/RulesHandler";
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
@Service()
|
@Service()
|
||||||
@ -15,7 +16,7 @@ export default class OfficeRibController extends ApiController {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get("/api/v1/notary/office/rib", [authHandler])
|
@Get("/api/v1/notary/rib", [authHandler, ruleHandler])
|
||||||
protected async getRibStream(req: Request, response: Response) {
|
protected async getRibStream(req: Request, response: Response) {
|
||||||
const officeId: string = req.body.user.office_Id;
|
const officeId: string = req.body.user.office_Id;
|
||||||
if (!officeId) throw new Error("No officeId provided");
|
if (!officeId) throw new Error("No officeId provided");
|
||||||
@ -43,7 +44,7 @@ export default class OfficeRibController extends ApiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post("/api/v1/notary/office/rib", [authHandler])
|
@Post("/api/v1/notary/rib", [authHandler, ruleHandler])
|
||||||
protected async post(req: Request, response: Response) {
|
protected async post(req: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
const officeId: string = req.body.user.office_Id;
|
const officeId: string = req.body.user.office_Id;
|
||||||
@ -82,7 +83,7 @@ export default class OfficeRibController extends ApiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete("/api/v1/notary/office/rib", [authHandler])
|
@Delete("/api/v1/notary/rib", [authHandler, ruleHandler])
|
||||||
protected async delete(req: Request, response: Response) {
|
protected async delete(req: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
const officeId: string = req.body.user.office_Id;
|
const officeId: string = req.body.user.office_Id;
|
||||||
|
@ -49,6 +49,11 @@ import AuthController from "./api/customer/AuthController";
|
|||||||
import NotaryOfficeRibController from "./api/notary/OfficeRibController";
|
import NotaryOfficeRibController from "./api/notary/OfficeRibController";
|
||||||
import CustomerOfficeRibController from "./api/customer/OfficeRibController";
|
import CustomerOfficeRibController from "./api/customer/OfficeRibController";
|
||||||
import IdNotOfficeController from "./api/idnot/OfficeController";
|
import IdNotOfficeController from "./api/idnot/OfficeController";
|
||||||
|
import SubscriptionsController from "./api/admin/SubscriptionsController";
|
||||||
|
import StripeController from "./api/admin/StripeController";
|
||||||
|
import StripeWebhooks from "@Common/webhooks/stripeWebhooks";
|
||||||
|
import RulesGroupsController from "./api/admin/RulesGroupsController";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description This allow to declare all controllers used in the application
|
* @description This allow to declare all controllers used in the application
|
||||||
*/
|
*/
|
||||||
@ -104,6 +109,10 @@ export default {
|
|||||||
Container.get(AuthController);
|
Container.get(AuthController);
|
||||||
Container.get(NotaryOfficeRibController);
|
Container.get(NotaryOfficeRibController);
|
||||||
Container.get(CustomerOfficeRibController);
|
Container.get(CustomerOfficeRibController);
|
||||||
Container.get(IdNotOfficeController)
|
Container.get(IdNotOfficeController);
|
||||||
|
Container.get(SubscriptionsController);
|
||||||
|
Container.get(StripeController);
|
||||||
|
Container.get(StripeWebhooks);
|
||||||
|
Container.get(RulesGroupsController);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -142,6 +142,24 @@ export class BackendVariables {
|
|||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public readonly SCW_BUCKET_NAME!: string;
|
public readonly SCW_BUCKET_NAME!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly STRIPE_SECRET_KEY!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID!: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
public readonly IDNOT_PROD_BASE_URL!: string;
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
this.DATABASE_PORT = process.env["DATABASE_PORT"]!;
|
this.DATABASE_PORT = process.env["DATABASE_PORT"]!;
|
||||||
@ -190,6 +208,12 @@ export class BackendVariables {
|
|||||||
this.SCW_ACCESS_KEY_SECRET = process.env["ACCESS_KEY_SECRET"]!;
|
this.SCW_ACCESS_KEY_SECRET = process.env["ACCESS_KEY_SECRET"]!;
|
||||||
this.SCW_BUCKET_ENDPOINT = process.env["BUCKET_ENDPOINT"]!;
|
this.SCW_BUCKET_ENDPOINT = process.env["BUCKET_ENDPOINT"]!;
|
||||||
this.SCW_BUCKET_NAME = process.env["BUCKET_NAME"]!;
|
this.SCW_BUCKET_NAME = process.env["BUCKET_NAME"]!;
|
||||||
|
this.STRIPE_SECRET_KEY = process.env["STRIPE_SECRET_KEY"]!;
|
||||||
|
this.STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID = process.env["STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID"]!;
|
||||||
|
this.STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID = process.env["STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID"]!;
|
||||||
|
this.STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID = process.env["STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID"]!;
|
||||||
|
this.STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID = process.env["STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID"]!;
|
||||||
|
this.IDNOT_PROD_BASE_URL = process.env["IDNOT_PROD_BASE_URL"]!;
|
||||||
}
|
}
|
||||||
public async validate(groups?: string[]) {
|
public async validate(groups?: string[]) {
|
||||||
const validationOptions = groups ? { groups } : undefined;
|
const validationOptions = groups ? { groups } : undefined;
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "user_whitelist" (
|
||||||
|
"uid" TEXT NOT NULL,
|
||||||
|
"idNot" VARCHAR(255) NOT NULL,
|
||||||
|
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMP(3),
|
||||||
|
|
||||||
|
CONSTRAINT "user_whitelist_pkey" PRIMARY KEY ("uid")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "user_whitelist_uid_key" ON "user_whitelist"("uid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "user_whitelist_idNot_key" ON "user_whitelist"("idNot");
|
@ -0,0 +1,34 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "subscriptions" (
|
||||||
|
"uid" TEXT NOT NULL,
|
||||||
|
"start_date" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"end_date" TIMESTAMP(3),
|
||||||
|
"nb_seats" INTEGER NOT NULL,
|
||||||
|
"office_uid" VARCHAR(255) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "subscriptions_pkey" PRIMARY KEY ("uid")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "seats" (
|
||||||
|
"uid" TEXT NOT NULL,
|
||||||
|
"subscription_uid" VARCHAR(255) NOT NULL,
|
||||||
|
"user_uid" VARCHAR(255) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "seats_pkey" PRIMARY KEY ("uid")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "subscriptions_uid_key" ON "subscriptions"("uid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "seats_uid_key" ON "seats"("uid");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "seats" ADD CONSTRAINT "seats_subscription_uid_fkey" FOREIGN KEY ("subscription_uid") REFERENCES "subscriptions"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "seats" ADD CONSTRAINT "seats_user_uid_fkey" FOREIGN KEY ("user_uid") REFERENCES "users"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `priceId` to the `subscriptions` table without a default value. This is not possible if the table is not empty.
|
||||||
|
- Made the column `start_date` on table `subscriptions` required. This step will fail if there are existing NULL values in that column.
|
||||||
|
- Made the column `end_date` on table `subscriptions` required. This step will fail if there are existing NULL values in that column.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "priceId" VARCHAR(255) NOT NULL,
|
||||||
|
ALTER COLUMN "start_date" SET NOT NULL,
|
||||||
|
ALTER COLUMN "end_date" SET NOT NULL;
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `type` to the `subscriptions` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ESubscriptionType" AS ENUM ('STANDARD', 'UNLIMITED');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "type" "ESubscriptionType" NOT NULL;
|
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `priceId` on the `subscriptions` table. All the data in the column will be lost.
|
||||||
|
- Added the required column `stripe_subscription_id` to the `subscriptions` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" DROP COLUMN "priceId",
|
||||||
|
ADD COLUMN "stripe_subscription_id" VARCHAR(255) NOT NULL;
|
@ -0,0 +1,5 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ESubscriptionStatus" AS ENUM ('ACTIVE', 'INACTIVE');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "status" "ESubscriptionStatus" NOT NULL DEFAULT 'INACTIVE';
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" ALTER COLUMN "status" SET DEFAULT 'ACTIVE';
|
@ -0,0 +1,7 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "seats" ADD COLUMN "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
ADD COLUMN "updated_at" TIMESTAMP(3);
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
ADD COLUMN "updated_at" TIMESTAMP(3);
|
@ -0,0 +1,30 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "rules_groups" (
|
||||||
|
"uid" TEXT NOT NULL,
|
||||||
|
"name" VARCHAR(255) NOT NULL,
|
||||||
|
"created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMP(3),
|
||||||
|
|
||||||
|
CONSTRAINT "rules_groups_pkey" PRIMARY KEY ("uid")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "_RulesGroupsHasRules" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "rules_groups_uid_key" ON "rules_groups"("uid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "_RulesGroupsHasRules_AB_unique" ON "_RulesGroupsHasRules"("A", "B");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "_RulesGroupsHasRules_B_index" ON "_RulesGroupsHasRules"("B");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_RulesGroupsHasRules" ADD CONSTRAINT "_RulesGroupsHasRules_A_fkey" FOREIGN KEY ("A") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_RulesGroupsHasRules" ADD CONSTRAINT "_RulesGroupsHasRules_B_fkey" FOREIGN KEY ("B") REFERENCES "rules_groups"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -68,6 +68,7 @@ model Users {
|
|||||||
appointment Appointments[]
|
appointment Appointments[]
|
||||||
votes Votes[]
|
votes Votes[]
|
||||||
user_notifications UserNotifications[]
|
user_notifications UserNotifications[]
|
||||||
|
seats Seats[]
|
||||||
|
|
||||||
@@map("users")
|
@@map("users")
|
||||||
}
|
}
|
||||||
@ -81,6 +82,15 @@ model Whitelist {
|
|||||||
@@map("whitelist")
|
@@map("whitelist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model UserWhitelist {
|
||||||
|
uid String @id @unique @default(uuid())
|
||||||
|
idNot String @unique @db.VarChar(255)
|
||||||
|
active Boolean @default(true)
|
||||||
|
created_at DateTime? @default(now())
|
||||||
|
updated_at DateTime? @updatedAt
|
||||||
|
@@map("user_whitelist")
|
||||||
|
}
|
||||||
|
|
||||||
model Offices {
|
model Offices {
|
||||||
uid String @id @unique @default(uuid())
|
uid String @id @unique @default(uuid())
|
||||||
idNot String @unique @db.VarChar(255)
|
idNot String @unique @db.VarChar(255)
|
||||||
@ -99,6 +109,7 @@ model Offices {
|
|||||||
office_folders OfficeFolders[]
|
office_folders OfficeFolders[]
|
||||||
document_types DocumentTypes[]
|
document_types DocumentTypes[]
|
||||||
office_roles OfficeRoles[]
|
office_roles OfficeRoles[]
|
||||||
|
subscriptions Subscriptions[]
|
||||||
|
|
||||||
@@map("offices")
|
@@map("offices")
|
||||||
}
|
}
|
||||||
@ -312,9 +323,19 @@ model Rules {
|
|||||||
role Roles[] @relation("RolesHasRules")
|
role Roles[] @relation("RolesHasRules")
|
||||||
office_roles OfficeRoles[] @relation("OfficeRolesHasRules")
|
office_roles OfficeRoles[] @relation("OfficeRolesHasRules")
|
||||||
namespace String @db.VarChar(255) @default("notary")
|
namespace String @db.VarChar(255) @default("notary")
|
||||||
|
groups RulesGroups[] @relation("RulesGroupsHasRules")
|
||||||
@@map("rules")
|
@@map("rules")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model RulesGroups {
|
||||||
|
uid String @id @unique @default(uuid())
|
||||||
|
name String @db.VarChar(255)
|
||||||
|
created_at DateTime? @default(now())
|
||||||
|
updated_at DateTime? @updatedAt
|
||||||
|
rules Rules[] @relation("RulesGroupsHasRules")
|
||||||
|
@@map("rules_groups")
|
||||||
|
}
|
||||||
|
|
||||||
model Emails {
|
model Emails {
|
||||||
uid String @id @unique @default(uuid())
|
uid String @id @unique @default(uuid())
|
||||||
templateName String @db.VarChar(255)
|
templateName String @db.VarChar(255)
|
||||||
@ -366,6 +387,43 @@ model TotpCodes {
|
|||||||
@@map("totp_codes")
|
@@map("totp_codes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Subscriptions {
|
||||||
|
uid String @id @unique @default(uuid())
|
||||||
|
type ESubscriptionType
|
||||||
|
status ESubscriptionStatus @default(ACTIVE)
|
||||||
|
stripe_subscription_id String @db.VarChar(255)
|
||||||
|
start_date DateTime @default(now())
|
||||||
|
end_date DateTime
|
||||||
|
nb_seats Int
|
||||||
|
office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade)
|
||||||
|
office_uid String @db.VarChar(255)
|
||||||
|
seats Seats[]
|
||||||
|
created_at DateTime? @default(now())
|
||||||
|
updated_at DateTime? @updatedAt
|
||||||
|
@@map("subscriptions")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Seats {
|
||||||
|
uid String @id @unique @default(uuid())
|
||||||
|
subscription Subscriptions @relation(fields: [subscription_uid], references: [uid], onDelete: Cascade)
|
||||||
|
subscription_uid String @db.VarChar(255)
|
||||||
|
user Users @relation(fields: [user_uid], references: [uid], onDelete: Cascade)
|
||||||
|
user_uid String @db.VarChar(255)
|
||||||
|
created_at DateTime? @default(now())
|
||||||
|
updated_at DateTime? @updatedAt
|
||||||
|
@@map("seats")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ESubscriptionStatus {
|
||||||
|
ACTIVE
|
||||||
|
INACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ESubscriptionType {
|
||||||
|
STANDARD
|
||||||
|
UNLIMITED
|
||||||
|
}
|
||||||
|
|
||||||
enum TotpCodesReasons {
|
enum TotpCodesReasons {
|
||||||
LOGIN
|
LOGIN
|
||||||
RESET_PASSWORD
|
RESET_PASSWORD
|
||||||
|
@ -527,28 +527,28 @@ export default async function main() {
|
|||||||
label: "Lecture des utilisateurs",
|
label: "Lecture des utilisateurs",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET offices",
|
name: "GET offices",
|
||||||
label: "Afficher des offices",
|
label: "Afficher des offices",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET customers",
|
name: "GET customers",
|
||||||
label: "Afficher des clients",
|
label: "Afficher des clients",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET deeds",
|
name: "GET deeds",
|
||||||
label: "Voir des types d'acte",
|
label: "Voir des types d'acte",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET deed-types",
|
name: "GET deed-types",
|
||||||
@ -562,7 +562,7 @@ export default async function main() {
|
|||||||
label: "Afficher des documents",
|
label: "Afficher des documents",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET document-types",
|
name: "GET document-types",
|
||||||
@ -576,112 +576,112 @@ export default async function main() {
|
|||||||
label: "Lecture des fichiers",
|
label: "Lecture des fichiers",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET folders",
|
name: "GET folders",
|
||||||
label: "Afficher les dossiers",
|
label: "Afficher les dossiers",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET roles",
|
name: "GET roles",
|
||||||
label: "Afficher les rôles",
|
label: "Afficher les rôles",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET rules",
|
name: "GET rules",
|
||||||
label: "Afficher les droits",
|
label: "Afficher les droits",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET office-roles",
|
name: "GET office-roles",
|
||||||
label: "Lecture des rôles d'office",
|
label: "Lecture des rôles d'office",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "collaborator",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST deeds",
|
name: "POST deeds",
|
||||||
label: "Créer un template de type d'acte",
|
label: "Créer un template de type d'acte",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT deeds",
|
name: "PUT deeds",
|
||||||
label: "Modifier un type d'acte",
|
label: "Modifier un type d'acte",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE deeds",
|
name: "DELETE deeds",
|
||||||
label: "Supprimer des types d'actes",
|
label: "Supprimer des types d'actes",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST folders",
|
name: "POST folders",
|
||||||
label: "Créer un dossier",
|
label: "Créer un dossier",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT folders",
|
name: "PUT folders",
|
||||||
label: "Modifier des dossiers",
|
label: "Modifier des dossiers",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE folders",
|
name: "DELETE folders",
|
||||||
label: "Supprimer un dossier vide",
|
label: "Supprimer un dossier vide",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST documents",
|
name: "POST documents",
|
||||||
label: "Demander des documents à un client",
|
label: "Demander des documents à un client",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT documents",
|
name: "PUT documents",
|
||||||
label: "Valider des documents",
|
label: "Valider des documents",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE documents",
|
name: "DELETE documents",
|
||||||
label: "Supprimer un document demandé",
|
label: "Supprimer un document demandé",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST customers",
|
name: "POST customers",
|
||||||
label: "Créer des clients",
|
label: "Créer des clients",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT customers",
|
name: "PUT customers",
|
||||||
label: "Modifier des clients",
|
label: "Modifier des clients",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE customers",
|
name: "DELETE customers",
|
||||||
@ -695,56 +695,56 @@ export default async function main() {
|
|||||||
label: "Ancrer un dossier",
|
label: "Ancrer un dossier",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GET anchors",
|
name: "GET anchors",
|
||||||
label: "Vérifier l'ancrage un dossier",
|
label: "Vérifier l'ancrage un dossier",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "global",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST deed-types",
|
name: "POST deed-types",
|
||||||
label: "Création des types d'actes",
|
label: "Création des types d'actes",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "admin",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT deed-types",
|
name: "PUT deed-types",
|
||||||
label: "Modification des types d'actes",
|
label: "Modification des types d'actes",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "admin",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE deed-types",
|
name: "DELETE deed-types",
|
||||||
label: "Suppression des types d'actes",
|
label: "Suppression des types d'actes",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "admin",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST document-types",
|
name: "POST document-types",
|
||||||
label: "Création des types de documents",
|
label: "Création des types de documents",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "admin",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT document-types",
|
name: "PUT document-types",
|
||||||
label: "Modification des types de documents",
|
label: "Modification des types de documents",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "admin",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE document-types",
|
name: "DELETE document-types",
|
||||||
label: "Suppression des types de documents",
|
label: "Suppression des types de documents",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "admin",
|
namespace: "collaborator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "POST office-roles",
|
name: "POST office-roles",
|
||||||
@ -793,13 +793,115 @@ export default async function main() {
|
|||||||
label: "Editer le RIB de l'office",
|
label: "Editer le RIB de l'office",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
namespace: "notary",
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GET rib",
|
||||||
|
label: "Lire le RIB de l'office",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "POST rib",
|
||||||
|
label: "Déposer le RIB de l'office",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DELETE rib",
|
||||||
|
label: "Supprimer le RIB de l'office",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GET subscriptions",
|
||||||
|
label: "Récupérer les abonnements",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "POST subscriptions",
|
||||||
|
label: "Inviter un collaborateur à l'abonnement",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PUT subscriptions",
|
||||||
|
label: "Modifier l'abonnement",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GET stripe",
|
||||||
|
label: "Gérer l'abonnement de l'office",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "POST stripe",
|
||||||
|
label: "Payer un abonnement",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
namespace: "collaborator",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const rulesGroups = [
|
||||||
|
{
|
||||||
|
name: "Gestion des matrices d'actes et des documents",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
rules: [
|
||||||
|
"POST deeds",
|
||||||
|
"PUT deeds",
|
||||||
|
"DELETE deeds",
|
||||||
|
"GET document-types",
|
||||||
|
"DELETE deed-types",
|
||||||
|
"PUT deed-types",
|
||||||
|
"DELETE document-types",
|
||||||
|
"GET deed-types",
|
||||||
|
"POST document-types",
|
||||||
|
"POST deed-types",
|
||||||
|
"PUT document-types",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Gestion de l'abonnement",
|
||||||
|
uid: "94343601-04c8-44ef-afb9-3047597528a9",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
rules : [
|
||||||
|
"GET subscriptions",
|
||||||
|
"POST subscriptions",
|
||||||
|
"PUT subscriptions",
|
||||||
|
"GET stripe",
|
||||||
|
"POST stripe",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Intégration du RIB",
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
rules : [
|
||||||
|
"PUT rib",
|
||||||
|
"GET rib",
|
||||||
|
"POST rib",
|
||||||
|
"DELETE rib",
|
||||||
|
]
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const collaboratorRules = rules.filter((rule) => rule.namespace === "collaborator");
|
const collaboratorRules = rules.filter((rule) => rule.namespace === "collaborator");
|
||||||
const notaryRules = [...collaboratorRules, ...rules.filter((rule) => rule.namespace === "notary")];
|
const notaryRules = [...collaboratorRules, ...rules.filter((rule) => rule.namespace === "notary")];
|
||||||
const adminRules = [...notaryRules, ...rules.filter((rule) => rule.namespace === "admin")];
|
const globalRules = [...notaryRules, ...rules.filter((rule) => rule.namespace === "global")];
|
||||||
|
const adminRules = [...globalRules, ...rules.filter((rule) => rule.namespace === "admin")];
|
||||||
const superAdminRules = [...adminRules, ...rules.filter((rule) => rule.namespace === "super-admin")];
|
const superAdminRules = [...adminRules, ...rules.filter((rule) => rule.namespace === "super-admin")];
|
||||||
|
|
||||||
const roles: Role[] = [
|
const roles: Role[] = [
|
||||||
@ -839,14 +941,14 @@ export default async function main() {
|
|||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
office: offices[0]!,
|
office: offices[0]!,
|
||||||
rules: notaryRules,
|
rules: globalRules,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Collaborateur",
|
name: "Collaborateur",
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
office: offices[0]!,
|
office: offices[0]!,
|
||||||
rules: notaryRules,
|
rules: globalRules,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -1869,6 +1971,20 @@ export default async function main() {
|
|||||||
role.uid = roleCreated.uid;
|
role.uid = roleCreated.uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const ruleGroup of rulesGroups) {
|
||||||
|
await prisma.rulesGroups.create({
|
||||||
|
data: {
|
||||||
|
uid: ruleGroup.uid,
|
||||||
|
name: ruleGroup.name,
|
||||||
|
rules: {
|
||||||
|
connect: ruleGroup.rules?.map((rule) => ({
|
||||||
|
uid: rules.find((r) => r.name === rule)!.uid!,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const officeRole of officeRoles) {
|
for (const officeRole of officeRoles) {
|
||||||
const officeRoleCreated = await prisma.officeRoles.create({
|
const officeRoleCreated = await prisma.officeRoles.create({
|
||||||
data: {
|
data: {
|
||||||
|
2194
src/common/databases/seeders/seederOld.ts
Normal file
2194
src/common/databases/seeders/seederOld.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -106,4 +106,35 @@ export default class EmailBuilder {
|
|||||||
if (civility === "MALE") return "Mr";
|
if (civility === "MALE") return "Mr";
|
||||||
else return "Mme";
|
else return "Mme";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async sendInvitationEmails(emails: string[]) {
|
||||||
|
emails.forEach((email) => {
|
||||||
|
const to = email;
|
||||||
|
|
||||||
|
const templateVariables = {
|
||||||
|
link: this.variables.APP_HOST,
|
||||||
|
idNotLink: this.variables.IDNOT_PROD_BASE_URL,
|
||||||
|
};
|
||||||
|
|
||||||
|
const templateName = ETemplates.SUBSCRIPTION_INVITATION;
|
||||||
|
const subject = "Invitation abonnement LeCoffre";
|
||||||
|
|
||||||
|
this.mailchimpService.create({
|
||||||
|
templateName,
|
||||||
|
to,
|
||||||
|
subject,
|
||||||
|
templateVariables,
|
||||||
|
uid: "",
|
||||||
|
from: null,
|
||||||
|
cc: [],
|
||||||
|
cci: [],
|
||||||
|
sentAt: null,
|
||||||
|
nbTrySend: null,
|
||||||
|
lastTrySendDate: null,
|
||||||
|
});
|
||||||
|
// this.mailchimpService.sendEmails();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,5 @@ export const ETemplates = {
|
|||||||
DOCUMENT_ASKED: "DOCUMENT_ASKED",
|
DOCUMENT_ASKED: "DOCUMENT_ASKED",
|
||||||
DOCUMENT_REFUSED: "DOCUMENT_REFUSED",
|
DOCUMENT_REFUSED: "DOCUMENT_REFUSED",
|
||||||
DOCUMENT_RECAP: "DOCUMENT_RECAP",
|
DOCUMENT_RECAP: "DOCUMENT_RECAP",
|
||||||
|
SUBSCRIPTION_INVITATION: "SUBSCRIPTION_INVITATION",
|
||||||
};
|
};
|
27
src/common/repositories/RulesGroupsRepository.ts
Normal file
27
src/common/repositories/RulesGroupsRepository.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Database from "@Common/databases/database";
|
||||||
|
import BaseRepository from "@Repositories/BaseRepository";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class RulesGroupsRepository extends BaseRepository {
|
||||||
|
constructor(private database: Database) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
protected get model() {
|
||||||
|
return this.database.getClient().rulesGroups;
|
||||||
|
}
|
||||||
|
protected get instanceDb() {
|
||||||
|
return this.database.getClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Find many subscriptions
|
||||||
|
*/
|
||||||
|
public async findMany(query: Prisma.RulesGroupsFindManyArgs) {
|
||||||
|
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||||
|
if (!query.include) return this.model.findMany({ ...query });
|
||||||
|
return this.model.findMany({ ...query });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
78
src/common/repositories/SeatsRepository.ts
Normal file
78
src/common/repositories/SeatsRepository.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import Database from "@Common/databases/database";
|
||||||
|
import BaseRepository from "@Repositories/BaseRepository";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma, Seats } from "@prisma/client";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class SeatsRepository extends BaseRepository {
|
||||||
|
constructor(private database: Database) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
protected get model() {
|
||||||
|
return this.database.getClient().seats;
|
||||||
|
}
|
||||||
|
protected get instanceDb() {
|
||||||
|
return this.database.getClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Find many seats
|
||||||
|
*/
|
||||||
|
public async findMany(query: Prisma.SeatsFindManyArgs) {
|
||||||
|
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||||
|
if (!query.include) return this.model.findMany({ ...query });
|
||||||
|
return this.model.findMany({ ...query });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : find unique seat
|
||||||
|
*/
|
||||||
|
public async findOneByUid(uid: string, query?: Prisma.SeatsInclude): Promise<Seats | null> {
|
||||||
|
return this.model.findUnique({
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
include: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a seat
|
||||||
|
*/
|
||||||
|
public async create(userUid: string, subscriptionUid: string): Promise<Seats> {
|
||||||
|
|
||||||
|
const createArgs: Prisma.SeatsCreateArgs = {
|
||||||
|
data: {
|
||||||
|
subscription: {
|
||||||
|
connect: {
|
||||||
|
uid: subscriptionUid
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
uid: userUid
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
{
|
||||||
|
|
||||||
|
return this.model.create(createArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Delete a seat
|
||||||
|
*/
|
||||||
|
public async delete(uid: string) {
|
||||||
|
return this.model.delete({
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
154
src/common/repositories/SubscriptionsRepository.ts
Normal file
154
src/common/repositories/SubscriptionsRepository.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import Database from "@Common/databases/database";
|
||||||
|
import BaseRepository from "@Repositories/BaseRepository";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { ESubscriptionStatus, ESubscriptionType, Prisma, Subscriptions } from "@prisma/client";
|
||||||
|
import { Subscription } from "le-coffre-resources/dist/Admin";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class SubscriptionsRepository extends BaseRepository {
|
||||||
|
constructor(private database: Database) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
protected get model() {
|
||||||
|
return this.database.getClient().subscriptions;
|
||||||
|
}
|
||||||
|
protected get instanceDb() {
|
||||||
|
return this.database.getClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Find many subscriptions
|
||||||
|
*/
|
||||||
|
public async findMany(query: Prisma.SubscriptionsFindManyArgs) {
|
||||||
|
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||||
|
if (!query.include) return this.model.findMany({ ...query });
|
||||||
|
return this.model.findMany({ ...query });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : find unique subscription
|
||||||
|
*/
|
||||||
|
public async findOneByUid(uid: string, query?: Prisma.SubscriptionsInclude): Promise<Subscriptions | null> {
|
||||||
|
return this.model.findUnique({
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
include: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a subscription
|
||||||
|
*/
|
||||||
|
public async create(subscription: Subscription): Promise<Subscriptions> {
|
||||||
|
if(subscription.type === "STANDARD")
|
||||||
|
{
|
||||||
|
const createArgs: Prisma.SubscriptionsCreateArgs = {
|
||||||
|
data: {
|
||||||
|
start_date: subscription.start_date,
|
||||||
|
end_date: subscription.end_date,
|
||||||
|
type: ESubscriptionType.STANDARD,
|
||||||
|
status: ESubscriptionStatus.ACTIVE,
|
||||||
|
nb_seats: subscription.nb_seats!,
|
||||||
|
stripe_subscription_id: subscription.stripe_subscription_id || "",
|
||||||
|
office: {
|
||||||
|
connect: {
|
||||||
|
uid: subscription.office!.uid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return this.model.create(createArgs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const createArgs: Prisma.SubscriptionsCreateArgs = {
|
||||||
|
data: {
|
||||||
|
start_date: subscription.start_date,
|
||||||
|
end_date: subscription.end_date,
|
||||||
|
type: ESubscriptionType.UNLIMITED,
|
||||||
|
status: ESubscriptionStatus.ACTIVE,
|
||||||
|
nb_seats: 0,
|
||||||
|
stripe_subscription_id: subscription.stripe_subscription_id || "",
|
||||||
|
office: {
|
||||||
|
connect: {
|
||||||
|
uid: subscription.office!.uid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return this.model.create(createArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : update given subscription
|
||||||
|
*/
|
||||||
|
public async update(uid: string, subscription: Subscription): Promise<Subscriptions> {
|
||||||
|
if(!subscription.type || subscription.type === ""){
|
||||||
|
const updateArgs: Prisma.SubscriptionsUpdateArgs = {
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
seats:{
|
||||||
|
deleteMany: {},
|
||||||
|
createMany: {
|
||||||
|
data: subscription.seats?.map((seat) => ({
|
||||||
|
user_uid: seat.user.uid || "",
|
||||||
|
})) ?? [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return this.model.update(updateArgs);
|
||||||
|
}
|
||||||
|
if(subscription.type === "STANDARD")
|
||||||
|
{
|
||||||
|
const updateArgs: Prisma.SubscriptionsUpdateArgs = {
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
end_date: subscription.end_date,
|
||||||
|
type: ESubscriptionType.STANDARD,
|
||||||
|
status: subscription.status as ESubscriptionStatus,
|
||||||
|
nb_seats: subscription.nb_seats!,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return this.model.update(updateArgs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const updateArgs: Prisma.SubscriptionsUpdateArgs = {
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
end_date: subscription.end_date,
|
||||||
|
type: ESubscriptionType.UNLIMITED,
|
||||||
|
status: subscription.status as ESubscriptionStatus,
|
||||||
|
nb_seats: 0,
|
||||||
|
seats: {
|
||||||
|
deleteMany: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return this.model.update(updateArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Delete a subscription
|
||||||
|
*/
|
||||||
|
public async delete(uid: string) {
|
||||||
|
return this.model.delete({
|
||||||
|
where: {
|
||||||
|
uid: uid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
39
src/common/repositories/UserWhitelistRepository.ts
Normal file
39
src/common/repositories/UserWhitelistRepository.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import Database from "@Common/databases/database";
|
||||||
|
import BaseRepository from "@Repositories/BaseRepository";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma } from "prisma/prisma-client";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class UserWhitelistRepository extends BaseRepository {
|
||||||
|
constructor(private database: Database) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
protected get model() {
|
||||||
|
return this.database.getClient().userWhitelist;
|
||||||
|
}
|
||||||
|
protected get instanceDb() {
|
||||||
|
return this.database.getClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Find many whitelist
|
||||||
|
*/
|
||||||
|
public async findMany(query: Prisma.UserWhitelistFindManyArgs) {
|
||||||
|
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||||
|
return this.model.findMany(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : find unique by email
|
||||||
|
*/
|
||||||
|
public async findOneByIdNotId(idNotId: string) {
|
||||||
|
return this.model.findMany({
|
||||||
|
where: {
|
||||||
|
idNot: idNotId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
104
src/common/webhooks/stripeWebhooks.ts
Normal file
104
src/common/webhooks/stripeWebhooks.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { BackendVariables } from "@Common/config/variables/Variables";
|
||||||
|
import ApiController from "@Common/system/controller-pattern/ApiController";
|
||||||
|
import { Controller, Post } from "@ControllerPattern/index";
|
||||||
|
import SubscriptionsService from "@Services/admin/SubscriptionsService/SubscriptionsService.ts";
|
||||||
|
import StripeService from "@Services/common/StripeService/StripeService";
|
||||||
|
import { validateOrReject } from "class-validator";
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import { Subscription } from "le-coffre-resources/dist/Admin";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
@Service()
|
||||||
|
export default class StripeWebhooks extends ApiController {
|
||||||
|
constructor(private stripeService: StripeService, private subscriptionsService: SubscriptionsService, private backendVariables: BackendVariables) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Create a new checkout session
|
||||||
|
*/
|
||||||
|
@Post("/api/v1/webhooks/stripe")
|
||||||
|
protected async post(req: Request, response: Response) {
|
||||||
|
try {
|
||||||
|
const event = req.body;
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
//Manage plan switch + recurring payment
|
||||||
|
case "invoice.payment_succeeded":
|
||||||
|
if (event.data.object.billing_reason !== "subscription_update" && event.data.object.billing_reason !== "subscription_cycle") break;
|
||||||
|
const stripeSubscription = await this.stripeService.getClient().subscriptions.retrieve(event.data.object.subscription);
|
||||||
|
if(stripeSubscription.metadata['env'] !== this.backendVariables.ENV) break;
|
||||||
|
|
||||||
|
const existingSubscription = await this.subscriptionsService.get({where : {stripe_subscription_id : stripeSubscription.id}});
|
||||||
|
|
||||||
|
if(!existingSubscription[0]) break;
|
||||||
|
|
||||||
|
const subscriptionUpdate: any = {};
|
||||||
|
subscriptionUpdate.start_date = new Date(stripeSubscription.current_period_start * 1000);
|
||||||
|
subscriptionUpdate.end_date = new Date(stripeSubscription.current_period_end * 1000);
|
||||||
|
subscriptionUpdate.nb_seats = stripeSubscription.items.data[0]?.quantity;
|
||||||
|
|
||||||
|
if(stripeSubscription.items.data[0]?.price?.id === this.backendVariables.STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID || stripeSubscription.items.data[0]?.price?.id === this.backendVariables.STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID){
|
||||||
|
subscriptionUpdate.type = "STANDARD";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
subscriptionUpdate.type = "UNLIMITED";
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscriptionEntityUpdate = Subscription.hydrate<Subscription>(subscriptionUpdate);
|
||||||
|
|
||||||
|
await validateOrReject(subscriptionEntityUpdate, { groups: ["updateSubscription"], forbidUnknownValues: false });
|
||||||
|
|
||||||
|
await this.subscriptionsService.update(existingSubscription[0].uid ,subscriptionEntityUpdate);
|
||||||
|
|
||||||
|
//Manage subscription creation and first payment
|
||||||
|
case "checkout.session.completed":
|
||||||
|
if (event.data.object.status !== "complete") break;
|
||||||
|
|
||||||
|
const subscription = JSON.parse(event.data.object.metadata.subscription);
|
||||||
|
const env = event.data.object.metadata.env;
|
||||||
|
|
||||||
|
if (env !== this.backendVariables.ENV) break;
|
||||||
|
|
||||||
|
subscription.stripe_subscription_id = event.data.object.subscription;
|
||||||
|
|
||||||
|
await this.stripeService.getClient().subscriptions.update(subscription.stripe_subscription_id, {
|
||||||
|
metadata: {
|
||||||
|
env: env,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const subscriptionInfo = await this.stripeService
|
||||||
|
.getClient()
|
||||||
|
.subscriptions.retrieve(subscription.stripe_subscription_id);
|
||||||
|
|
||||||
|
subscription.start_date = new Date(subscriptionInfo.current_period_start * 1000);
|
||||||
|
subscription.end_date = new Date(subscriptionInfo.current_period_end * 1000);
|
||||||
|
|
||||||
|
const subscriptionEntity = Subscription.hydrate<Subscription>(subscription);
|
||||||
|
|
||||||
|
await validateOrReject(subscriptionEntity, { groups: ["createSubscription"], forbidUnknownValues: false });
|
||||||
|
|
||||||
|
await this.subscriptionsService.create(subscriptionEntity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Manage plan expiration
|
||||||
|
case "customer.subscription.deleted":
|
||||||
|
const currentSubscription = await this.stripeService.getClient().subscriptions.retrieve(event.data.object.id);
|
||||||
|
if(currentSubscription.metadata['env'] !== this.backendVariables.ENV) break;
|
||||||
|
const subscriptionToDelete = await this.subscriptionsService.get({where : {stripe_subscription_id : event.data.object.id}});
|
||||||
|
if(!subscriptionToDelete[0]) break;
|
||||||
|
await this.subscriptionsService.delete(subscriptionToDelete[0].uid);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.json({ received: true });
|
||||||
|
} catch (error) {
|
||||||
|
this.httpInternalError(response, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ const storage = multer.memoryStorage();
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const variables = await Container.get(BackendVariables).validate();
|
const variables = await Container.get(BackendVariables).validate();
|
||||||
const port = variables.APP_PORT;
|
const port = variables.APP_PORT;
|
||||||
const rootUrl = variables.APP_ROOT_URL;
|
const rootUrl = variables.APP_ROOT_URL;
|
||||||
const label = variables.APP_LABEL ?? "Unknown Service";
|
const label = variables.APP_LABEL ?? "Unknown Service";
|
||||||
|
20
src/services/admin/RulesGroupsService/RulesGroupsService.ts
Normal file
20
src/services/admin/RulesGroupsService/RulesGroupsService.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import BaseService from "@Services/BaseService";
|
||||||
|
import "reflect-metadata";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import RulesGroupsRepository from "@Repositories/RulesGroupsRepository";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class RulesGroupsService extends BaseService {
|
||||||
|
constructor(private rulesGroupsRepository: RulesGroupsRepository) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get all subscriptions
|
||||||
|
* @throws {Error} If subscriptions cannot be get
|
||||||
|
*/
|
||||||
|
public get(query: Prisma.RulesGroupsFindManyArgs) {
|
||||||
|
return this.rulesGroupsRepository.findMany(query);
|
||||||
|
}
|
||||||
|
}
|
45
src/services/admin/SeatsService/SeatsService.ts
Normal file
45
src/services/admin/SeatsService/SeatsService.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import BaseService from "@Services/BaseService";
|
||||||
|
import "reflect-metadata";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma, Seats } from "@prisma/client";
|
||||||
|
import SeatsRepository from "@Repositories/SeatsRepository";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class SeatsService extends BaseService {
|
||||||
|
constructor(private seatsRepository: SeatsRepository) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get all seats
|
||||||
|
* @throws {Error} If seats cannot be get
|
||||||
|
*/
|
||||||
|
public get(query: Prisma.SeatsFindManyArgs) {
|
||||||
|
return this.seatsRepository.findMany(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a seat by uid
|
||||||
|
* @throws {Error} If seat is not found
|
||||||
|
*/
|
||||||
|
public async getByUid(uid: string, query?: Prisma.SeatsInclude) {
|
||||||
|
return this.seatsRepository.findOneByUid(uid, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a new seat
|
||||||
|
* @throws {Error} If seat cannot be created
|
||||||
|
*/
|
||||||
|
public async create(subscriptionUid: string, userUid: string): Promise<Seats> {
|
||||||
|
return this.seatsRepository.create(subscriptionUid, userUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Delete a seat
|
||||||
|
* @throws {Error} If seat cannot be deleted
|
||||||
|
*/
|
||||||
|
public async delete(uid: string) {
|
||||||
|
return this.seatsRepository.delete(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
import BaseService from "@Services/BaseService";
|
||||||
|
import "reflect-metadata";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
import { Prisma, Subscriptions } from "@prisma/client";
|
||||||
|
import SubscriptionsRepository from "@Repositories/SubscriptionsRepository";
|
||||||
|
import { Subscription } from "le-coffre-resources/dist/Admin";
|
||||||
|
import SeatsService from "../SeatsService/SeatsService";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class SubscriptionsService extends BaseService {
|
||||||
|
constructor(private subscriptionsRepository: SubscriptionsRepository, private seatsService: SeatsService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get all subscriptions
|
||||||
|
* @throws {Error} If subscriptions cannot be get
|
||||||
|
*/
|
||||||
|
public get(query: Prisma.SubscriptionsFindManyArgs) {
|
||||||
|
return this.subscriptionsRepository.findMany(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a subscription by uid
|
||||||
|
* @throws {Error} If subscription is not found
|
||||||
|
*/
|
||||||
|
public async getByUid(uid: string, query?: Prisma.SubscriptionsInclude) {
|
||||||
|
return this.subscriptionsRepository.findOneByUid(uid, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a new subscription
|
||||||
|
* @throws {Error} If subsctiption cannot be created
|
||||||
|
*/
|
||||||
|
public async create(subscriptionEntity: Subscription): Promise<Subscriptions> {
|
||||||
|
return this.subscriptionsRepository.create(subscriptionEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Modify a subscription
|
||||||
|
* @throws {Error} If subscription cannot be modified
|
||||||
|
*/
|
||||||
|
public async update(uid: string, subscriptionEntity: Subscription): Promise<Subscriptions> {
|
||||||
|
if(subscriptionEntity.type === "STANDARD"){
|
||||||
|
const seats = await this.seatsService.get({ where: { subscription: { uid: uid } }, orderBy: {created_at: 'asc'} });
|
||||||
|
const seatsToKeep = subscriptionEntity.nb_seats;
|
||||||
|
const seatsToDelete = seats.slice(seatsToKeep);
|
||||||
|
|
||||||
|
for (const seat of seatsToDelete) {
|
||||||
|
await this.seatsService.delete(seat.uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.subscriptionsRepository.update(uid, subscriptionEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Delete a subscription
|
||||||
|
* @throws {Error} If subscription cannot be deleted
|
||||||
|
*/
|
||||||
|
public async delete(uid: string) {
|
||||||
|
return this.subscriptionsRepository.delete(uid);
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ import { ECustomerStatus } from "@prisma/client";
|
|||||||
import { Customer } from "le-coffre-resources/dist/Notary";
|
import { Customer } from "le-coffre-resources/dist/Notary";
|
||||||
import bcrypt from "bcrypt";
|
import bcrypt from "bcrypt";
|
||||||
|
|
||||||
enum PROVIDER_OPENID {
|
export enum PROVIDER_OPENID {
|
||||||
idNot = "idNot",
|
idNot = "idNot",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,13 +122,14 @@ export default class IdNotService extends BaseService {
|
|||||||
grant_type: "authorization_code",
|
grant_type: "authorization_code",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const token = await fetch(this.variables.IDNOT_BASE_URL + this.variables.IDNOT_CONNEXION_URL + "?" + query, { method: "POST" });
|
const token = await fetch(this.variables.IDNOT_BASE_URL + this.variables.IDNOT_CONNEXION_URL + "?" + query, { method: "POST" });
|
||||||
|
|
||||||
if(token.status !== 200) console.error(await token.text());
|
if(token.status !== 200) console.error(await token.text());
|
||||||
|
|
||||||
const decodedToken = (await token.json()) as IIdNotToken;
|
const decodedToken = (await token.json()) as IIdNotToken;
|
||||||
|
|
||||||
const decodedIdToken = jwt.decode(decodedToken.id_token) as IdNotJwtPayload;
|
const decodedIdToken = jwt.decode(decodedToken.id_token) as IdNotJwtPayload;
|
||||||
|
|
||||||
|
|
||||||
return decodedIdToken;
|
return decodedIdToken;
|
||||||
@ -147,7 +148,7 @@ export default class IdNotService extends BaseService {
|
|||||||
case EIdnotRole.SUPPLEANT:
|
case EIdnotRole.SUPPLEANT:
|
||||||
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
||||||
case EIdnotRole.ADMINISTRATEUR:
|
case EIdnotRole.ADMINISTRATEUR:
|
||||||
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
return (await this.rolesService.get({ where: { name: "admin" } }))[0]!;
|
||||||
case EIdnotRole.CURATEUR:
|
case EIdnotRole.CURATEUR:
|
||||||
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
return (await this.rolesService.get({ where: { name: "notary" } }))[0]!;
|
||||||
default:
|
default:
|
||||||
|
@ -52,7 +52,7 @@ export default class MailchimpService extends BaseService {
|
|||||||
* @throws {Error} If email cannot be sent
|
* @throws {Error} If email cannot be sent
|
||||||
*/
|
*/
|
||||||
public async sendEmails() {
|
public async sendEmails() {
|
||||||
const emailsToSend = await this.get({ where: { sentAt: null } });
|
const emailsToSend = await this.get({ where: { sentAt: null } });
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
let nextTrySendDate = null;
|
let nextTrySendDate = null;
|
||||||
|
|
||||||
|
59
src/services/common/StripeService/StripeService.ts
Normal file
59
src/services/common/StripeService/StripeService.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { BackendVariables } from "@Common/config/variables/Variables";
|
||||||
|
import { Subscription } from "le-coffre-resources/dist/Admin";
|
||||||
|
import Stripe from "stripe";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class StripeService {
|
||||||
|
private client: Stripe;
|
||||||
|
constructor(protected variables: BackendVariables) {
|
||||||
|
this.client = new Stripe(variables.STRIPE_SECRET_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getClient(): Stripe {
|
||||||
|
return this.client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createCheckoutSession(subscription: Subscription) {
|
||||||
|
const priceId = subscription.type === "STANDARD" ? this.variables.STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID : this.variables.STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID;
|
||||||
|
return this.client.checkout.sessions.create({
|
||||||
|
mode: "subscription",
|
||||||
|
payment_method_types: ["card", "paypal"],
|
||||||
|
billing_address_collection: "auto",
|
||||||
|
line_items: [
|
||||||
|
{
|
||||||
|
price: priceId,
|
||||||
|
quantity: subscription.type === "STANDARD" ? subscription.nb_seats : 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
success_url: this.variables.APP_HOST + "/subscription/success",
|
||||||
|
cancel_url: this.variables.APP_HOST + "/subscription/error",
|
||||||
|
metadata: {
|
||||||
|
subscription: JSON.stringify(subscription),
|
||||||
|
env: this.variables.ENV,
|
||||||
|
},
|
||||||
|
allow_promotion_codes: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getStripeSubscriptionByUid(subscriptionId: string) {
|
||||||
|
return await this.client.subscriptions.retrieve(subscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createClientPortalSession(subscriptionId: string) {
|
||||||
|
const subscription = await this.client.subscriptions.retrieve(subscriptionId);
|
||||||
|
|
||||||
|
return this.client.billingPortal.sessions.create({
|
||||||
|
customer: subscription.customer as string,
|
||||||
|
return_url: this.variables.APP_HOST + "/subscription/manage",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCustomerBySubscription(subscriptionId: string) {
|
||||||
|
const subscription = await this.client.subscriptions.retrieve(subscriptionId);
|
||||||
|
return this.client.customers.retrieve(subscription.customer as string);
|
||||||
|
}
|
||||||
|
}
|
14
src/services/common/UserWhitelistService/WhitelistService.ts
Normal file
14
src/services/common/UserWhitelistService/WhitelistService.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import UserWhitelistRepository from "@Repositories/UserWhitelistRepository";
|
||||||
|
import BaseService from "@Services/BaseService";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class UserWhitelistService extends BaseService {
|
||||||
|
constructor(private userWhitelistRepository: UserWhitelistRepository) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByIdNotId(idNotId: string): Promise<any> {
|
||||||
|
return this.userWhitelistRepository.findOneByIdNotId(idNotId);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ import BaseService from "@Services/BaseService";
|
|||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { Service } from "typedi";
|
import { Service } from "typedi";
|
||||||
import UsersRepository from "@Repositories/UsersRepository";
|
import UsersRepository from "@Repositories/UsersRepository";
|
||||||
import User from "le-coffre-resources/dist/SuperAdmin";
|
import User from "le-coffre-resources/dist/Admin";
|
||||||
import { Prisma, Users } from "@prisma/client";
|
import { Prisma, Users } from "@prisma/client";
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@ -91,4 +91,5 @@ export default class UsersService extends BaseService {
|
|||||||
return this.userRepository.findManyToCheck();
|
return this.userRepository.findManyToCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user