From 819b554b64e50fbfbc873e44e6165035b70f1626 Mon Sep 17 00:00:00 2001 From: OxSaitama Date: Thu, 12 Oct 2023 19:45:26 +0200 Subject: [PATCH] add validation errors --- package.json | 2 +- src/app/api/admin/DeedTypesController.ts | 5 -- src/app/api/admin/OfficeFoldersController.ts | 44 +++++++++------ src/app/api/notary/DocumentTypesController.ts | 11 ++-- src/app/api/notary/OfficeFoldersController.ts | 56 ++++++++++--------- .../super-admin/OfficeFoldersController.ts | 38 ++++++++----- .../DeedTypeHandler.ts | 12 ++++ .../DocumentTypeHandler.ts | 12 ++++ .../OfficeMembershipHandlers/FolderHandler.ts | 31 +++++----- .../repositories/OfficeFoldersRepository.ts | 10 +++- .../OfficeFoldersService.ts | 9 --- .../OfficeFoldersService.ts | 9 --- .../OfficeFoldersService.ts | 9 --- .../super-admin/OfficeFolderService.test.ts | 6 +- 14 files changed, 139 insertions(+), 115 deletions(-) diff --git a/package.json b/package.json index c0ec46b8..d1529382 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "express": "^4.18.2", "fp-ts": "^2.16.1", "jsonwebtoken": "^9.0.0", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.90", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.92", "module-alias": "^2.2.2", "monocle-ts": "^2.3.13", "multer": "^1.4.5-lts.1", diff --git a/src/app/api/admin/DeedTypesController.ts b/src/app/api/admin/DeedTypesController.ts index d1273879..3963128e 100644 --- a/src/app/api/admin/DeedTypesController.ts +++ b/src/app/api/admin/DeedTypesController.ts @@ -74,11 +74,6 @@ export default class DeedTypesController extends ApiController { //validate deed type await validateOrReject(deedTypeEntity, { groups: ["createDeedType"], forbidUnknownValues: false }); - const doesExist = await this.deedTypesService.get({ where: { name: deedTypeEntity.name } }); - if (doesExist.length > 0) { - this.httpBadRequest(response, "Deed type name already used"); - return; - } //call service to get prisma entity const deedTypeEntityCreated = await this.deedTypesService.create(deedTypeEntity); diff --git a/src/app/api/admin/OfficeFoldersController.ts b/src/app/api/admin/OfficeFoldersController.ts index bf1c8732..2284ae19 100644 --- a/src/app/api/admin/OfficeFoldersController.ts +++ b/src/app/api/admin/OfficeFoldersController.ts @@ -62,7 +62,7 @@ export default class OfficeFoldersController extends ApiController { if (query.where?.stakeholders) delete query.where.stakeholders; const officeFoldersWhereInput: Prisma.OfficeFoldersWhereInput = { ...query.where, stakeholders: { some: { uid: userId } } }; query.where = officeFoldersWhereInput; - + //call service to get prisma entity const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); @@ -89,13 +89,18 @@ export default class OfficeFoldersController extends ApiController { await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { - strategy: "excludeAll", - }); - //success - this.httpCreated(response, officeFolders); + try { + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -120,7 +125,7 @@ export default class OfficeFoldersController extends ApiController { this.httpNotFoundRequest(response, "office folder not found"); return; } - + //init OfficeFolder resource with request body values const officeFolderEntity = OfficeFolder.hydrate(req.body); @@ -128,15 +133,20 @@ export default class OfficeFoldersController extends ApiController { await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + try { + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { - strategy: "excludeAll", - }); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); - //success - this.httpSuccess(response, officeFolders); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -160,7 +170,7 @@ export default class OfficeFoldersController extends ApiController { if (req.query["q"]) { query = JSON.parse(req.query["q"] as string); } - + const officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); if (!officeFolderEntity) { diff --git a/src/app/api/notary/DocumentTypesController.ts b/src/app/api/notary/DocumentTypesController.ts index 6a1a81bd..8071a296 100644 --- a/src/app/api/notary/DocumentTypesController.ts +++ b/src/app/api/notary/DocumentTypesController.ts @@ -4,7 +4,6 @@ import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; import DocumentTypesService from "@Services/notary/DocumentTypesService/DocumentTypesService"; import { DocumentTypes, Prisma } from "@prisma/client"; -import ObjectHydrate from "@Common/helpers/ObjectHydrate"; import { DocumentType } from "le-coffre-resources/dist/Notary"; import { validateOrReject } from "class-validator"; import authHandler from "@App/middlewares/AuthHandler"; @@ -133,11 +132,15 @@ export default class DocumentTypesController extends ApiController { const documentTypeEntity = await this.documentTypesService.getByUid(uid, query); - //Hydrate ressource with prisma entity - const user = ObjectHydrate.hydrate(new DocumentType(), documentTypeEntity!, { strategy: "excludeAll" }); + if (!documentTypeEntity) { + this.httpNotFoundRequest(response, "document type not found"); + return; + } + + const documentType = DocumentType.hydrate(documentTypeEntity, { strategy: "excludeAll" }); //success - this.httpSuccess(response, user); + this.httpSuccess(response, documentType); } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/notary/OfficeFoldersController.ts b/src/app/api/notary/OfficeFoldersController.ts index d5a5b115..f8dca5ad 100644 --- a/src/app/api/notary/OfficeFoldersController.ts +++ b/src/app/api/notary/OfficeFoldersController.ts @@ -86,13 +86,18 @@ export default class OfficeFoldersController extends ApiController { await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { - strategy: "excludeAll", - }); - //success - this.httpCreated(response, officeFolders); + try { + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -111,9 +116,7 @@ export default class OfficeFoldersController extends ApiController { return; } - const officeFolderFound = await this.officeFoldersService.getByUid(uid, { - folder_anchor: true, - }); + const officeFolderFound = await this.officeFoldersService.getByUid(uid); if (!officeFolderFound) { this.httpNotFoundRequest(response, "office folder not found"); @@ -121,25 +124,26 @@ export default class OfficeFoldersController extends ApiController { } //init OfficeFolder resource with request body values - const officefolderToUpdate = OfficeFolder.hydrate(req.body); - const officeFolderFoundEntity = OfficeFolder.hydrate(officeFolderFound); - //validate folder - await validateOrReject(officefolderToUpdate, { groups: ["updateFolder"], forbidUnknownValues: false }); + const officeFolderEntity = OfficeFolder.hydrate(req.body); - if (officeFolderFoundEntity.folder_anchor?.status === "VERIFIED_ON_CHAIN") { - this.httpBadRequest(response, "Cannot update a verified folder"); + //validate folder + await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); + + //call service to get prisma entity + try { + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); return; } - //call service to get prisma entity - const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officefolderToUpdate); - - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, officeFolders); } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/super-admin/OfficeFoldersController.ts b/src/app/api/super-admin/OfficeFoldersController.ts index f31d2807..200dc117 100644 --- a/src/app/api/super-admin/OfficeFoldersController.ts +++ b/src/app/api/super-admin/OfficeFoldersController.ts @@ -87,13 +87,18 @@ export default class OfficeFoldersController extends ApiController { await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { - strategy: "excludeAll", - }); - //success - this.httpCreated(response, officeFolders); + try { + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -126,15 +131,20 @@ export default class OfficeFoldersController extends ApiController { await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + try { + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { - strategy: "excludeAll", - }); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); - //success - this.httpSuccess(response, officeFolders); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts index f8b8e104..57066861 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts @@ -11,12 +11,24 @@ export default async function deedTypeHandler(req: Request, response: Response, const uid = req.path && req.path.split("/")[5]; const documentTypes: DocumentType[] = req.body.document_types; const office = req.body.office; + const name = req.body.name; if (office && office.uid != officeId) { response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } + if (name) { + const deedTypeService = Container.get(DeedTypesService); + const deedType = await deedTypeService.get({ + where: { AND: [{ name: { equals: name, mode: "insensitive" } }, { office: { uid: officeId } }] }, + }); + if (deedType[0] && (!uid || deedType[0].uid != uid)) { + response.status(HttpCodes.VALIDATION_ERROR).send([{ property: "name", constraints: { name: "Nom d'acte déjà utilisé" } }]); + return; + } + } + if (uid) { const deedTypeService = Container.get(DeedTypesService); const deedType = await deedTypeService.getByUidWithOffice(uid!); diff --git a/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts index 9c8c8071..e5078ba8 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts @@ -8,12 +8,24 @@ export default async function documentTypeHandler(req: Request, response: Respon const officeId = req.body.user.office_Id; const uid = req.path && req.path.split("/")[5]; const office = req.body.office; + const name = req.body.name; if (office && office.uid != officeId) { response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } + if (name) { + const documentTypeService = Container.get(DocumentTypesService); + const documentType = await documentTypeService.get({ + where: { AND: [{ name: { equals: name, mode: "insensitive" } }, { office: { uid: officeId } }] }, + }); + if (documentType[0] && (!uid || documentType[0].uid != uid)) { + response.status(HttpCodes.VALIDATION_ERROR).send([{ property: "name", constraints: { name: "Nom de document déjà utilisé" } }]); + return; + } + } + if (uid) { const documentTypeService = Container.get(DocumentTypesService); const documentType = await documentTypeService.getByUidWithOffice(uid!); diff --git a/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts index 2019b74a..ae447090 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts @@ -10,14 +10,25 @@ export default async function folderHandler(req: Request, response: Response, ne const userId = req.body.user.userId; let uid = req.path && req.path.split("/")[5]; const office = req.body.office; - const officeFolderNumber = req.body.folder_number; const deed = req.body.deed; + const folderNumber = req.body.folder_number; if (office && office.uid != officeId) { response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } + if(folderNumber) { + const officeFolderService = Container.get(OfficeFoldersService); + const sameFolderNumber = await officeFolderService.get({ + where: { AND: [{ folder_number: folderNumber }, { office_uid: officeId }] }, + }); + if(sameFolderNumber[0] && (!uid || uid != sameFolderNumber[0]?.uid)) { + response.status(HttpCodes.VALIDATION_ERROR).send([{ property: "folder_number", constraints: { folder_number: "Numéro de dossier déjà utilisé" } }]); + return; + } + } + if (deed && deed.deed_type) { const deedTypeService = Container.get(DeedTypesService); const deedTypeWithOffice = await deedTypeService.getByUidWithOffice(deed.deed_type.uid!); @@ -25,20 +36,12 @@ export default async function folderHandler(req: Request, response: Response, ne response.status(HttpCodes.NOT_FOUND).send("Deed type not found"); return; } - if (deedTypeWithOffice.office.uid != officeId) { - response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this deed type"); + if(deedTypeWithOffice.archived_at) { + response.status(HttpCodes.FORBIDDEN).send("Deed type is archived"); return; } - } - - const officeFolderService = Container.get(OfficeFoldersService); - - if (officeFolderNumber && req.method == "POST") { - const officeFoldersWithSameNumber = await officeFolderService.get({ - where: { folder_number: officeFolderNumber, office: { uid: officeId } }, - }); - if (officeFoldersWithSameNumber.length) { - response.status(HttpCodes.BAD_REQUEST).send("Office number already used"); + if (deedTypeWithOffice.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this deed type"); return; } } @@ -47,6 +50,8 @@ export default async function folderHandler(req: Request, response: Response, ne if(uid === "download") { uid = req.path && req.path.split("/")[6]; } + const officeFolderService = Container.get(OfficeFoldersService); + const officeFolder = await officeFolderService.getByUidWithStakeholders(uid!); if (!officeFolder) { diff --git a/src/common/repositories/OfficeFoldersRepository.ts b/src/common/repositories/OfficeFoldersRepository.ts index f918890a..7486b7c7 100644 --- a/src/common/repositories/OfficeFoldersRepository.ts +++ b/src/common/repositories/OfficeFoldersRepository.ts @@ -35,8 +35,12 @@ export default class OfficeFoldersRepository extends BaseRepository { description: officeFolder.description, status: EFolderStatus.LIVE, deed: { - connect: { - uid: officeFolder.deed?.uid, + create: { + deed_type: { + connect: { + uid: officeFolder.deed?.deed_type?.uid, + }, + }, }, }, office: { @@ -121,7 +125,7 @@ export default class OfficeFoldersRepository extends BaseRepository { }, include: { customers: true, - } + }, }); } diff --git a/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts b/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts index 8d474aef..43953660 100644 --- a/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts @@ -3,16 +3,12 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/Admin"; import { Service } from "typedi"; -import DeedTypesService from "../DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, - private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository, ) { super(); } @@ -30,11 +26,6 @@ export default class OfficeFoldersService extends BaseService { * @throws {Error} If folder cannot be created */ public async create(officeFolderEntity: OfficeFolder): Promise { - const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if (!deedType) throw new Error("deed type not found"); - if (deedType.archived_at) throw new Error("deed type is archived"); - const deed = await this.deedRepository.create(officeFolderEntity.deed!); - officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); } diff --git a/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts b/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts index 97fa5680..e2274813 100644 --- a/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts @@ -3,16 +3,12 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { Service } from "typedi"; -import DeedTypesService from "../DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, - private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository, ) { super(); } @@ -30,11 +26,6 @@ export default class OfficeFoldersService extends BaseService { * @throws {Error} If folder cannot be created */ public async create(officeFolderEntity: OfficeFolder): Promise { - const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if (!deedType) throw new Error("deed type not found"); - if (deedType.archived_at) throw new Error("deed type is archived"); - const deed = await this.deedRepository.create(officeFolderEntity.deed!); - officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); } diff --git a/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts b/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts index 73e72808..ead0f2bb 100644 --- a/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts @@ -3,16 +3,12 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; import { Service } from "typedi"; -import DeedTypesService from "../DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, - private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository, ) { super(); } @@ -30,11 +26,6 @@ export default class OfficeFoldersService extends BaseService { * @throws {Error} If folder cannot be created */ public async create(officeFolderEntity: OfficeFolder): Promise { - const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if (!deedType) throw new Error("deed type not found"); - if (deedType.archived_at) throw new Error("deed type is archived"); - const deed = await this.deedRepository.create(officeFolderEntity.deed!); - officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); } diff --git a/src/test/services/super-admin/OfficeFolderService.test.ts b/src/test/services/super-admin/OfficeFolderService.test.ts index 909a6ddd..579d0c7c 100644 --- a/src/test/services/super-admin/OfficeFolderService.test.ts +++ b/src/test/services/super-admin/OfficeFolderService.test.ts @@ -18,15 +18,11 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import OfficeFolderService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; import { initCustomers, initDeedType, initDocumentType, initOffice, initUsers } from "@Test/config/Init"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; -import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; const prisma = new PrismaClient(); const OfficeFolderServiceTest = new OfficeFolderService( - Container.get(OfficeFoldersRepository), - Container.get(DeedTypesService), - Container.get(DeedsRepository), + Container.get(OfficeFoldersRepository) ); beforeAll(async () => {