diff --git a/Dockerfile b/Dockerfile index 85e1458c..a00cf919 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,8 @@ RUN npm install -D prisma@4.11.0 COPY package.json ./ RUN apk update && apk add openssh-client git +# ENV PUPPETEER_CACHE_DIR=~/leCoffre/.cache/puppeteer +# ENV PUPPETEER_SKIP_DOWNLOAD=false COPY id_rsa /root/.ssh/id_rsa RUN chmod 600 ~/.ssh/id_rsa @@ -22,6 +24,8 @@ WORKDIR leCoffre COPY --from=deps leCoffre/node_modules ./node_modules COPY --from=deps leCoffre/package.json package.json +#COPY --from=deps leCoffre/.cache ./.cache + COPY tsconfig.json tsconfig.json COPY src src @@ -39,8 +43,9 @@ COPY --from=builder --chown=lecoffreuser leCoffre/node_modules ./node_modules COPY --from=builder --chown=lecoffreuser leCoffre/dist dist COPY --from=builder --chown=lecoffreuser leCoffre/package.json ./package.json COPY --from=builder --chown=lecoffreuser leCoffre/src/common/databases ./src/common/databases +#COPY --from=builder --chown=lecoffreuser leCoffre/.cache ./.cache USER lecoffreuser -CMD ["npm", "run", "api:start"] +CMD ["npm", "run", "start"] EXPOSE 3001 \ No newline at end of file diff --git a/devops/stg.values.yaml b/devops/stg.values.yaml index 494ee569..5ae4ae13 100644 --- a/devops/stg.values.yaml +++ b/devops/stg.values.yaml @@ -5,7 +5,7 @@ scwSecretKey: AgChoEnPitXp4Ny/rVMEcevaWKNVpyj2cJYAcq+yFqKwVwnLB+ffDvwqz9XBHu+6d4 lecoffreBack: serviceAccountName: lecoffre-back-sa envSecrets: stg-env - command: "'sh', '-c', 'export $(xargs { + const ruleFound = allRules.find((r) => r.uid === rule.uid && r.namespace === "notary"); + return ruleFound; + }); + } //init IOfficeRole resource with request body values const officeRoleEntity = OfficeRole.hydrate(req.body); //validate officeRole - await validateOrReject(officeRoleEntity, { groups: ["updateOfficeRole"] }); + await validateOrReject(officeRoleEntity, { groups: ["updateOfficeRole"] }); //call service to get prisma entity const officeRoleEntityUpdated = await this.officeRolesService.update(officeRoleEntity); diff --git a/src/app/api/customer/CustomersController.ts b/src/app/api/customer/CustomersController.ts deleted file mode 100644 index f958ab7e..00000000 --- a/src/app/api/customer/CustomersController.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Response, Request } from "express"; -import { Controller, Get } from "@ControllerPattern/index"; -import ApiController from "@Common/system/controller-pattern/ApiController"; -import CustomersService from "@Services/customer/CustomersService/CustomersService"; -import { Service } from "typedi"; -import Customer from "le-coffre-resources/dist/Customer"; -import authHandler from "@App/middlewares/AuthHandler"; -import ruleHandler from "@App/middlewares/RulesHandler"; - -@Controller() -@Service() -export default class CustomersController extends ApiController { - constructor(private customersService: CustomersService) { - super(); - } - - /** - * @description Get all customers - */ - @Get("/api/v1/customer/customers") - protected async get(req: Request, response: Response) { - try { - //get query - let query; - if (req.query["q"]) { - query = JSON.parse(req.query["q"] as string); - } - - - //call service to get prisma entity - const customersEntities = await this.customersService.get(query); - - //Hydrate ressource with prisma entity - const customers = Customer.hydrateArray(customersEntities, { strategy: "excludeAll" }); - - //success - this.httpSuccess(response, customers); - } catch (error) { - this.httpInternalError(response, error); - return; - } - } - - - /** - * @description Get a specific customer by uid - */ - @Get("/api/v1/customer/customers/:uid", [authHandler, ruleHandler]) - protected async getOneByUid(req: Request, response: Response) { - try { - const uid = req.params["uid"]; - if (!uid) { - this.httpBadRequest(response, "No uid provided"); - return; - } - - let query; - if (req.query["q"]) { - query = JSON.parse(req.query["q"] as string); - } - - const customerEntity = await this.customersService.getByUid(uid, query); - - if (!customerEntity) { - this.httpNotFoundRequest(response, "customer not found"); - return; - } - - //Hydrate ressource with prisma entity - const customer = Customer.hydrate(customerEntity, { strategy: "excludeAll" }); - - //success - this.httpSuccess(response, customer); - } catch (error) { - this.httpInternalError(response, error); - return; - } - } -} diff --git a/src/app/api/customer/DocumentsController.ts b/src/app/api/customer/DocumentsController.ts index d802ba36..966b613a 100644 --- a/src/app/api/customer/DocumentsController.ts +++ b/src/app/api/customer/DocumentsController.ts @@ -24,13 +24,14 @@ export default class DocumentsController extends ApiController { protected async get(req: Request, response: Response) { try { //get query - let query: Prisma.CustomersFindManyArgs = {}; + let query: Prisma.DocumentsFindManyArgs = {}; if (req.query["q"]) { query = JSON.parse(req.query["q"] as string); } - const customerId: string = req.body.user.customerId; - const customerWhereInput: Prisma.DocumentsWhereInput ={ depositor: { uid: customerId } }; + if(query.where?.depositor) delete query.where.depositor; + if(query.where?.depositor_uid) delete query.where.depositor_uid; + const customerWhereInput: Prisma.DocumentsWhereInput = { ...query.where, depositor: { uid: customerId } }; query.where = customerWhereInput; diff --git a/src/app/api/customer/OfficeFoldersController.ts b/src/app/api/customer/OfficeFoldersController.ts index e524b445..7e44ef33 100644 --- a/src/app/api/customer/OfficeFoldersController.ts +++ b/src/app/api/customer/OfficeFoldersController.ts @@ -5,6 +5,8 @@ import OfficeFoldersService from "@Services/customer/OfficeFoldersService/Office import { Service } from "typedi"; import { OfficeFolders, Prisma } from "@prisma/client"; import { OfficeFolder } from "le-coffre-resources/dist/Customer"; +import officeFolderHandler from "@App/middlewares/CustomerHandler/FolderHandler"; +import authHandler from "@App/middlewares/AuthHandler"; // import authHandler from "@App/middlewares/AuthHandler"; // import ruleHandler from "@App/middlewares/RulesHandler"; // import folderHandler from "@App/middlewares/OfficeMembershipHandlers/FolderHandler"; @@ -19,7 +21,7 @@ export default class OfficeFoldersController extends ApiController { /** * @description Get all folders */ - @Get("/api/v1/customer/folders") + @Get("/api/v1/customer/folders", [authHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -28,37 +30,14 @@ export default class OfficeFoldersController extends ApiController { query = JSON.parse(req.query["q"] as string); } - - if (req.query["search"] && typeof req.query["search"] === "string") { - const filter = req.query["search"]; - query = { - where: { - OR: [ - { - name: { contains: filter, mode: "insensitive" }, - }, - { - folder_number: { contains: filter, mode: "insensitive" }, - }, - { - customers: { - some: { - contact: { - OR: [ - { first_name: { contains: filter, mode: "insensitive" } }, - { last_name: { contains: filter, mode: "insensitive" } }, - ], - }, - }, - }, - }, - ], - }, - }; + const customerId: string = req.body.user.customerId; + if(!customerId) { + this.httpBadRequest(response, "No customerId provided"); + return; } - const officeWhereInput: Prisma.OfficesWhereInput = {}; - if (!query.where) query.where = { office: officeWhereInput }; - query.where.office = officeWhereInput; + if(query.where?.customers) delete query.where.customers; + const officeFolderWhereInput: Prisma.OfficeFoldersWhereInput = { ...query.where, customers: { some: { uid: customerId } }}; + query.where = officeFolderWhereInput; //call service to get prisma entity const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); @@ -79,7 +58,7 @@ export default class OfficeFoldersController extends ApiController { * @description Get a specific folder by uid * @returns IFolder */ - @Get("/api/v1/customer/folders/:uid") + @Get("/api/v1/customer/folders/:uid", [authHandler, officeFolderHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -91,8 +70,10 @@ export default class OfficeFoldersController extends ApiController { let query; if (req.query["q"]) { query = JSON.parse(req.query["q"] as string); + if(query?.customers) { + query.customers = true; + } } - const officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); if (!officeFolderEntity) { diff --git a/src/app/api/id360/CustomerController.ts b/src/app/api/id360/CustomerController.ts index 49abb8fb..fc234983 100644 --- a/src/app/api/id360/CustomerController.ts +++ b/src/app/api/id360/CustomerController.ts @@ -35,13 +35,11 @@ export default class CustomerController extends ApiController { } try { const enrollment = await this.id360Service.getEnrollment(callbackToken); - console.log("enrollment", enrollment); if (enrollment.status !== "OK") { this.httpUnauthorized(response, "Enrollment status is not OK"); return; } const customerData = await this.id360Service.getReport(enrollment.id); - console.log(customerData.external_methods.france_connect.results); const customer = await this.customerService.get({ where: { contact: { @@ -55,7 +53,6 @@ export default class CustomerController extends ApiController { contact: true, } }); - console.log(customer); // const contact = await this.customerService.getByEmail( // customerData.external_methods.france_connect.results.france_connect_out_userinfo[0].email, // ); diff --git a/src/app/api/id360/DocumentController.ts b/src/app/api/id360/DocumentController.ts index 73cd6d5b..1b8d43ca 100644 --- a/src/app/api/id360/DocumentController.ts +++ b/src/app/api/id360/DocumentController.ts @@ -50,10 +50,7 @@ export default class DocumentController extends ApiController { this.httpBadRequest(response, "Missing document id"); return; } - - const enrl = await this.id360Service.createEnrollment(documentId!); - console.log(enrl) - + await this.id360Service.createEnrollment(documentId!); //success this.httpSuccess(response); } catch (error) { diff --git a/src/app/api/idnot/UserController.ts b/src/app/api/idnot/UserController.ts index 2106276a..102af93a 100644 --- a/src/app/api/idnot/UserController.ts +++ b/src/app/api/idnot/UserController.ts @@ -37,30 +37,7 @@ export default class UserController extends ApiController { const payload = await this.authService.getUserJwtPayload(user.idNot); const accessToken = this.authService.generateAccessToken(payload); const refreshToken = this.authService.generateRefreshToken(payload); - - this.httpSuccess(response, { accessToken, refreshToken }); - } catch (error) { - console.log(error); - this.httpInternalError(response); - return; - } - } - - @Post("/api/v1/idnot/user/login/:idnot") - protected async login(req: Request, response: Response) { - try { - const id = req.params["idnot"]; - if (!id) throw new Error("idnot is required"); - - const payload = await this.authService.getUserJwtPayload(id); - if (!payload) { - this.httpNotFoundRequest(response); - return; - } - const accessToken = this.authService.generateAccessToken(payload); - const refreshToken = this.authService.generateRefreshToken(payload); - - //success + this.httpSuccess(response, { accessToken, refreshToken }); } catch (error) { console.log(error); diff --git a/src/app/api/notary/CustomersController.ts b/src/app/api/notary/CustomersController.ts index 59d070c7..af756207 100644 --- a/src/app/api/notary/CustomersController.ts +++ b/src/app/api/notary/CustomersController.ts @@ -7,6 +7,7 @@ import { Customer } from "le-coffre-resources/dist/Notary"; import { validateOrReject } from "class-validator"; import authHandler from "@App/middlewares/AuthHandler"; import ruleHandler from "@App/middlewares/RulesHandler"; +import { Prisma } from "@prisma/client"; @Controller() @Service() @@ -22,11 +23,17 @@ export default class CustomersController extends ApiController { protected async get(req: Request, response: Response) { try { //get query - let query; + let query: Prisma.CustomersFindManyArgs = {}; if (req.query["q"]) { query = JSON.parse(req.query["q"] as string); } + const officeId: string = req.body.user.office_Id; + if(query.where?.office_folders?.some?.office_uid) delete query.where.office_folders.some.office_uid; + if(query.where?.office_folders?.some?.office?.uid) delete query.where?.office_folders?.some?.office?.uid; + const customerWhereInput: Prisma.CustomersWhereInput = { ...query.where, office_folders: { some: { office_uid: officeId } }}; + query.where = customerWhereInput; + //call service to get prisma entity const customersEntities = await this.customersService.get(query); diff --git a/src/app/api/notary/OfficeFolderAnchorsController.ts b/src/app/api/notary/OfficeFolderAnchorsController.ts index 29f9e0ea..f0e1c76f 100644 --- a/src/app/api/notary/OfficeFolderAnchorsController.ts +++ b/src/app/api/notary/OfficeFolderAnchorsController.ts @@ -5,15 +5,35 @@ import { Service } from "typedi"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { getFolderHashes } from "@Common/optics/notary"; import OfficeFoldersService from "@Services/notary/OfficeFoldersService/OfficeFoldersService"; +import OfficeFolderAnchorsRepository from "@Repositories/OfficeFolderAnchorsRepository"; import SecureService from "@Services/common/SecureService/SecureService"; import authHandler from "@App/middlewares/AuthHandler"; import ruleHandler from "@App/middlewares/RulesHandler"; import folderHandler from "@App/middlewares/OfficeMembershipHandlers/FolderHandler"; +import OfficeFolderAnchor from "le-coffre-resources/dist/Notary/OfficeFolderAnchor"; +const hydrateOfficeFolderAnchor = (data: any): OfficeFolderAnchor => + OfficeFolderAnchor.hydrate( + { + hash_sources: data.hash_sources, + root_hash: data.root_hash, + + blockchain: data.transactions[0].blockchain, + status: data.transactions[0].status, + + anchor_nb_try: data.transactions[0].anchor_nb_try, + tx_id: data.transactions[0].tx_id?.toString() ?? undefined, + tx_link: data.transactions[0].tx_link, + tx_hash: data.transactions[0].tx_hash, + + anchored_at: data.transactions[0].anchoring_timestamp, + }, + { strategy: "excludeAll" }, + ); @Controller() @Service() export default class OfficeFoldersController extends ApiController { - constructor(private secureService: SecureService, private officeFoldersService: OfficeFoldersService) { + constructor(private secureService: SecureService, private officeFolderAnchorsRepository: OfficeFolderAnchorsRepository, private officeFoldersService: OfficeFoldersService) { super(); } @@ -83,16 +103,30 @@ export default class OfficeFoldersController extends ApiController { files: true, }, }, + folder_anchor: true, }; - const officeFolderFound = await this.officeFoldersService.getByUid(uid, query); + const officeFolderFound: any = await this.officeFoldersService.getByUid(uid, query); if (!officeFolderFound) { this.httpNotFoundRequest(response, "Office folder not found"); return; } + const officeFolderAnchorFound = OfficeFolderAnchor.hydrate(officeFolderFound.folder_anchor, { + strategy: "excludeAll", + }); + + if (officeFolderAnchorFound) { + this.httpBadRequest(response, { + error: "Office folder already anchored", + folder_anchor: officeFolderAnchorFound, + }); + return; + } + const officeFolder = OfficeFolder.hydrate(officeFolderFound, { strategy: "excludeAll" }); + const folderHashes = getFolderHashes(officeFolder); if (folderHashes.length === 0) { @@ -101,9 +135,20 @@ export default class OfficeFoldersController extends ApiController { } const sortedHashes = [...folderHashes].sort(); - const anchor = await this.secureService.anchor(sortedHashes); + const data = await this.secureService.anchor(sortedHashes); - this.httpSuccess(response, anchor); + const officeFolderAnchor = hydrateOfficeFolderAnchor(data); + + const newOfficeFolderAnchor = await this.officeFolderAnchorsRepository.create( + officeFolderAnchor + ); + + await this.officeFoldersService.update( + uid, + OfficeFolder.hydrate({ uid: uid, folder_anchor: newOfficeFolderAnchor }, { strategy: "excludeAll" }), + ); + + this.httpSuccess(response, officeFolderAnchor); } catch (error) { this.httpInternalError(response, error); return; @@ -129,9 +174,10 @@ export default class OfficeFoldersController extends ApiController { files: true, }, }, + folder_anchor: true, }; - const officeFolderFound = await this.officeFoldersService.getByUid(uid, query); + const officeFolderFound: any = await this.officeFoldersService.getByUid(uid, query); if (!officeFolderFound) { this.httpNotFoundRequest(response, "Office folder not found"); @@ -147,9 +193,31 @@ export default class OfficeFoldersController extends ApiController { } const sortedHashes = [...folderHashes].sort(); - const anchor = await this.secureService.verify(sortedHashes); + const officeFolderAnchorFound = OfficeFolderAnchor.hydrate(officeFolderFound.folder_anchor, { + strategy: "excludeAll", + }); - this.httpSuccess(response, anchor); + if (!officeFolderAnchorFound || !officeFolderAnchorFound.uid) { + this.httpNotFoundRequest(response, {error: "Not anchored", hash_sources: sortedHashes}); + return; + } + + const data = await this.secureService.verify(sortedHashes); + + if (data.errors || data.transactions.length === 0) { + this.httpNotFoundRequest(response, {error: "Not anchored", hash_sources: sortedHashes}); + return; + } + + const officeFolderAnchor = hydrateOfficeFolderAnchor(data); + + const updatedOfficeFolderAnchor = await this.officeFolderAnchorsRepository.update( + officeFolderAnchorFound.uid, + officeFolderAnchor + ); + + this.httpSuccess(response, updatedOfficeFolderAnchor); + return; } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/notary/RulesController.ts b/src/app/api/notary/RulesController.ts index 63d29165..435a27c1 100644 --- a/src/app/api/notary/RulesController.ts +++ b/src/app/api/notary/RulesController.ts @@ -26,6 +26,10 @@ export default class RulesController extends ApiController { query = JSON.parse(req.query["q"] as string); } + query.where = { + ...query.where, + namespace: "notary", + }; //call service to get prisma entity const rulesEntities = await this.rulesService.get(query); @@ -57,6 +61,11 @@ export default class RulesController extends ApiController { query = JSON.parse(req.query["q"] as string); } + query.where = { + ...query.where, + namespace: "notary", + }; + const ruleEntity = await this.rulesService.getByUid(uid, query); if (!ruleEntity) { diff --git a/src/app/api/common/UserNotificationController.ts b/src/app/api/notary/UserNotificationController.ts similarity index 79% rename from src/app/api/common/UserNotificationController.ts rename to src/app/api/notary/UserNotificationController.ts index eec01d06..1654df3b 100644 --- a/src/app/api/common/UserNotificationController.ts +++ b/src/app/api/notary/UserNotificationController.ts @@ -5,6 +5,7 @@ import { Service } from "typedi"; import UserNotification from "le-coffre-resources/dist/Notary/UserNotification"; import UserNotificationService from "@Services/common/UserNotificationService/UserNotificationService"; import authHandler from "@App/middlewares/AuthHandler"; +import { Prisma } from "@prisma/client"; @Controller() @Service() @@ -16,7 +17,7 @@ export default class UserNotificationController extends ApiController { /** * @description Get all customers */ - @Get("/api/v1/notifications", [authHandler]) + @Get("/api/v1/notary/notifications", [authHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -25,11 +26,13 @@ export default class UserNotificationController extends ApiController { query = JSON.parse(req.query["q"] as string); } - if (query.where) { - query.where = { ...query.where, user: { uid: req.body.user.uid } }; - } else { - query.where = { user: { uid: req.body.user.uid } }; - } + + const userId: string = req.body.user.userId; + if(query.where?.user_uid) delete query.where.user_uid; + if(query.where?.user?.uid) delete query.where.user.uid; + const notificationWhereInput: Prisma.UserNotificationsWhereInput = { ...query.where, user_uid: userId }; + query.where = notificationWhereInput; + query.include = { notification: true }; //call service to get prisma entity const userNotificationEntities = await this.userNotificationService.get(query); @@ -48,7 +51,7 @@ export default class UserNotificationController extends ApiController { /** * @description Modify a specific customer by uid */ - @Put("/api/v1/notifications/:uid") + @Put("/api/v1/notary/notifications/:uid", [authHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -64,6 +67,11 @@ export default class UserNotificationController extends ApiController { return; } + if(userNotificationFound.user_uid !== req.body.user.userId) { + this.httpForbidden(response, "You are not allowed to update this user notification"); + return; + } + //init IUser resource with request body values const userNotificationEntity = UserNotification.hydrate(req.body); @@ -86,7 +94,7 @@ export default class UserNotificationController extends ApiController { /** * @description Get a specific customer by uid */ - @Get("/api/v1/notifications/:uid") + @Get("/api/v1/notary/notifications/:uid", [authHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -108,6 +116,11 @@ export default class UserNotificationController extends ApiController { return; } + if(userNotificationEntity.user_uid !== req.body.userId) { + this.httpForbidden(response, "You are allowed to get this user notification"); + return; + } + //Hydrate ressource with prisma entity const userNotification = UserNotification.hydrate(userNotificationEntity, { strategy: "excludeAll" }); diff --git a/src/app/api/super-admin/CustomersController.ts b/src/app/api/super-admin/CustomersController.ts index d1a15fd2..62a82548 100644 --- a/src/app/api/super-admin/CustomersController.ts +++ b/src/app/api/super-admin/CustomersController.ts @@ -8,6 +8,7 @@ import { validateOrReject } from "class-validator"; import authHandler from "@App/middlewares/AuthHandler"; import ruleHandler from "@App/middlewares/RulesHandler"; import roleHandler from "@App/middlewares/RolesHandler"; +import { Prisma } from "@prisma/client"; @Controller() @Service() @@ -28,6 +29,12 @@ export default class CustomersController extends ApiController { query = JSON.parse(req.query["q"] as string); } + const officeId: string = req.body.user.office_Id; + if(query.where?.office_folders?.some?.office_uid) delete query.where.office_folders.some.office_uid; + if(query.where?.office_folders?.some?.office?.uid) delete query.where?.office_folders?.some?.office?.uid; + const customerWhereInput: Prisma.CustomersWhereInput = { ...query.where, office_folders: { some: { office_uid: officeId } }}; + query.where = customerWhereInput; + //call service to get prisma entity const customersEntities = await this.customersService.get(query); diff --git a/src/app/index.ts b/src/app/index.ts index fd205cf5..092417a4 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -42,14 +42,12 @@ import FilesControllerCustomer from "./api/customer/FilesController"; import DocumentsControllerCustomer from "./api/customer/DocumentsController"; import OfficeFoldersController from "./api/customer/OfficeFoldersController"; import OfficeFolderAnchorsController from "./api/notary/OfficeFolderAnchorsController"; -import CustomersController from "./api/customer/CustomersController"; import AppointmentsController from "./api/super-admin/AppointmentsController"; import VotesController from "./api/super-admin/VotesController"; import LiveVoteController from "./api/super-admin/LiveVoteController"; import DocumentControllerId360 from "./api/id360/DocumentController"; import CustomerControllerId360 from "./api/id360/CustomerController"; - -import UserNotificationController from "./api/common/UserNotificationController"; +import UserNotificationController from "./api/notary/UserNotificationController"; /** @@ -105,7 +103,6 @@ export default { Container.get(DocumentsControllerCustomer); Container.get(OfficeFoldersController); Container.get(OfficeFolderAnchorsController); - Container.get(CustomersController); Container.get(UserNotificationController); Container.get(DocumentControllerId360); Container.get(CustomerControllerId360); diff --git a/src/app/middlewares/CustomerHandler/FolderHandler.ts b/src/app/middlewares/CustomerHandler/FolderHandler.ts new file mode 100644 index 00000000..aaf6ad54 --- /dev/null +++ b/src/app/middlewares/CustomerHandler/FolderHandler.ts @@ -0,0 +1,24 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import OfficeFoldersService from "@Services/customer/OfficeFoldersService/OfficeFoldersService"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; + +export default async function officeFolderHandler(req: Request, response: Response, next: NextFunction) { + const customerId = req.body.user.customerId; + const uid = req.path && req.path.split("/")[5]; + + if (uid) { + const officeFolderService = Container.get(OfficeFoldersService); + const officeFolder = await officeFolderService.getByUidWithCustomers(uid); + if (!officeFolder) { + response.status(HttpCodes.NOT_FOUND).send("Folder not found"); + return; + } + if (!officeFolder.customers.find((customer) => customer.uid == customerId)) { + response.status(HttpCodes.UNAUTHORIZED).send("Not authorized with this depositor"); + return; + } + } + + next(); +} diff --git a/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts index 9d684de0..f6b9714f 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/DocumentHandler.ts @@ -45,12 +45,12 @@ export default async function documentHandler(req: Request, response: Response, const document = await documentService.getByUidWithOffice(uid!); if (!document) { - response.sendStatus(HttpCodes.NOT_FOUND); + response.sendStatus(HttpCodes.NOT_FOUND).send("Document not found"); return; } - if (document.document_type.office.uid != officeId) { - response.sendStatus(HttpCodes.UNAUTHORIZED); + if (document.folder.office.uid != officeId) { + response.sendStatus(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } } diff --git a/src/common/databases/migrations/20230929113629_rule_namespace/migration.sql b/src/common/databases/migrations/20230929113629_rule_namespace/migration.sql new file mode 100644 index 00000000..0eeea98b --- /dev/null +++ b/src/common/databases/migrations/20230929113629_rule_namespace/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "rules" ADD COLUMN "namespace" VARCHAR(255) NOT NULL DEFAULT 'notary'; diff --git a/src/common/databases/schema.prisma b/src/common/databases/schema.prisma index a2120220..113f741d 100644 --- a/src/common/databases/schema.prisma +++ b/src/common/databases/schema.prisma @@ -299,7 +299,7 @@ model Rules { updated_at DateTime? @updatedAt role Roles[] @relation("RolesHasRules") office_roles OfficeRoles[] @relation("OfficeRolesHasRules") - + namespace String @db.VarChar(255) @default("notary") @@map("rules") } diff --git a/src/common/databases/seeders/seeder.ts b/src/common/databases/seeders/seeder.ts index 6c144e8e..0c46ad72 100644 --- a/src/common/databases/seeders/seeder.ts +++ b/src/common/databases/seeders/seeder.ts @@ -19,7 +19,6 @@ export default async function main() { try { const prisma = new PrismaClient(); - const idNot2 = "jelkvelknvlkn"; const idNot3 = "rleenrenlnr"; const idNot4 = "ljfeflecnmd"; const idNot5 = "rflrefrjf"; @@ -171,15 +170,15 @@ export default async function main() { const contacts: Contact[] = [ { address: addresses[0], - first_name: "Arnaud", - last_name: "Daubernatali", - email: "arnaud.daubernatali@smart-chain.fr", + first_name: "Angela", + last_name: "Dubois", + email: "angela.dubois@gmail.com", phone_number: "06 12 34 56 78", cell_phone_number: "06 12 34 56 78", birthdate: null, created_at: new Date(), updated_at: new Date(), - civility: ECivility.MALE, + civility: ECivility.FEMALE, }, { address: addresses[1], @@ -231,9 +230,9 @@ export default async function main() { }, { address: addresses[5], - first_name: "Thibault", - last_name: "Dubois", - email: "thibault.dubois@outlook.com", + first_name: "Paul", + last_name: "Dupont", + email: "paul.dupont@outlook.com", phone_number: "06 67 89 01 23", cell_phone_number: "06 67 89 01 23", birthdate: null, @@ -243,9 +242,9 @@ export default async function main() { }, { address: addresses[6], - first_name: "Léa", - last_name: "Fontaine", - email: "lea.fontaine@gmail.com", + first_name: "Jean", + last_name: "Dubigot", + email: "jean.dubigot@gmail.com", phone_number: "06 78 90 12 34", cell_phone_number: "06 78 90 12 34", birthdate: null, @@ -255,9 +254,9 @@ export default async function main() { }, { address: addresses[7], - first_name: "Guillaume", - last_name: "Renaud", - email: "guillaume.renaud@gmail.com", + first_name: "Vincent", + last_name: "Martin", + email: "vincent.martin@gmail.com", phone_number: "06 89 01 23 45", cell_phone_number: "06 89 01 23 45", birthdate: null, @@ -424,6 +423,12 @@ export default async function main() { ]; const customers: Customer[] = [ + { + contact: contacts[0], + created_at: new Date(), + updated_at: new Date(), + status: ECustomerStatus.PENDING, + }, { contact: contacts[5], created_at: new Date(), @@ -522,259 +527,302 @@ export default async function main() { label: "Lecture des utilisateurs", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET offices", - label: "Lecture des offices", + label: "Afficher des offices", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET customers", - label: "Lecture des clients", + label: "Afficher des clients", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET deeds", - label: "Lecture des actes", + label: "Voir des types d'acte", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET deed-types", label: "Lecture des types d'actes", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET documents", - label: "Lecture des documents", + label: "Afficher des documents", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET document-types", label: "Lecture des types de documents", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET files", label: "Lecture des fichiers", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET folders", - label: "Lecture des dossiers", + label: "Afficher les dossiers", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET roles", - label: "Lecture utilisateurs", + label: "Afficher les rôles", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET rules", - label: "Lecture des droits", + label: "Afficher les droits", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "GET office-roles", label: "Lecture des rôles d'office", created_at: new Date(), updated_at: new Date(), + namespace: "collaborator", }, { name: "POST deeds", - label: "Création des actes", + label: "Créer un template de type d'acte", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "PUT deeds", - label: "Modification des actes", + label: "Modifier un type d'acte", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "DELETE deeds", - label: "Suppression des actes", + label: "Supprimer des types d'actes", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "POST folders", - label: "Création des dossiers", + label: "Créer un dossier", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "PUT folders", - label: "Modification des dossiers", + label: "Modifier des dossiers", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "DELETE folders", - label: "Suppression des dossiers", + label: "Supprimer un dossier vide", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "POST documents", - label: "Création des documents", + label: "Demander des documents à un client", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "PUT documents", - label: "Modification des documents", + label: "Valider des documents", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "DELETE documents", - label: "Suppression des documents", + label: "Supprimer un document", created_at: new Date(), updated_at: new Date(), + namespace: "super-admin", }, { name: "POST customers", - label: "Création des clients", + label: "Créer des clients", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "PUT customers", - label: "Modification des clients", + label: "Modifier des clients", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "DELETE customers", - label: "Suppression des clients", + label: "Supprimer un client", created_at: new Date(), updated_at: new Date(), + namespace: "super-admin", }, { name: "POST anchors", label: "Ancrer un dossier", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "GET anchors", label: "Vérifier l'ancrage un dossier", created_at: new Date(), updated_at: new Date(), + namespace: "notary", }, { name: "POST deed-types", label: "Création des types d'actes", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "PUT deed-types", label: "Modification des types d'actes", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "DELETE deed-types", label: "Suppression des types d'actes", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "POST document-types", label: "Création des types de documents", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "PUT document-types", label: "Modification des types de documents", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "DELETE document-types", label: "Suppression des types de documents", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "POST office-roles", label: "Création des rôles d'office", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "PUT office-roles", label: "Modification des rôles d'office", created_at: new Date(), updated_at: new Date(), + namespace: "admin", }, { name: "DELETE office-roles", label: "Suppression des rôles d'office", created_at: new Date(), updated_at: new Date(), - }, - { - name: "DELETE office-roles", - label: "Suppression des rôles d'office", - created_at: new Date(), - updated_at: new Date(), + namespace: "admin", }, { name: "PUT users", label: "Modification des utilisateurs", created_at: new Date(), updated_at: new Date(), + namespace: "admin", + }, + { + name: "DELETE office-roles", + label: "Suppression des rôles d'office", + created_at: new Date(), + updated_at: new Date(), + namespace: "super-admin", }, { name: "PUT offices", label: "Modification des offices", created_at: new Date(), updated_at: new Date(), + namespace: "super-admin", }, ]; + const collaboratorRules = rules.filter((rule) => rule.namespace === "collaborator"); + const notaryRules = [...collaboratorRules, ...rules.filter((rule) => rule.namespace === "notary")]; + const adminRules = [...notaryRules, ...rules.filter((rule) => rule.namespace === "admin")]; + const superAdminRules = [...adminRules, ...rules.filter((rule) => rule.namespace === "super-admin")]; + const roles: Role[] = [ { name: "super-admin", label: "Super administrateur", created_at: new Date(), updated_at: new Date(), - rules: rules, + rules: superAdminRules, }, { name: "admin", label: "Administrateur", created_at: new Date(), updated_at: new Date(), - rules: rules.slice(0, 35), + rules: adminRules, }, { name: "notary", label: "Notaire", created_at: new Date(), updated_at: new Date(), - rules: rules.slice(0, 25), + rules: [], }, { name: "default", label: "Utilisateur", created_at: new Date(), updated_at: new Date(), - rules: rules.slice(0,1), + rules: [], }, ]; @@ -784,26 +832,18 @@ export default async function main() { created_at: new Date(), updated_at: new Date(), office: offices[0]!, - rules: rules.slice(0, 35), + rules: notaryRules, }, { name: "Collaborateur", created_at: new Date(), updated_at: new Date(), office: offices[0]!, - rules: rules.slice(0, 22), + rules: notaryRules, }, ]; const users: User[] = [ - { - created_at: new Date(), - updated_at: new Date(), - idNot: idNot2, - contact: contacts[0], - office_membership: offices[0], - role: roles[0], - }, { created_at: new Date(), updated_at: new Date(), @@ -839,111 +879,32 @@ export default async function main() { role: roles[3], }, ]; + const documentTypes: DocumentType[] = [ { archived_at: null, - name: "Document d'identité", + name: "Carte Nationale d'Identité recto-verso", office: offices[0], - private_description: - "Document officiel d'identification utilisé par plusieurs personnes pour prouver leur identité et leur nationalité (CNI, passeport)", - public_description: - "Document officiel d'identification utilisé par plusieurs personnes pour prouver leur identité et leur nationalité (CNI, passeport)", + private_description: "Document d'identité", + public_description: "Document d'identité", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Taxe Foncière", + name: "Contrat de mariage", office: offices[0], - private_description: - "Impôt annuel imposé sur les propriétés foncières et utilisé pour financer les services publics locaux.", - public_description: - "Impôt annuel imposé sur les propriétés foncières et utilisé pour financer les services publics locaux.", - created_at: new Date(), - updated_at: new Date(), - }, - - { - archived_at: null, - name: "Contrat Mariage", - office: offices[0], - private_description: "Accord légal qui établit les droits et les obligations entre deux personnes s'unissant en mariage.", - public_description: "Accord légal qui établit les droits et les obligations entre deux personnes s'unissant en mariage.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Livret de famille", + name: "Convention de PACS", office: offices[0], - private_description: - "Document officiel qui enregistre les détails et les événements familiaux tels que les mariages, les naissances et les décès d'un couple et de leurs enfants.", - public_description: - "Document officiel qui enregistre les détails et les événements familiaux tels que les mariages, les naissances et les décès d'un couple et de leurs enfants.", - created_at: new Date(), - updated_at: new Date(), - }, - { - archived_at: null, - name: "Bail commercial", - office: offices[0], - private_description: - "Contrat légal entre un propriétaire et un locataire pour la location d'un bien immobilier utilisé à des fins commerciales ou professionnelles.", - public_description: - "Contrat légal entre un propriétaire et un locataire pour la location d'un bien immobilier utilisé à des fins commerciales ou professionnelles.", - created_at: new Date(), - updated_at: new Date(), - }, - { - archived_at: null, - name: "Statuts SCI", - office: offices[0], - private_description: - "Document légal qui définit les règles et les dispositions régissant la Société Civile Immobilière (SCI).", - public_description: - "Document légal qui définit les règles et les dispositions régissant la Société Civile Immobilière (SCI).", - created_at: new Date(), - updated_at: new Date(), - }, - { - archived_at: null, - name: "Avis de taxe foncière", - office: offices[0], - private_description: "Notification officielle indiquant le montant de l'impôt foncier dû sur une propriété.", - public_description: "Notification officielle indiquant le montant de l'impôt foncier dû sur une propriété.", - created_at: new Date(), - updated_at: new Date(), - }, - { - archived_at: null, - name: "Appel de charge de copropriété", - office: offices[0], - private_description: - "Document envoyé aux copropriétaires pour les informer des dépenses et des charges communes liées à la gestion et à l'entretien de l'immeuble.", - public_description: - "Document envoyé aux copropriétaires pour les informer des dépenses et des charges communes liées à la gestion et à l'entretien de l'immeuble.", - created_at: new Date(), - updated_at: new Date(), - }, - { - archived_at: null, - name: "PVAG", - office: offices[0], - private_description: - "Compte rendu écrit des discussions, décisions et résolutions prises lors d'une réunion d'assemblée générale de copropriété.", - public_description: - "Compte rendu écrit des discussions, décisions et résolutions prises lors d'une réunion d'assemblée générale de copropriété.", - created_at: new Date(), - updated_at: new Date(), - }, - { - archived_at: null, - name: "Règlement de copropriété", - office: offices[0], - private_description: - "Document juridique qui établit les règles et les droits des copropriétaires d'un immeuble en copropriété.", - public_description: - "Document juridique qui établit les règles et les droits des copropriétaires d'un immeuble en copropriété.", + private_description: " ", + public_description: "Avec précision du régime", created_at: new Date(), updated_at: new Date(), }, @@ -951,98 +912,631 @@ export default async function main() { archived_at: null, name: "Titre de propriété", office: offices[0], - private_description: "Document légal qui atteste de la propriété d'un bien immobilier et en identifie le propriétaire.", - public_description: "Document légal qui atteste de la propriété d'un bien immobilier et en identifie le propriétaire.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Plan et loi carrez", + name: "Cahier des charges du lotissement", office: offices[0], - private_description: - "Document officiel qui mesure la superficie d'un lot ou d'un bien immobilier, conformément à la loi Carrez qui encadre les transactions immobilières.", + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Règlement du lotissement", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Cahier de prescriptions architecturales", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Statuts de l'association syndicale libre", + office: offices[0], + private_description: " ", + public_description: "Avec nom et adresse du président", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Etat descriptif de division et règlement de copropriété", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Etat descriptif de division et règlement de copropriété modificatifs", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Carnet d'entretien", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Trois derniers PV D'AG", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Trois derniers relevés de charge", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Bail ou congé délivré", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Certificat d'assainissement", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Facture ou contrat d'electricité", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Facture ou contrat de gaz", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Loi carrez", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Etat parasitaire", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Amiante", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Facture des travaux", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Garanties décénales des entreprises", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "PV de réception des travaux", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Permis de construire et modificatifs", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Déclaration attestation l'achèvement des travaux", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Attestation de non opposition", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Assurance décenale", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Dommage ouvrage", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Dernière facture ramonage", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Liste du mobilier", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "RIB daté et signé", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Extrait KBIS et statuts de la société", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Document arpentage et plan de division", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Accord de prêt", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Offre de prêt", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Attestation dépôt de permis de construire", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Permis de construire", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Extrait acte de décès", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Fiche de renseignements d'états civils", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Donation entre epoux", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Testament", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Liste des banques avce un compte bancaire", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Contrat d'assurance-vie", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Liste des caisses versant une retraite ou une pension", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Dernière déclaration de revenus", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Avis d'imposition (revenus et ISF)", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Avis d'imposition (foncier et habitation)", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Liste des emprunts en cours", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Actes de donation", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Déclarations de dons faites aux impôts", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Actes de succession", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Actes de vente de biens", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Factures de travaux", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Bail de location", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Nom et adresse du Syndic", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Liste des autres biens", + office: offices[0], + private_description: " ", public_description: - "Document officiel qui mesure la superficie d'un lot ou d'un bien immobilier, conformément à la loi Carrez qui encadre les transactions immobilières.", + "Exemple: PEE, PER, parts de société, bijoux de valeur et oeuvres d'art, fonds de commerce, fonds artisanal, entreprise commerciale, exploitation agricole...", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "CNI", + name: "Caution, Prestation compensatoire, Pension alimentaire", office: offices[0], - private_description: - "Document officiel d'identification délivré par l'État pour prouver l'identité et la nationalité d'une personne.", + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Titre de propriété des biens", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Tableaux d'amortissement des prêts immobiliers", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Cartes grises et cotes ARGUS des véhicules", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Etat des avoirs bancaires", + office: offices[0], + private_description: " ", + public_description: "Joints ou individuels au jour de la séparation", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Avoirs mobiliers", + office: offices[0], + private_description: " ", public_description: - "Document officiel d'identification délivré par l'État pour prouver l'identité et la nationalité d'une personne.", + "arrêtés à la date de la séparation (relevés de comptes épargne entreprise, épargne retraite, assurance-vie...)", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Modifications règlement copropriété (plusieurs)", + name: "Livret de famille", office: offices[0], - private_description: - "Documents légaux qui apportent des changements ou des ajustements aux règles et dispositions du règlement de copropriété initial.", - public_description: - "Documents légaux qui apportent des changements ou des ajustements aux règles et dispositions du règlement de copropriété initial.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Avis de décès", + name: "Dernières régularisations de charges", office: offices[0], - private_description: - "Notification officielle délivrée par les autorités compétentes pour informer du décès d'une personne.", - public_description: "Notification officielle délivrée par les autorités compétentes pour informer du décès d'une personne.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Lettre de mission", + name: "Diagnostic de Performance Energétique (DPE)", office: offices[0], - private_description: - "Document contractuel qui définit les termes et les objectifs d'une mission confiée à une personne ou à une entreprise.", - public_description: - "Document contractuel qui définit les termes et les objectifs d'une mission confiée à une personne ou à une entreprise.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "DPE", + name: "Avis d'imposition N-1", office: offices[0], - private_description: "Diagnostic de Performance Energétique.", - public_description: "Diagnostic de Performance Energétique.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "RIB", + name: "Avis d'imposition N-2", office: offices[0], - private_description: "Relevé d'identité bancaire ou IBAN.", - public_description: "Relevé d'identité bancaire ou IBAN.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Acte d'achat par la SCI", + name: "Contrat de travail", office: offices[0], - private_description: "Acte d'achat par la SCI.", - public_description: "Acte d'achat par la SCI.", + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, { archived_at: null, - name: "Other", + name: "Trois derniers bulletins de salaire", office: offices[0], - private_description: "Other", - public_description: "Other", + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Bilan comptable", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Trois dernières quittances de loyers ou attestation d'hébergement", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Taxe foncière", + office: offices[0], + private_description: " ", + public_description: " ", + created_at: new Date(), + updated_at: new Date(), + }, + { + archived_at: null, + name: "Justificatif de domicile", + office: offices[0], + private_description: " ", + public_description: " ", created_at: new Date(), updated_at: new Date(), }, @@ -1050,13 +1544,13 @@ export default async function main() { const deedTypes: DeedType[] = [ { - name: "Acte de donation", + name: "Promesse de vente", archived_at: null, - description: "Acte de donation", + description: "Promesse de vente entre deux partis", office: offices[0], created_at: new Date(), updated_at: new Date(), - document_types: documentTypes.slice(0, 4), + document_types: [...documentTypes.slice(0, 31), documentTypes[66]!], }, { name: "Acte de vente", @@ -1065,7 +1559,7 @@ export default async function main() { office: offices[0], created_at: new Date(), updated_at: new Date(), - document_types: documentTypes.slice(0, 4), + document_types: documentTypes.slice(30, 36), }, { name: "Acte de succession", @@ -1074,16 +1568,34 @@ export default async function main() { office: offices[0], created_at: new Date(), updated_at: new Date(), - document_types: documentTypes.slice(0, 4), + document_types: [...documentTypes.slice(36, 56), documentTypes[62]!, documentTypes[30]!], }, { - name: "Acte de vente de maison individuelle", + name: "Acte de divorce", archived_at: null, - description: "Acte de vente de maison individuelle", + description: "Acte de divorce", office: offices[0], created_at: new Date(), updated_at: new Date(), - document_types: documentTypes.slice(0, 4), + document_types: [...documentTypes.slice(57, 62), documentTypes[30]!, documentTypes[0]!], + }, + { + name: "Acte de donation", + archived_at: null, + description: "Acte de donation", + office: offices[0], + created_at: new Date(), + updated_at: new Date(), + document_types: [documentTypes[0]!, documentTypes[62]!, documentTypes[57]!], + }, + { + name: "Bail d'habitation", + archived_at: null, + description: "Bail d'habitation", + office: offices[0], + created_at: new Date(), + updated_at: new Date(), + document_types: [documentTypes[0]!, documentTypes[30]!, documentTypes[57]!, ...documentTypes.slice(62)], }, ]; @@ -1320,6 +1832,7 @@ export default async function main() { data: { name: rule.name, label: rule.label, + namespace: rule.namespace, }, }); rule.uid = ruleCreated.uid; diff --git a/src/common/notifications/NotificationBuilder.ts b/src/common/notifications/NotificationBuilder.ts index 732d1c73..3db177a2 100644 --- a/src/common/notifications/NotificationBuilder.ts +++ b/src/common/notifications/NotificationBuilder.ts @@ -1,10 +1,11 @@ import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; -import { Documents } from "@prisma/client"; +import { Documents, OfficeFolders } from "@prisma/client"; import User, { Document, OfficeFolder, Vote } from "le-coffre-resources/dist/SuperAdmin"; import { Service } from "typedi"; import NotificationsService from "@Services/common/NotificationsService/NotificationsService"; import UsersService from "@Services/super-admin/UsersService/UsersService"; import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; +import { BackendVariables } from "@Common/config/variables/Variables"; @Service() export default class NotificationBuilder { @@ -13,6 +14,7 @@ export default class NotificationBuilder { private documentsService: DocumentsService, private usersService: UsersService, private foldersService: OfficeFoldersService, + private backendVariables: BackendVariables ) {} public async sendDocumentDepositedNotification(documentEntity: Documents) { @@ -32,33 +34,33 @@ export default class NotificationBuilder { " " + document.depositor?.contact?.last_name + " vous a envoyé un document à valider", - redirection_url: "", + redirection_url: `${this.backendVariables.APP_HOST}/folders/${document.folder?.uid}/documents/${document.uid}`, created_at: new Date(), updated_at: new Date(), user: document.folder!.stakeholders || [], }); } - public async sendDocumentAnchoredNotification(documentEntity: Documents) { - const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { - depositor: { include: { contact: true } }, - folder: { include: { folder_anchor: true, office: true, stakeholders: true } }, - }); - if (!documentPrisma) throw new Error("Document not found"); - const document = Document.hydrate(documentPrisma); - if (document.folder?.folder_anchor?.status !== "VERIFIED_ON_CHAIN") return; + public async sendFolderAnchoredNotification(folderEntity: OfficeFolders) { + if(!folderEntity.uid) return; + const officeFolderPrisma = await this.foldersService.getByUid(folderEntity.uid, + { folder_anchor: true, office: true, stakeholders: true } + ); + if (!officeFolderPrisma) throw new Error("Folder not found"); + const folder = OfficeFolder.hydrate(officeFolderPrisma); + if (folder.folder_anchor?.status !== "VERIFIED_ON_CHAIN") return; this.notificationsService.create({ message: "Le dossier " + - document.folder?.folder_number + + folder.folder_number + " - " + - document.folder?.name + + folder.name + " a été certifié. Vous pouvez désormais télécharger le certificat de dépôt pour le mettre dans la GED de votre logiciel de rédaction d'acte.", - redirection_url: "", + redirection_url: `${this.backendVariables.APP_HOST}/folders/${folder?.uid}`, created_at: new Date(), updated_at: new Date(), - user: document.folder!.stakeholders || [], + user: folder.stakeholders || [], }); } @@ -80,7 +82,7 @@ export default class NotificationBuilder { this.notificationsService.create({ message: message, - redirection_url: "", + redirection_url: `${this.backendVariables.APP_HOST}/users/${vote.appointment.targeted_user.uid}`, created_at: new Date(), updated_at: new Date(), user: superAdminList || [], @@ -131,7 +133,7 @@ export default class NotificationBuilder { " avant le " + formattedDate + " (date limite d'expiration des documents).", - redirection_url: "", + redirection_url: `${this.backendVariables.APP_HOST}/folders/${folder.uid}`, created_at: new Date(), updated_at: new Date(), user: folder.stakeholders || [], diff --git a/src/common/repositories/OfficeFolderAnchorsRepository.ts b/src/common/repositories/OfficeFolderAnchorsRepository.ts new file mode 100644 index 00000000..c0687017 --- /dev/null +++ b/src/common/repositories/OfficeFolderAnchorsRepository.ts @@ -0,0 +1,68 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { OfficeFolderAnchors, Prisma } from "@prisma/client"; +import { OfficeFolderAnchor } from "le-coffre-resources/dist/SuperAdmin"; + +@Service() +export default class OfficeFolderAnchorsRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().officeFolderAnchors; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Create new office folder anchor + */ + public async create(officeFolderAnchor: OfficeFolderAnchor): Promise { + const createArgs: Prisma.OfficeFolderAnchorsCreateArgs = { + data: { + hash_sources: officeFolderAnchor.hash_sources, + root_hash: officeFolderAnchor.root_hash!, + + blockchain: officeFolderAnchor.blockchain as OfficeFolderAnchors["blockchain"], + status: officeFolderAnchor.status as OfficeFolderAnchors["status"], + + anchor_nb_try: officeFolderAnchor.anchor_nb_try, + tx_id: officeFolderAnchor.tx_id, + tx_link: officeFolderAnchor.tx_link, + tx_hash: officeFolderAnchor.tx_hash, + + anchored_at: officeFolderAnchor.anchored_at, + }, + }; + + return this.model.create({ ...createArgs }); + } + + /** + * @description : Update data of an office folder anchor + */ + public async update(officeFolderAnchorUid: string, officeFolderAnchor: OfficeFolderAnchor): Promise { + const updateArgs: Prisma.OfficeFolderAnchorsUpdateArgs = { + where: { + uid: officeFolderAnchorUid, + }, + data: { + blockchain: officeFolderAnchor.blockchain as OfficeFolderAnchors["blockchain"], + status: officeFolderAnchor.status as OfficeFolderAnchors["status"], + + anchor_nb_try: officeFolderAnchor.anchor_nb_try, + tx_id: officeFolderAnchor.tx_id, + tx_link: officeFolderAnchor.tx_link, + tx_hash: officeFolderAnchor.tx_hash, + + anchored_at: officeFolderAnchor.anchored_at, + }, + }; + + return this.model.update({ + ...updateArgs, + }); + } +} diff --git a/src/common/repositories/OfficeFoldersRepository.ts b/src/common/repositories/OfficeFoldersRepository.ts index d391ef92..5d591906 100644 --- a/src/common/repositories/OfficeFoldersRepository.ts +++ b/src/common/repositories/OfficeFoldersRepository.ts @@ -84,6 +84,7 @@ export default class OfficeFoldersRepository extends BaseRepository { uid: document.uid!, })), }, + folder_anchor_uid: officeFolder.folder_anchor?.uid, }, }; @@ -93,6 +94,7 @@ export default class OfficeFoldersRepository extends BaseRepository { stakeholders: true, customers: true, documents: true, + folder_anchor: true, }, }); } @@ -109,6 +111,20 @@ export default class OfficeFoldersRepository extends BaseRepository { }); } + /** + * @description : Find one office folder + */ + public async findOneByUidWithCustomers(uid: string) { + return this.model.findUnique({ + where: { + uid: uid, + }, + include: { + customers: true, + } + }); + } + /** * @description : Find one office folder */ diff --git a/src/common/repositories/RulesRepository.ts b/src/common/repositories/RulesRepository.ts index 281e505b..aa44b819 100644 --- a/src/common/repositories/RulesRepository.ts +++ b/src/common/repositories/RulesRepository.ts @@ -31,7 +31,8 @@ export default class RulesRepository extends BaseRepository { const createArgs: Prisma.RulesCreateArgs = { data: { name: rule.name, - label: rule.label + label: rule.label, + namespace: rule.namespace, }, }; @@ -48,7 +49,7 @@ export default class RulesRepository extends BaseRepository { }, data: { name: rule.name, - label: rule.label + label: rule.label, }, }; diff --git a/src/common/system/controller-pattern/BaseController.ts b/src/common/system/controller-pattern/BaseController.ts index 39bd4be7..7baa9c02 100644 --- a/src/common/system/controller-pattern/BaseController.ts +++ b/src/common/system/controller-pattern/BaseController.ts @@ -40,6 +40,10 @@ export default abstract class BaseController { return this.httpResponse(response, HttpCodes.NOT_IMPLEMENTED, responseData); } + protected httpForbidden(response: Response, responseData: IResponseData = "Forbidden") { + return this.httpResponse(response, HttpCodes.FORBIDDEN, responseData); + } + protected httpResponse(response: Response, httpCode: HttpCodes, responseData: IResponseData = {}) { if (responseData instanceof Error) { throw responseData; diff --git a/src/common/system/controller-pattern/HttpCodes.ts b/src/common/system/controller-pattern/HttpCodes.ts index 648c30b1..95c4a67d 100644 --- a/src/common/system/controller-pattern/HttpCodes.ts +++ b/src/common/system/controller-pattern/HttpCodes.ts @@ -8,5 +8,6 @@ enum HttpCodes { NOT_IMPLEMENTED = 501, NOT_FOUND = 404, UNAUTHORIZED = 401, + FORBIDDEN = 403, } export default HttpCodes; diff --git a/src/services/common/AnchoringProofService/AnchoringProofService.ts b/src/services/common/AnchoringProofService/AnchoringProofService.ts index 82c13dcd..45964213 100644 --- a/src/services/common/AnchoringProofService/AnchoringProofService.ts +++ b/src/services/common/AnchoringProofService/AnchoringProofService.ts @@ -53,7 +53,7 @@ export default class AnchoringProofService extends BaseService { [[ANCHORING_TIME]] Certificat de dépôt international Hash : - b834ce9229ee2c2283c837685772a473 + [[ROOT_HASH]] Déposant(s) Auteur : @@ -62,7 +62,7 @@ export default class AnchoringProofService extends BaseService { Smart-Chain Explorateur blockchain - https://tzstats.com/opYWLHH96gbV8HPajRqmoRx3UBVbr6iXz43kuHqm8ey4LLPWqeC + [[TX_LINK]] `; @@ -73,6 +73,7 @@ export default class AnchoringProofService extends BaseService { public async generate(data: AnchoringProofData): Promise { const browser = await puppeteer.launch({ headless: "new", + executablePath: process.env['PUPPETEER_EXECUTABLE_PATH'], args: ["--no-sandbox", "--disable-setuid-sandbox"], }); const page = await browser.newPage(); @@ -85,7 +86,10 @@ export default class AnchoringProofService extends BaseService { `; - htmlContent = htmlContent.replace("[[ANCHORING_TIME]]", data.anchoringTime); + htmlContent = htmlContent + .replace("[[ROOT_HASH]]", data.rootHash) + .replace("[[ANCHORING_TIME]]", data.anchoringTime) + .replace(/\[\[TX_LINK\]\]/g, data.txLink); await page.setContent(htmlContent); await page.addStyleTag({ diff --git a/src/services/common/ContactService.ts b/src/services/common/ContactService.ts deleted file mode 100644 index e1cc6c19..00000000 --- a/src/services/common/ContactService.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Contacts, Customers } from "@prisma/client"; -import BaseService from "@Services/BaseService"; -import { Service } from "typedi"; -import ContactRepository from "@Repositories/ContactRepository"; - -@Service() -export default class DocumentsService extends BaseService { - constructor(private contactRepository: ContactRepository) { - super(); - } - - /** - * @description : Get a contact by email - * @throws {Error} If contact cannot be get by email - */ - public async getByEmail(email: string): Promise<(Contacts & {customers: Customers | null}) | null> { - return this.contactRepository.findOneByEmail(email); - } -} diff --git a/src/services/common/Id360Service/Id360Service.ts b/src/services/common/Id360Service/Id360Service.ts index 531bd1e0..0271396d 100644 --- a/src/services/common/Id360Service/Id360Service.ts +++ b/src/services/common/Id360Service/Id360Service.ts @@ -110,7 +110,6 @@ export default class Id360Service extends BaseService { ); const resJson = (await res.json()) as EnrollmentResponse; - console.log(resJson.id); return { franceConnectUrl: `${this.variables.DOCAPOST_BASE_URL}static/process_ui/index.html#/enrollment/${resJson.api_key}`, processId: resJson.id, @@ -139,10 +138,8 @@ export default class Id360Service extends BaseService { ); const resJson = (await res.json()) as EnrollmentResponse; - console.log(resJson); const route = await this.getRouteId(resJson.api_key); await this.selectRoute(resJson.api_key, route); - console.log(route); await this.uploadDocument(resJson.api_key, documentUid); return await this.getReport(resJson.id); diff --git a/src/services/common/IdNotService/IdNotService.ts b/src/services/common/IdNotService/IdNotService.ts index 87d6c9cc..7b403836 100644 --- a/src/services/common/IdNotService/IdNotService.ts +++ b/src/services/common/IdNotService/IdNotService.ts @@ -33,7 +33,7 @@ interface IRattachementData { name: string; }; locationsUrl: string; - } + }; personne: { numeroTelephonePro: string; prenom: string; @@ -67,7 +67,7 @@ interface IOfficeData { }; typeEntite: { name: string; - } + }; } interface IOfficeLocation { @@ -124,7 +124,7 @@ export default class IdNotService extends BaseService { const token = await fetch(this.variables.IDNOT_BASE_URL + this.variables.IDNOT_CONNEXION_URL + "?" + query, { method: "POST" }); const decodedToken = (await token.json()) as IIdNotToken; const decodedIdToken = jwt.decode(decodedToken.id_token) as IdNotJwtPayload; - + return decodedIdToken; } @@ -152,19 +152,19 @@ export default class IdNotService extends BaseService { public async getOfficeRole(roleName: string, officeUid: string) { switch (roleName) { case EIdnotRole.NOTAIRE_TITULAIRE: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Notaire" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Notaire" }, { office_uid: officeUid }] } }))[0]!; case EIdnotRole.NOTAIRE_ASSOCIE: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Notaire" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Notaire" }, { office_uid: officeUid }] } }))[0]!; case EIdnotRole.NOTAIRE_SALARIE: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Notaire" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Notaire" }, { office_uid: officeUid }] } }))[0]!; case EIdnotRole.COLLABORATEUR: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Collaborateur" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!; case EIdnotRole.SUPPLEANT: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Collaborateur" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!; case EIdnotRole.ADMINISTRATEUR: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Collaborateur" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!; case EIdnotRole.CURATEUR: - return (await this.officeRolesService.get({ where: {AND:[{ name: "Collaborateur" }, {office_uid: officeUid}]}}))[0]!; + return (await this.officeRolesService.get({ where: { AND: [{ name: "Collaborateur" }, { office_uid: officeUid }] } }))[0]!; default: return; } @@ -193,39 +193,37 @@ export default class IdNotService extends BaseService { const searchParams = new URLSearchParams({ key: this.variables.IDNOT_API_KEY, }); - let userData = await (await fetch( - `${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${user.idNot}_${user.office_membership!.idNot}?` + - searchParams, - { - method: "GET", - }, - )).json() as IRattachementData; - - if (!userData.statutDuRattachement) { - const rattachements = await (await fetch( - `${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/personnes/${user.idNot}/rattachements?` + + let userData = (await ( + await fetch( + `${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${user.idNot}_${user.office_membership!.idNot}?` + searchParams, { method: "GET", }, - )).json() as any; + ) + ).json()) as IRattachementData; + + if (!userData.statutDuRattachement) { + const rattachements = (await ( + await fetch(`${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/personnes/${user.idNot}/rattachements?` + searchParams, { + method: "GET", + }) + ).json()) as any; if (rattachements.totalResultCount === 0) { await this.userService.updateCheckedAt(user.uid!); //await this.userService.delete(user.uid!); return; } const rattachementsResults = rattachements.result as IRattachementData[]; - if(!rattachementsResults) return; + if (!rattachementsResults) return; rattachementsResults.forEach(async (rattachement) => { if (rattachement.statutDuRattachement) { - const officeData = await (await fetch( - `${this.variables.IDNOT_API_BASE_URL + rattachement.entiteUrl}?` + - searchParams, - { + const officeData = (await ( + await fetch(`${this.variables.IDNOT_API_BASE_URL + rattachement.entiteUrl}?` + searchParams, { method: "GET", - }, - )).json() as IOfficeData; - if(officeData.typeEntite.name === "office") { + }) + ).json()) as IOfficeData; + if (officeData.typeEntite.name === "office") { userData = rattachement; } } @@ -236,7 +234,7 @@ export default class IdNotService extends BaseService { if (user.office_membership!.idNot !== userData.entite.ou) { updates++; - let officeData = (await this.officeService.get({ where: { idNot:userData.entite.ou } }))[0]; + let officeData = (await this.officeService.get({ where: { idNot: userData.entite.ou } }))[0]; if (!officeData) { const officeLocationData = (await ( await fetch(`${this.variables.IDNOT_API_BASE_URL + userData.entite.locationsUrl}?` + searchParams, { method: "GET" }) @@ -248,7 +246,7 @@ export default class IdNotService extends BaseService { office_status: this.getOfficeStatus(userData.entite.statutEntite.name), address: { address: officeLocationData.result[0]!.adrGeo4, - city: officeLocationData.result[0]!.adrGeoVille.split(" ")[0] ?? officeLocationData.result[0]!.adrGeoVille, + city: officeLocationData.result[0]!.adrGeoVille.split(" ")[0] ?? officeLocationData.result[0]!.adrGeoVille, zip_code: Number(officeLocationData.result[0]!.adrGeoCodePostal), created_at: null, updated_at: null, @@ -279,13 +277,9 @@ export default class IdNotService extends BaseService { const searchParams = new URLSearchParams({ key: this.variables.IDNOT_API_KEY, }); - const officeRawData = await fetch( - `${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/entities/${office.idNot}?` + - searchParams, - { - method: "GET", - }, - ); + const officeRawData = await fetch(`${this.variables.IDNOT_API_BASE_URL}/api/pp/v2/entities/${office.idNot}?` + searchParams, { + method: "GET", + }); if (officeRawData.status === 404) { await this.officeService.updateCheckedAt(office.uid!); //await this.officeService.delete(office.uid!); @@ -293,15 +287,15 @@ export default class IdNotService extends BaseService { } const officeData = (await officeRawData.json()) as IOfficeData; let updates = 0; - if(office.name !== officeData.denominationSociale) { + if (office.name !== officeData.denominationSociale) { updates++; office.name = officeData.denominationSociale; } - if(office.office_status !== this.getOfficeStatus(officeData.statutEntite.name)) { + if (office.office_status !== this.getOfficeStatus(officeData.statutEntite.name)) { updates++; office.office_status = this.getOfficeStatus(officeData.statutEntite.name); } - if(updates != 0) await this.officeService.update(office.uid!, office); + if (updates != 0) await this.officeService.update(office.uid!, office); await this.officeService.updateCheckedAt(office.uid!); } @@ -318,14 +312,15 @@ export default class IdNotService extends BaseService { }) ).json()) as IRattachementData; - - if(!userData.statutDuRattachement || userData.entite.typeEntite.name !== "office") { + if (!userData.statutDuRattachement || userData.entite.typeEntite.name !== "office") { return null; } const officeLocationData = (await ( await fetch(`${this.variables.IDNOT_API_BASE_URL + userData.entite.locationsUrl}?` + searchParams, { method: "GET" }) ).json()) as IOfficeLocation; + + const office = await this.officeService.get({ where: { idNot: decodedToken.entity_idn } }); // if(officeLocationData.result[0]!.adrGeoCodePostal.slice(0,2) !== "35") { // return null; @@ -342,7 +337,7 @@ export default class IdNotService extends BaseService { office_status: this.getOfficeStatus(userData.entite.statutEntite.name), address: { address: officeLocationData.result[0]!.adrGeo4, - city: officeLocationData.result[0]!.adrGeoVille.split(" ")[0] ?? officeLocationData.result[0]!.adrGeoVille, //officeLocationData.result[0]!.adrPostaleVille, + city: officeLocationData.result[0]!.adrGeoVille.split(" ")[0] ?? officeLocationData.result[0]!.adrGeoVille, //officeLocationData.result[0]!.adrPostaleVille, zip_code: Number(officeLocationData.result[0]!.adrGeoCodePostal), created_at: null, updated_at: null, @@ -362,34 +357,40 @@ export default class IdNotService extends BaseService { updated_at: null, }, }; + let userHydrated = User.hydrate(userToAdd); const user = await this.userService.create(userHydrated); + const userOffice = await this.officeService.getByUid(user.office_uid); userHydrated = User.hydrate(user); + const userOfficeHydrated = Office.hydrate(userOffice!); - const officeRoles = await this.officeRolesService.get({ where: { office: { idNot: "0000" }}, include: { office: true, rules: true } }); - const documentTypes = await this.documentTypesService.get({ where: { office: { idNot: "0000" }}, include: { office: true } }); - const deedTypes = await this.deedTypesService.get({ where:{ office: { idNot: "0000" }}, include: { office: true, document_types: true } }); - - const officeRolesHydrated = OfficeRole.hydrateArray(officeRoles); - const documentTypesHydrated = DocumentType.hydrateArray(documentTypes); - const deedTypesHydrated = DeedType.hydrateArray(deedTypes); - - officeRolesHydrated.forEach(async (officeRole) => { - officeRole.office.uid = user.office_uid; - await this.officeRolesService.create(officeRole); - }); - documentTypesHydrated.forEach(async (documentType) => { - documentType.office!.uid = user.office_uid; - await this.documentTypesService.create(documentType); - }); - deedTypesHydrated.forEach(async (deedType) => { - deedType.office!.uid = user.office_uid; - await this.deedTypesService.create(deedType); - }); - + if(office.length === 0) { + const officeRoles = await this.officeRolesService.get({ + where: { office: { idNot: "0000" } }, + include: { office: true, rules: true }, + }); + const deedTypes = await this.deedTypesService.get({ + where: { office: { idNot: "0000" } }, + include: { office: true, document_types: { include: { office: true } } }, + }); + const documentTypes = await this.documentTypesService.get({ + where: { office: { idNot: "0000" } }, + include: { office: true }, + }); + + const officeRolesHydrated = OfficeRole.hydrateArray(officeRoles); + const deedTypesHydrated = DeedType.hydrateArray(deedTypes); + const documentTypesHydrated = DocumentType.hydrateArray(documentTypes); + + + await this.duplicateOfficeRoles(officeRolesHydrated, userOfficeHydrated); + const documentTypesCreated = await this.duplicateDocumentTypes(documentTypesHydrated, userOfficeHydrated); + await this.duplicateDeedTypes(deedTypesHydrated, documentTypesCreated, userOfficeHydrated); + } + const officeRole = await this.getOfficeRole(userData.typeLien.name, user.office_uid); - if(officeRole) { + if (officeRole) { const officeRoleHydrated = OfficeRole.hydrate(officeRole!); userHydrated.office_role = officeRoleHydrated; await this.userService.update(user.uid, userHydrated); @@ -400,12 +401,44 @@ export default class IdNotService extends BaseService { return user; } + public async duplicateDocumentTypes(documentTypes: DocumentType[], office: Office): Promise { + let newDocumentTypes: DocumentType[] = []; + for(const documentType of documentTypes) { + documentType.office = office; + const documentTypeCreated = await this.documentTypesService.create(documentType); + newDocumentTypes.push(DocumentType.hydrate(documentTypeCreated)); + }; + return newDocumentTypes; + } + + public async duplicateDeedTypes(deedTypes: DeedType[], documentTypes: DocumentType[], office: Office) { + for (const deedType of deedTypes) { + let newDocumentTypes: DocumentType[] = []; + for (const document of deedType.document_types!) { + const newDocumentType = documentTypes.find((documentType) => documentType.name === document.name); + if(!newDocumentType) continue; + newDocumentTypes.push(newDocumentType!); + }; + deedType.document_types = newDocumentTypes; + deedType.office = office; + await this.deedTypesService.create(deedType); + }; + } + + public async duplicateOfficeRoles(officeRoles: OfficeRole[], office: Office){ + for(const officeRole of officeRoles) { + officeRole.office = office; + await this.officeRolesService.create(officeRole); + }; + } + + + public async updateUsers() { const usersReq = await this.userService.getUsersToBeChecked(); const users = User.hydrateArray(usersReq); users.forEach(async (user) => { await this.updateUser(user.uid!); - }); } diff --git a/src/services/customer/CustomersService/CustomersService.ts b/src/services/customer/CustomersService/CustomersService.ts index 68c9888e..8ec5f672 100644 --- a/src/services/customer/CustomersService/CustomersService.ts +++ b/src/services/customer/CustomersService/CustomersService.ts @@ -1,12 +1,11 @@ import { Customers, Prisma } from "@prisma/client"; import CustomersRepository from "@Repositories/CustomersRepository"; -import ContactRepository from "@Repositories/ContactRepository"; import BaseService from "@Services/BaseService"; import { Service } from "typedi"; @Service() export default class CustomersService extends BaseService { - constructor(private customerRepository: CustomersRepository, private contactRepository: ContactRepository) { + constructor(private customerRepository: CustomersRepository) { super(); } @@ -17,30 +16,4 @@ export default class CustomersService extends BaseService { public async get(query: Prisma.CustomersFindManyArgs): Promise { return this.customerRepository.findMany(query); } - - /** - * @description : Get a customer by uid - * @throws {Error} If customer cannot be get by uid - */ - public async getByUid(uid: string, query?: Prisma.CustomersInclude): Promise { - return this.customerRepository.findOneByUid(uid, query); - } - - /** - * @description : Get a customer by contact uid - * @throws {Error} If customer cannot be get by contact uid - */ - public async getByContact(contactUid: string): Promise { - return this.customerRepository.findOneByContact(contactUid); - } - - /** - * @description : Get a customer by contact uid - * @throws {Error} If customer cannot be get by contact uid - */ - public async getByEmail(contactUid: string) { - return this.contactRepository.findOneByEmail(contactUid); - } - - -} +} \ No newline at end of file diff --git a/src/services/customer/DocumentsService/DocumentsService.ts b/src/services/customer/DocumentsService/DocumentsService.ts index fb6d925c..b162f5dc 100644 --- a/src/services/customer/DocumentsService/DocumentsService.ts +++ b/src/services/customer/DocumentsService/DocumentsService.ts @@ -24,9 +24,9 @@ export default class DocumentsService extends BaseService { * @throws {Error} If document cannot be created */ public async create(document: Document): Promise { - const otherDocumentType = await this.documentTypeService.get({ where: { name: "Other" } }); + const otherDocumentType = await this.documentTypeService.get({ where: { name: "Autres documents" } }); - if(otherDocumentType.length < 1) throw new Error("Other document type not found"); + if(otherDocumentType.length < 1) throw new Error("Autres documents document type not found"); document.document_type = otherDocumentType[0]; document.document_status = "DEPOSITED"; diff --git a/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts b/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts index 6afdede7..5095585a 100644 --- a/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/customer/OfficeFoldersService/OfficeFoldersService.ts @@ -26,4 +26,14 @@ export default class OfficeFoldersService extends BaseService { public async getByUid(uid: string, query?: Prisma.OfficeFoldersInclude) { return this.officeFoldersRepository.findOneByUid(uid, query); } + + /** + * @description : Get a folder by uid + * @throws {Error} If folder cannot be get by uid + */ + public async getByUidWithCustomers(uid: string) { + return this.officeFoldersRepository.findOneByUidWithCustomers(uid); + } + + } diff --git a/src/services/notary/CustomersService/CustomersService.ts b/src/services/notary/CustomersService/CustomersService.ts index 72e6923d..3202d143 100644 --- a/src/services/notary/CustomersService/CustomersService.ts +++ b/src/services/notary/CustomersService/CustomersService.ts @@ -23,6 +23,14 @@ export default class CustomersService extends BaseService { * @throws {Error} If customer cannot be created */ public async create(customerEntity: Customer): Promise { + const customers = await this.get({ + where: { + contact: { + OR: [{ email: customerEntity.contact?.email }, { cell_phone_number: customerEntity.contact?.cell_phone_number }], + }, + }, + }); + if(customers[0]) return customers[0]; return this.customerRepository.create(customerEntity); }