diff --git a/src/app/api/idnot-user/UserInfoController.ts b/src/app/api/idnot-user/UserInfoController.ts deleted file mode 100644 index afd5bf22..00000000 --- a/src/app/api/idnot-user/UserInfoController.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Response, Request } from "express"; - import { Controller,Post } from "@ControllerPattern/index"; - import ApiController from "@Common/system/controller-pattern/ApiController"; - import { Service } from "typedi"; -import AuthService from "@Services/private-services/AuthService/AuthService"; -//import User from "le-coffre-resources/dist/Notary"; - - @Controller() - @Service() - export default class UserInfoController extends ApiController { - constructor(private authService: AuthService) { - super(); - } - - /** - * @description Get user created from IdNot authentification - * @returns User - */ - @Post("/api/v1/idnot-user/:code") - protected async getUserInfosFromIdnot(req: Request, response: Response) { - try { - const code = req.params["code"]; - const user = await this.authService.getUserFromIdNotTokens(code!); - //success - this.httpSuccess(response, user); - } catch (error) { - this.httpInternalError(response); - return; - } - } - -} \ No newline at end of file diff --git a/src/app/api/idnot/UserController.ts b/src/app/api/idnot/UserController.ts new file mode 100644 index 00000000..ad72402d --- /dev/null +++ b/src/app/api/idnot/UserController.ts @@ -0,0 +1,85 @@ +import { Response, Request } from "express"; +import { Controller, Post } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import { Service } from "typedi"; +import AuthService from "@Services/common/AuthService/AuthService"; +import { JwtPayload } from "jsonwebtoken"; + +@Controller() +@Service() +export default class UserController extends ApiController { + constructor(private authService: AuthService) { + super(); + } + + /** + * @description Get user created from IdNot authentification + * @todo Used for test, should be removed + * @returns User + */ + // @Post("/api/v1/idnot/user/:code") + // protected async getUserInfosFromIdnot(req: Request, response: Response) { + // console.warn("/api/v1/idnot/user/:code used for test, should be removed"); + + // try { + // const code = req.params["code"]; + // const user = await this.authService.getUserFromIdNotTokens(code!); + // //success + // this.httpSuccess(response, user); + // } catch (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.getUserPayload(id!); + const accessToken = this.authService.generateAccessToken(payload); + const refreshToken = this.authService.generateRefreshToken(payload); + + //success + this.httpSuccess(response, { accessToken, refreshToken }); + } catch (error) { + console.log(error) + this.httpInternalError(response); + return; + } + } + + @Post("/api/v1/idnot/user/refresh-token") + protected async refreshToken(req: Request, response: Response) { + try { + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + if (!token) { + this.httpBadRequest(response); + return; + } + + let accessToken; + this.authService.verifyRefreshToken(token, (err, userPayload) => { + if (err) { + this.httpUnauthorized(response); + return; + } + + const user = userPayload as JwtPayload; + delete user.iat; + delete user!.exp; + accessToken = this.authService.generateAccessToken(user); + }); + + //success + this.httpSuccess(response, accessToken); + } catch (error) { + this.httpInternalError(response); + return; + } + } +} diff --git a/src/app/api/super-admin/CustomersController.ts b/src/app/api/super-admin/CustomersController.ts index 6bd28b1e..440de50b 100644 --- a/src/app/api/super-admin/CustomersController.ts +++ b/src/app/api/super-admin/CustomersController.ts @@ -6,6 +6,8 @@ import { Service } from "typedi"; import { Customer } from "le-coffre-resources/dist/SuperAdmin"; import { Customers } from "@prisma/client"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -17,7 +19,7 @@ export default class CustomersController extends ApiController { /** * @description Get all customers */ - @Get("/api/v1/super-admin/customers") + @Get("/api/v1/super-admin/customers", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -40,7 +42,7 @@ export default class CustomersController extends ApiController { /** * @description Create a new customer */ - @Post("/api/v1/super-admin/customers") + @Post("/api/v1/super-admin/customers", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //init IUser resource with request body values @@ -66,7 +68,7 @@ export default class CustomersController extends ApiController { /** * @description Modify a specific customer by uid */ - @Put("/api/v1/super-admin/customers/:uid") + @Put("/api/v1/super-admin/customers/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -107,7 +109,7 @@ export default class CustomersController extends ApiController { /** * @description Get a specific customer by uid */ - @Get("/api/v1/super-admin/customers/:uid") + @Get("/api/v1/super-admin/customers/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/DeedTypesController.ts b/src/app/api/super-admin/DeedTypesController.ts index 5f038ba9..d890bc2c 100644 --- a/src/app/api/super-admin/DeedTypesController.ts +++ b/src/app/api/super-admin/DeedTypesController.ts @@ -6,6 +6,8 @@ import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesSe import { DeedTypes } from "@prisma/client"; import { DeedType } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -18,7 +20,7 @@ export default class DeedTypesController extends ApiController { * @description Get all deedtypes * @returns Deedtype[] list of deedtypes */ - @Get("/api/v1/super-admin/deed-types") + @Get("/api/v1/super-admin/deed-types", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -41,7 +43,7 @@ export default class DeedTypesController extends ApiController { * @description Create a new deedtype * @returns Deedtype created */ - @Post("/api/v1/super-admin/deed-types") + @Post("/api/v1/super-admin/deed-types", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //init DeedType resource with request body values @@ -70,7 +72,7 @@ export default class DeedTypesController extends ApiController { * @description Modify a specific deedtype by uid * @returns Deedtype modified */ - @Put("/api/v1/super-admin/deed-types/:uid") + @Put("/api/v1/super-admin/deed-types/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -112,7 +114,7 @@ export default class DeedTypesController extends ApiController { * @description Get a specific deedtype by uid * @returns IDeedtype */ - @Get("/api/v1/super-admin/deed-types/:uid") + @Get("/api/v1/super-admin/deed-types/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/DeedsController.ts b/src/app/api/super-admin/DeedsController.ts index 3f4d3c62..2dd94592 100644 --- a/src/app/api/super-admin/DeedsController.ts +++ b/src/app/api/super-admin/DeedsController.ts @@ -6,6 +6,8 @@ import { Service } from "typedi"; import { Deeds } from "@prisma/client"; import { Deed } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -18,7 +20,7 @@ export default class DeedsController extends ApiController { * @description Get all deeds * @returns Deed[] list of deeds */ - @Get("/api/v1/super-admin/deeds") + @Get("/api/v1/super-admin/deeds", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -41,7 +43,7 @@ export default class DeedsController extends ApiController { * @description Get a specific deed by uid * @returns Deed */ - @Get("/api/v1/super-admin/deeds/:uid") + @Get("/api/v1/super-admin/deeds/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -79,7 +81,7 @@ export default class DeedsController extends ApiController { /** * @description Modify a specific deed by uid */ - @Put("/api/v1/super-admin/deeds/:uid") + @Put("/api/v1/super-admin/deeds/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/DocumentTypesController.ts b/src/app/api/super-admin/DocumentTypesController.ts index ecd89e14..99cef9ac 100644 --- a/src/app/api/super-admin/DocumentTypesController.ts +++ b/src/app/api/super-admin/DocumentTypesController.ts @@ -7,6 +7,8 @@ import { DocumentTypes } from "@prisma/client"; import ObjectHydrate from "@Common/helpers/ObjectHydrate"; import { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -18,7 +20,7 @@ export default class DocumentTypesController extends ApiController { /** * @description Get all document-types */ - @Get("/api/v1/super-admin/document-types") + @Get("/api/v1/super-admin/document-types", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -43,7 +45,7 @@ export default class DocumentTypesController extends ApiController { /** * @description Create a new documentType */ - @Post("/api/v1/super-admin/document-types") + @Post("/api/v1/super-admin/document-types", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //init DocumentType resource with request body values @@ -67,7 +69,7 @@ export default class DocumentTypesController extends ApiController { /** * @description Modify a specific documentType by uid */ - @Put("/api/v1/super-admin/document-types/:uid") + @Put("/api/v1/super-admin/document-types/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -107,7 +109,7 @@ export default class DocumentTypesController extends ApiController { /** * @description Get a specific documentType by uid */ - @Get("/api/v1/super-admin/document-types/:uid") + @Get("/api/v1/super-admin/document-types/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/DocumentsController.ts b/src/app/api/super-admin/DocumentsController.ts index 009d33ca..cfc5bb2f 100644 --- a/src/app/api/super-admin/DocumentsController.ts +++ b/src/app/api/super-admin/DocumentsController.ts @@ -6,6 +6,8 @@ import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsSe import { Documents } from "@prisma/client"; import { Document } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -18,7 +20,7 @@ export default class DocumentsController extends ApiController { * @description Get all documents * @returns IDocument[] list of documents */ - @Get("/api/v1/super-admin/documents") + @Get("/api/v1/super-admin/documents", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -42,7 +44,7 @@ export default class DocumentsController extends ApiController { * @description Create a new document * @returns IDocument created */ - @Post("/api/v1/super-admin/documents") + @Post("/api/v1/super-admin/documents", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //init Document resource with request body values @@ -70,7 +72,7 @@ export default class DocumentsController extends ApiController { /** * @description Update a specific document */ - @Put("/api/v1/super-admin/documents/:uid") + @Put("/api/v1/super-admin/documents/:uid", [authHandler,ruleHandler]) protected async update(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -109,7 +111,7 @@ export default class DocumentsController extends ApiController { /** * @description Delete a specific document */ - @Delete("/api/v1/super-admin/documents/:uid") + @Delete("/api/v1/super-admin/documents/:uid", [authHandler,ruleHandler]) protected async delete(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -142,7 +144,7 @@ export default class DocumentsController extends ApiController { /** * @description Get a specific document by uid */ - @Get("/api/v1/super-admin/documents/:uid") + @Get("/api/v1/super-admin/documents/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/FilesController.ts b/src/app/api/super-admin/FilesController.ts index 3bfd52da..465e684f 100644 --- a/src/app/api/super-admin/FilesController.ts +++ b/src/app/api/super-admin/FilesController.ts @@ -2,11 +2,13 @@ import { Response, Request } from "express"; import { Controller, Delete, Get, Post, Put } from "@ControllerPattern/index"; import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; -import FilesService from "@Services/private-services/FilesService/FilesService"; +import FilesService from "@Services/common/FilesService/FilesService"; import { Files } from "@prisma/client"; import { File } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -19,7 +21,7 @@ export default class FilesController extends ApiController { * @description Get all Files * @returns File[] list of Files */ - @Get("/api/v1/super-admin/files") + @Get("/api/v1/super-admin/files", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -42,7 +44,7 @@ export default class FilesController extends ApiController { /** * @description Get a specific File by uid */ - @Get("/api/v1/super-admin/files/download/:uid") + @Get("/api/v1/super-admin/files/download/:uid", [authHandler,ruleHandler]) protected async download(req: Request, response: Response) { const uid = req.params["uid"]; if (!uid) { @@ -71,7 +73,7 @@ export default class FilesController extends ApiController { * @description Create a new File * @returns File created */ - @Post("/api/v1/super-admin/files") + @Post("/api/v1/super-admin/files", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //get file @@ -112,7 +114,7 @@ export default class FilesController extends ApiController { /** * @description Update a specific file */ - @Put("/api/v1/super-admin/files/:uid") + @Put("/api/v1/super-admin/files/:uid", [authHandler,ruleHandler]) protected async update(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -150,7 +152,7 @@ export default class FilesController extends ApiController { /** * @description Delete a specific File */ - @Delete("/api/v1/super-admin/files/:uid") + @Delete("/api/v1/super-admin/files/:uid", [authHandler,ruleHandler]) protected async delete(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -188,7 +190,7 @@ export default class FilesController extends ApiController { /** * @description Get a specific File by uid */ - @Get("/api/v1/super-admin/files/:uid") + @Get("/api/v1/super-admin/files/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/OfficeFoldersController.ts b/src/app/api/super-admin/OfficeFoldersController.ts index ed2dbce1..6999e03b 100644 --- a/src/app/api/super-admin/OfficeFoldersController.ts +++ b/src/app/api/super-admin/OfficeFoldersController.ts @@ -6,6 +6,8 @@ import { Service } from "typedi"; import { OfficeFolders } from "@prisma/client"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -17,7 +19,7 @@ export default class OfficeFoldersController extends ApiController { /** * @description Get all folders */ - @Get("/api/v1/super-admin/folders") + @Get("/api/v1/super-admin/folders", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -41,7 +43,7 @@ export default class OfficeFoldersController extends ApiController { /** * @description Create a new folder */ - @Post("/api/v1/super-admin/folders") + @Post("/api/v1/super-admin/folders", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //init OfficeFolder resource with request body values @@ -78,7 +80,7 @@ export default class OfficeFoldersController extends ApiController { /** * @description Modify a specific folder by uid */ - @Put("/api/v1/super-admin/folders/:uid") + @Put("/api/v1/super-admin/folders/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -120,7 +122,7 @@ export default class OfficeFoldersController extends ApiController { * @description Get a specific folder by uid * @returns IFolder */ - @Get("/api/v1/super-admin/folders/:uid") + @Get("/api/v1/super-admin/folders/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -159,7 +161,7 @@ export default class OfficeFoldersController extends ApiController { /** * @description Delete a specific folder */ - @Delete("/api/v1/super-admin/folders/:uid") + @Delete("/api/v1/super-admin/folders/:uid", [authHandler,ruleHandler]) protected async delete(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/OfficesController.ts b/src/app/api/super-admin/OfficesController.ts index 86de50f5..2ec24cc1 100644 --- a/src/app/api/super-admin/OfficesController.ts +++ b/src/app/api/super-admin/OfficesController.ts @@ -6,6 +6,8 @@ import { Service } from "typedi"; import { Offices } from "@prisma/client"; import { Office as OfficeResource } from "le-coffre-resources/dist/SuperAdmin"; import { validateOrReject } from "class-validator"; +import ruleHandler from "@App/middlewares/RulesHandler"; +import authHandler from "@App/middlewares/AuthHandler"; @Controller() @Service() @@ -16,7 +18,7 @@ export default class OfficesController extends ApiController { /** * @description Get all offices */ - @Get("/api/v1/super-admin/offices") + @Get("/api/v1/super-admin/offices", [authHandler, ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -35,7 +37,7 @@ export default class OfficesController extends ApiController { /** * @description Create a new office */ - @Post("/api/v1/super-admin/offices") + @Post("/api/v1/super-admin/offices", [authHandler,ruleHandler]) protected async post(req: Request, response: Response) { try { //init IUser resource with request body values @@ -58,7 +60,7 @@ export default class OfficesController extends ApiController { /** * @description Modify a specific office by uid */ - @Put("/api/v1/super-admin/offices/:uid") + @Put("/api/v1/super-admin/offices/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -93,7 +95,7 @@ export default class OfficesController extends ApiController { /** * @description Get a specific office by uid */ - @Get("/api/v1/super-admin/offices/:uid") + @Get("/api/v1/super-admin/offices/:uid", [authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/api/super-admin/RolesController.ts b/src/app/api/super-admin/RolesController.ts new file mode 100644 index 00000000..c4ac55af --- /dev/null +++ b/src/app/api/super-admin/RolesController.ts @@ -0,0 +1,147 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RolesService from "@Services/super-admin/RolesService/RolesService"; +import { Service } from "typedi"; +import { validateOrReject } from "class-validator"; +import { Role } from "le-coffre-resources/dist/Notary"; +import { Roles } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; + +@Controller() +@Service() +export default class RolesController extends ApiController { + constructor(private rolesService: RolesService) { + super(); + } + + /** + * @description Get all roles + */ + @Get("/api/v1/super-admin/roles", [authHandler,ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + const query = JSON.parse(req.query["q"] as string); + + //call service to get prisma entity + const rolesEntities = await this.rolesService.get(query); + + //Hydrate ressource with prisma entity + const roles = Role.hydrateArray(rolesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, roles); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new role + */ + @Post("/api/v1/super-admin/roles", [authHandler,ruleHandler]) + protected async getAddresses(req: Request, response: Response) { + try { + //init IRole resource with request body values + const roleEntity = Role.hydrate(req.body); + + //validate role + await validateOrReject(roleEntity, { groups: ["createRole"] }); + + //call service to get prisma entity + const roleEntityCreated = await this.rolesService.create(roleEntity); + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific role by uid + */ + @Put("/api/v1/super-admin/roles/:uid", [authHandler,ruleHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const roleFound = await this.rolesService.getByUid(uid); + + if (!roleFound) { + this.httpNotFoundRequest(response, "role not found"); + return; + } + + //init IRole resource with request body values + const roleEntity = Role.hydrate(req.body); + + //validate role + await validateOrReject(roleEntity, { groups: ["updateRole"] }); + + //call service to get prisma entity + const roleEntityUpdated = await this.rolesService.update(roleEntity); + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific role by uid + */ + @Get("/api/v1/super-admin/roles/:uid", [authHandler,ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + let roleEntity: Roles | null; + //get query + if (req.query["q"]) { + const query = JSON.parse(req.query["q"] as string); + roleEntity = await this.rolesService.getByUid(uid, query); + } else { + //call service to get prisma entity + roleEntity = await this.rolesService.getByUid(uid); + } + + if (!roleEntity) { + this.httpNotFoundRequest(response, "role not found"); + return; + } + + //Hydrate ressource with prisma entity + const role = Role.hydrate(roleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, role); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/RulesController.ts b/src/app/api/super-admin/RulesController.ts new file mode 100644 index 00000000..fe7e4ee3 --- /dev/null +++ b/src/app/api/super-admin/RulesController.ts @@ -0,0 +1,147 @@ +import { Response, Request } from "express"; +import { Controller, Get, Post, Put } from "@ControllerPattern/index"; +import ApiController from "@Common/system/controller-pattern/ApiController"; +import RulesService from "@Services/super-admin/RulesService/RulesService"; +import { Service } from "typedi"; +import { validateOrReject } from "class-validator"; +import { Rule } from "le-coffre-resources/dist/Notary"; +import { Rules } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; + +@Controller() +@Service() +export default class RulesController extends ApiController { + constructor(private rulesService: RulesService) { + super(); + } + + /** + * @description Get all rules + */ + @Get("/api/v1/super-admin/rules", [authHandler,ruleHandler]) + protected async get(req: Request, response: Response) { + try { + //get query + const query = JSON.parse(req.query["q"] as string); + + //call service to get prisma entity + const rulesEntities = await this.rulesService.get(query); + + //Hydrate ressource with prisma entity + const rules = Rule.hydrateArray(rulesEntities, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rules); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Create a new rule + */ + @Post("/api/v1/super-admin/rules", [authHandler,ruleHandler]) + protected async getAddresses(req: Request, response: Response) { + try { + //init IRule resource with request body values + const ruleEntity = Rule.hydrate(req.body); + + //validate rule + await validateOrReject(ruleEntity, { groups: ["createRule"] }); + + //call service to get prisma entity + const ruleEntityCreated = await this.rulesService.create(ruleEntity); + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntityCreated, { + strategy: "excludeAll", + }); + + //success + this.httpCreated(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Modify a specific rule by uid + */ + @Put("/api/v1/super-admin/rules/:uid", [authHandler,ruleHandler]) + protected async put(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + + const ruleFound = await this.rulesService.getByUid(uid); + + if (!ruleFound) { + this.httpNotFoundRequest(response, "rule not found"); + return; + } + + //init IRule resource with request body values + const ruleEntity = Rule.hydrate(req.body); + + //validate rule + await validateOrReject(ruleEntity, { groups: ["updateRule"] }); + + //call service to get prisma entity + const ruleEntityUpdated = await this.rulesService.update(ruleEntity); + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } + + /** + * @description Get a specific rule by uid + */ + @Get("/api/v1/super-admin/rules/:uid", [authHandler,ruleHandler]) + protected async getOneByUid(req: Request, response: Response) { + try { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "No uid provided"); + return; + } + let ruleEntity: Rules | null; + //get query + if (req.query["q"]) { + const query = JSON.parse(req.query["q"] as string); + ruleEntity = await this.rulesService.getByUid(uid, query); + } else { + //call service to get prisma entity + ruleEntity = await this.rulesService.getByUid(uid); + } + + if (!ruleEntity) { + this.httpNotFoundRequest(response, "rule not found"); + return; + } + + //Hydrate ressource with prisma entity + const rule = Rule.hydrate(ruleEntity, { strategy: "excludeAll" }); + + //success + this.httpSuccess(response, rule); + } catch (error) { + this.httpInternalError(response, error); + return; + } + } +} diff --git a/src/app/api/super-admin/UsersController.ts b/src/app/api/super-admin/UsersController.ts index 5231ccc1..aa2de89c 100644 --- a/src/app/api/super-admin/UsersController.ts +++ b/src/app/api/super-admin/UsersController.ts @@ -6,6 +6,8 @@ import { Service } from "typedi"; import { validateOrReject } from "class-validator"; import User from "le-coffre-resources/dist/Notary"; import { Users } from "@prisma/client"; +import authHandler from "@App/middlewares/AuthHandler"; +import ruleHandler from "@App/middlewares/RulesHandler"; @Controller() @Service() @@ -17,7 +19,7 @@ export default class UsersController extends ApiController { /** * @description Get all users */ - @Get("/api/v1/super-admin/users") + @Get("/api/v1/super-admin/users", [authHandler,ruleHandler]) protected async get(req: Request, response: Response) { try { //get query @@ -40,7 +42,7 @@ export default class UsersController extends ApiController { /** * @description Create a new user */ - @Post("/api/v1/super-admin/users") + @Post("/api/v1/super-admin/users", [authHandler, ruleHandler]) protected async getAddresses(req: Request, response: Response) { try { //init IUser resource with request body values @@ -68,7 +70,7 @@ export default class UsersController extends ApiController { /** * @description Modify a specific user by uid */ - @Put("/api/v1/super-admin/users/:uid") + @Put("/api/v1/super-admin/users/:uid", [authHandler,ruleHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -109,7 +111,7 @@ export default class UsersController extends ApiController { /** * @description Get a specific user by uid */ - @Get("/api/v1/super-admin/users/:uid") + @Get("/api/v1/super-admin/users/:uid",[authHandler,ruleHandler]) protected async getOneByUid(req: Request, response: Response) { try { const uid = req.params["uid"]; diff --git a/src/app/index.ts b/src/app/index.ts index e2b0a51f..f23a9a7d 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -8,9 +8,11 @@ import DeedsController from "./api/super-admin/DeedsController"; import DeedTypesController from "./api/super-admin/DeedTypesController"; import DocumentsController from "./api/super-admin/DocumentsController"; import DocumentTypesController from "./api/super-admin/DocumentTypesController"; -import IdNotUserInfoController from "./api/idnot-user/UserInfoController"; +import IdNotUserController from "./api/idnot/UserController"; import DocumentsControllerCustomer from "./api/customer/DocumentsController"; import FilesController from "./api/super-admin/FilesController"; +import RulesController from "./api/super-admin/RolesController"; +import RolesController from "./api/super-admin/RolesController"; /** @@ -27,8 +29,10 @@ export default { Container.get(DeedTypesController); Container.get(DocumentsController); Container.get(DocumentTypesController); - Container.get(IdNotUserInfoController); + Container.get(IdNotUserController); Container.get(FilesController); Container.get(DocumentsControllerCustomer); + Container.get(RulesController); + Container.get(RolesController); }, }; diff --git a/src/app/middlewares/AuthHandler.ts b/src/app/middlewares/AuthHandler.ts new file mode 100644 index 00000000..549cfe1f --- /dev/null +++ b/src/app/middlewares/AuthHandler.ts @@ -0,0 +1,26 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import AuthService from "@Services/common/AuthService/AuthService"; +import { NextFunction, Request, Response } from "express"; +import Container from "typedi"; + +export default function authHandler(req: Request, response: Response, next: NextFunction) { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + + if (!token) { + response.sendStatus(HttpCodes.UNAUTHORIZED) + return; + } + + const authService = Container.get(AuthService); + authService.verifyAccessToken(token, (err, userPayload) => { + if (err) { + response.sendStatus(HttpCodes.UNAUTHORIZED); + return; + } + console.log(userPayload); + req.body.user = userPayload + next(); + }); +} + diff --git a/src/app/middlewares/RulesHandler.ts b/src/app/middlewares/RulesHandler.ts new file mode 100644 index 00000000..c1a4d6e6 --- /dev/null +++ b/src/app/middlewares/RulesHandler.ts @@ -0,0 +1,22 @@ +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { NextFunction, Request, Response } from "express"; + +export default async function ruleHandler(req: Request, response: Response, next: NextFunction) { + const rules = req.body.user.rules; + const service = req.path && req.path.split('/')[4]; + const namespace = req.path && req.path.split('/')[3]; + const role = req.body.user.role; + + if(namespace != 'notary' && role != namespace) { + response.sendStatus(HttpCodes.UNAUTHORIZED); + return; + } + + if(!rules.includes(req.method + ' ' + service)) { + response.sendStatus(HttpCodes.UNAUTHORIZED); + return; + } + + next(); +} + diff --git a/src/common/config/variables/Variables.ts b/src/common/config/variables/Variables.ts index bc20851c..95a8a427 100644 --- a/src/common/config/variables/Variables.ts +++ b/src/common/config/variables/Variables.ts @@ -54,6 +54,12 @@ export class BackendVariables { @IsNotEmpty() public readonly PINATA_GATEWAY!: string; + @IsNotEmpty() + public readonly ACCESS_TOKEN_SECRET!: string; + + @IsNotEmpty() + public readonly REFRESH_TOKEN_SECRET!: string; + public constructor() { dotenv.config(); this.DATABASE_PORT = process.env["DATABASE_PORT"]!; @@ -72,9 +78,21 @@ export class BackendVariables { this.PINATA_API_KEY = process.env["PINATA_API_KEY"]!; this.PINATA_API_SECRET = process.env["PINATA_API_SECRET"]!; this.PINATA_GATEWAY = process.env["PINATA_GATEWAY"]!; + this.ACCESS_TOKEN_SECRET = process.env["ACCESS_TOKEN_SECRET"]!; + this.REFRESH_TOKEN_SECRET = process.env["REFRESH_TOKEN_SECRET"]!; } - public async validate() { - await validateOrReject(this); + public async validate(groups?: string[]) { + const validationOptions = groups ? { groups } : undefined; + + try { + await validateOrReject(this, validationOptions); + } + catch(error) { + if(process.env["NODE_ENV"] === "development") { + throw error; + } + throw new Error("Some env variables are required!"); + } return this; } } diff --git a/src/common/databases/migrations/20230505075245_v1/migration.sql b/src/common/databases/migrations/20230505075245_v1/migration.sql deleted file mode 100644 index c212eab0..00000000 --- a/src/common/databases/migrations/20230505075245_v1/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `iv` to the `files` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "files" ADD COLUMN "iv" VARCHAR(255) NOT NULL; diff --git a/src/common/databases/migrations/20230505131655_v2/migration.sql b/src/common/databases/migrations/20230505131655_v2/migration.sql deleted file mode 100644 index a7f5aaa6..00000000 --- a/src/common/databases/migrations/20230505131655_v2/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `file_name` to the `files` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "files" ADD COLUMN "file_name" VARCHAR(255) NOT NULL; diff --git a/src/common/databases/migrations/20230510204321_v4/migration.sql b/src/common/databases/migrations/20230510204321_v4/migration.sql deleted file mode 100644 index 463c9e19..00000000 --- a/src/common/databases/migrations/20230510204321_v4/migration.sql +++ /dev/null @@ -1,9 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `iv` on the `files` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "files" DROP COLUMN "iv", -ADD COLUMN "key" VARCHAR(255); diff --git a/src/common/databases/migrations/20230511085908_v5/migration.sql b/src/common/databases/migrations/20230511085908_v5/migration.sql deleted file mode 100644 index a5b3abcb..00000000 --- a/src/common/databases/migrations/20230511085908_v5/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "files" ADD COLUMN "archived_at" TIMESTAMP(3); diff --git a/src/common/databases/migrations/20230515134800_v6/migration.sql b/src/common/databases/migrations/20230515134800_v6/migration.sql deleted file mode 100644 index efaf46c5..00000000 --- a/src/common/databases/migrations/20230515134800_v6/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ -/* - Warnings: - - - Added the required column `mimetype` to the `files` table without a default value. This is not possible if the table is not empty. - - Added the required column `size` to the `files` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "files" ADD COLUMN "mimetype" VARCHAR(255) NOT NULL, -ADD COLUMN "size" INTEGER NOT NULL; diff --git a/src/common/databases/migrations/20230426144239_init/migration.sql b/src/common/databases/migrations/20230621092719_init/migration.sql similarity index 85% rename from src/common/databases/migrations/20230426144239_init/migration.sql rename to src/common/databases/migrations/20230621092719_init/migration.sql index d017a9c4..f8237a5c 100644 --- a/src/common/databases/migrations/20230426144239_init/migration.sql +++ b/src/common/databases/migrations/20230621092719_init/migration.sql @@ -35,9 +35,9 @@ CREATE TABLE "contacts" ( "last_name" VARCHAR(255) NOT NULL, "email" VARCHAR(255) NOT NULL, "phone_number" VARCHAR(50), - "cell_phone_number" VARCHAR(50), + "cell_phone_number" VARCHAR(50) NOT NULL, "civility" "ECivility" NOT NULL DEFAULT 'MALE', - "address_uid" VARCHAR(255) NOT NULL, + "address_uid" VARCHAR(255), "birthdate" TIMESTAMP(3), "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3), @@ -50,6 +50,7 @@ CREATE TABLE "users" ( "uid" TEXT NOT NULL, "idNot" VARCHAR(255) NOT NULL, "contact_uid" VARCHAR(255) NOT NULL, + "roles_uid" TEXT NOT NULL, "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3), "office_uid" VARCHAR(255) NOT NULL, @@ -174,6 +175,11 @@ CREATE TABLE "files" ( "uid" TEXT NOT NULL, "document_uid" VARCHAR(255) NOT NULL, "file_path" VARCHAR(255) NOT NULL, + "file_name" VARCHAR(255) NOT NULL, + "mimetype" VARCHAR(255) NOT NULL, + "size" INTEGER NOT NULL, + "archived_at" TIMESTAMP(3), + "key" VARCHAR(255), "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3), @@ -249,6 +255,50 @@ CREATE TABLE "deed_type_has_document_types" ( CONSTRAINT "deed_type_has_document_types_pkey" PRIMARY KEY ("uid") ); +-- CreateTable +CREATE TABLE "roles" ( + "uid" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "roles_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "rules" ( + "uid" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + "role_has_rules_uid" TEXT, + "office_role_has_rules_uid" TEXT, + + CONSTRAINT "rules_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "role_has_rules" ( + "uid" TEXT NOT NULL, + "role_uid" VARCHAR(255) NOT NULL, + "rule_uid" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "role_has_rules_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "office_role_has_rules" ( + "uid" TEXT NOT NULL, + "role_uid" VARCHAR(255) NOT NULL, + "rule_uid" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "office_role_has_rules_pkey" PRIMARY KEY ("uid") +); + -- CreateIndex CREATE UNIQUE INDEX "addresses_uid_key" ON "addresses"("uid"); @@ -366,12 +416,27 @@ CREATE UNIQUE INDEX "deed_type_has_document_types_uid_key" ON "deed_type_has_doc -- CreateIndex CREATE UNIQUE INDEX "deed_type_has_document_types_deed_type_uid_document_type_ui_key" ON "deed_type_has_document_types"("deed_type_uid", "document_type_uid"); +-- CreateIndex +CREATE UNIQUE INDEX "roles_uid_key" ON "roles"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "rules_uid_key" ON "rules"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "role_has_rules_uid_key" ON "role_has_rules"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "office_role_has_rules_uid_key" ON "office_role_has_rules"("uid"); + -- AddForeignKey ALTER TABLE "contacts" ADD CONSTRAINT "contacts_address_uid_fkey" FOREIGN KEY ("address_uid") REFERENCES "addresses"("uid") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "users" ADD CONSTRAINT "users_contact_uid_fkey" FOREIGN KEY ("contact_uid") REFERENCES "contacts"("uid") ON DELETE CASCADE ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE RESTRICT ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "users" ADD CONSTRAINT "users_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE; @@ -444,6 +509,14 @@ ALTER TABLE "deed_type_has_document_types" ADD CONSTRAINT "deed_type_has_documen -- AddForeignKey ALTER TABLE "deed_type_has_document_types" ADD CONSTRAINT "deed_type_has_document_types_deed_type_uid_fkey" FOREIGN KEY ("deed_type_uid") REFERENCES "deed_types"("uid") ON DELETE CASCADE ON UPDATE CASCADE; --- AlterTable -ALTER TABLE "contacts" ALTER COLUMN "cell_phone_number" SET NOT NULL, -ALTER COLUMN "address_uid" DROP NOT NULL; \ No newline at end of file +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_role_has_rules_uid_fkey" FOREIGN KEY ("role_has_rules_uid") REFERENCES "role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_office_role_has_rules_uid_fkey" FOREIGN KEY ("office_role_has_rules_uid") REFERENCES "office_role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "role_has_rules" ADD CONSTRAINT "role_has_rules_role_uid_fkey" FOREIGN KEY ("role_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "office_role_has_rules" ADD CONSTRAINT "office_role_has_rules_role_uid_fkey" FOREIGN KEY ("role_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230621100427_v1/migration.sql b/src/common/databases/migrations/20230621100427_v1/migration.sql new file mode 100644 index 00000000..be549452 --- /dev/null +++ b/src/common/databases/migrations/20230621100427_v1/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to alter the column `roles_uid` on the `users` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(255)`. + +*/ +-- DropForeignKey +ALTER TABLE "users" DROP CONSTRAINT "users_roles_uid_fkey"; + +-- AlterTable +ALTER TABLE "users" ALTER COLUMN "roles_uid" SET DATA TYPE VARCHAR(255); + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230622172124_v2/migration.sql b/src/common/databases/migrations/20230622172124_v2/migration.sql new file mode 100644 index 00000000..34d5f531 --- /dev/null +++ b/src/common/databases/migrations/20230622172124_v2/migration.sql @@ -0,0 +1,37 @@ +/* + Warnings: + + - You are about to drop the column `office_role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - You are about to drop the column `role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - Added the required column `office_uid` to the `office_role_has_rules` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_office_role_has_rules_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_role_has_rules_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "users" DROP CONSTRAINT "users_roles_uid_fkey"; + +-- AlterTable +ALTER TABLE "office_role_has_rules" ADD COLUMN "office_uid" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "rules" DROP COLUMN "office_role_has_rules_uid", +DROP COLUMN "role_has_rules_uid", +ADD COLUMN "officesRolesHasRulesUid" TEXT, +ADD COLUMN "rolesHasRulesUid" TEXT; + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_rolesHasRulesUid_fkey" FOREIGN KEY ("rolesHasRulesUid") REFERENCES "role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_officesRolesHasRulesUid_fkey" FOREIGN KEY ("officesRolesHasRulesUid") REFERENCES "office_role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "office_role_has_rules" ADD CONSTRAINT "office_role_has_rules_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230622172838_v3/migration.sql b/src/common/databases/migrations/20230622172838_v3/migration.sql new file mode 100644 index 00000000..b218d50d --- /dev/null +++ b/src/common/databases/migrations/20230622172838_v3/migration.sql @@ -0,0 +1,24 @@ +/* + Warnings: + + - You are about to drop the column `officesRolesHasRulesUid` on the `rules` table. All the data in the column will be lost. + - You are about to drop the column `rolesHasRulesUid` on the `rules` table. All the data in the column will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_officesRolesHasRulesUid_fkey"; + +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_rolesHasRulesUid_fkey"; + +-- AlterTable +ALTER TABLE "rules" DROP COLUMN "officesRolesHasRulesUid", +DROP COLUMN "rolesHasRulesUid", +ADD COLUMN "office_role_has_rules_uid" TEXT, +ADD COLUMN "role_has_rules_uid" TEXT; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_role_has_rules_uid_fkey" FOREIGN KEY ("role_has_rules_uid") REFERENCES "role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "rules" ADD CONSTRAINT "rules_office_role_has_rules_uid_fkey" FOREIGN KEY ("office_role_has_rules_uid") REFERENCES "office_role_has_rules"("uid") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230623070044_v4/migration.sql b/src/common/databases/migrations/20230623070044_v4/migration.sql new file mode 100644 index 00000000..865da2cf --- /dev/null +++ b/src/common/databases/migrations/20230623070044_v4/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - You are about to drop the column `rule_uid` on the `office_role_has_rules` table. All the data in the column will be lost. + - You are about to drop the column `rule_uid` on the `role_has_rules` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "office_role_has_rules" DROP COLUMN "rule_uid"; + +-- AlterTable +ALTER TABLE "role_has_rules" DROP COLUMN "rule_uid"; diff --git a/src/common/databases/migrations/20230623072820_v5/migration.sql b/src/common/databases/migrations/20230623072820_v5/migration.sql new file mode 100644 index 00000000..417d4724 --- /dev/null +++ b/src/common/databases/migrations/20230623072820_v5/migration.sql @@ -0,0 +1,30 @@ +/* + Warnings: + + - You are about to drop the column `office_role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - You are about to drop the column `role_has_rules_uid` on the `rules` table. All the data in the column will be lost. + - Added the required column `rule_uid` to the `office_role_has_rules` table without a default value. This is not possible if the table is not empty. + - Added the required column `rule_uid` to the `role_has_rules` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_office_role_has_rules_uid_fkey"; + +-- DropForeignKey +ALTER TABLE "rules" DROP CONSTRAINT "rules_role_has_rules_uid_fkey"; + +-- AlterTable +ALTER TABLE "office_role_has_rules" ADD COLUMN "rule_uid" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "role_has_rules" ADD COLUMN "rule_uid" VARCHAR(255) NOT NULL; + +-- AlterTable +ALTER TABLE "rules" DROP COLUMN "office_role_has_rules_uid", +DROP COLUMN "role_has_rules_uid"; + +-- AddForeignKey +ALTER TABLE "role_has_rules" ADD CONSTRAINT "role_has_rules_rule_uid_fkey" FOREIGN KEY ("rule_uid") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "office_role_has_rules" ADD CONSTRAINT "office_role_has_rules_rule_uid_fkey" FOREIGN KEY ("rule_uid") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/schema.prisma b/src/common/databases/schema.prisma index f9035aa2..fa2ad5eb 100644 --- a/src/common/databases/schema.prisma +++ b/src/common/databases/schema.prisma @@ -54,6 +54,8 @@ model Users { idNot String @unique @db.VarChar(255) contact Contacts @relation(fields: [contact_uid], references: [uid], onDelete: Cascade) contact_uid String @unique @db.VarChar(255) + role Roles @relation(fields: [roles_uid], references: [uid], onDelete: Cascade) + roles_uid String @db.VarChar(255) created_at DateTime? @default(now()) updated_at DateTime? @updatedAt office_membership Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) @@ -65,19 +67,20 @@ model Users { } model Offices { - uid String @id @unique @default(uuid()) - idNot String @unique @db.VarChar(255) - name String @db.VarChar(255) - crpcen String @unique @db.VarChar(255) - address Addresses @relation(fields: [address_uid], references: [uid], onDelete: Cascade) - address_uid String @unique @db.VarChar(255) - office_status EOfficeStatus @default(DESACTIVATED) - created_at DateTime? @default(now()) - updated_at DateTime? @updatedAt - deed_types DeedTypes[] - users Users[] - office_folders OfficeFolders[] - document_types DocumentTypes[] + uid String @id @unique @default(uuid()) + idNot String @unique @db.VarChar(255) + name String @db.VarChar(255) + crpcen String @unique @db.VarChar(255) + address Addresses @relation(fields: [address_uid], references: [uid], onDelete: Cascade) + address_uid String @unique @db.VarChar(255) + office_status EOfficeStatus @default(DESACTIVATED) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + deed_types DeedTypes[] + users Users[] + office_folders OfficeFolders[] + document_types DocumentTypes[] + office_role_has_rules OfficesRolesHasRules[] @@map("offices") } @@ -205,7 +208,7 @@ model Files { file_path String @unique @db.VarChar(255) file_name String @db.VarChar(255) mimetype String @db.VarChar(255) - size Int + size Int archived_at DateTime? key String? @db.VarChar(255) created_at DateTime? @default(now()) @@ -296,6 +299,55 @@ model DeedTypeHasDocumentTypes { @@map("deed_type_has_document_types") } +model Roles { + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + role_has_rules RolesHasRules[] + office_role_has_rules OfficesRolesHasRules[] + users Users[] + + @@map("roles") +} + +model Rules { + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + role_has_rules RolesHasRules[] + office_roles_has_rules OfficesRolesHasRules[] + + @@map("rules") +} + +model RolesHasRules { + uid String @id @unique @default(uuid()) + role Roles @relation(fields: [role_uid], references: [uid], onDelete: Cascade) + role_uid String @db.VarChar(255) + rule Rules @relation(fields: [rule_uid], references: [uid], onDelete: Cascade) + rule_uid String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + + @@map("role_has_rules") +} + +model OfficesRolesHasRules { + uid String @id @unique @default(uuid()) + office Offices @relation(fields: [office_uid], references: [uid], onDelete: Cascade) + role Roles @relation(fields: [role_uid], references: [uid], onDelete: Cascade) + rule Rules @relation(fields: [rule_uid], references: [uid], onDelete: Cascade) + office_uid String @db.VarChar(255) + role_uid String @db.VarChar(255) + rule_uid String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + + @@map("office_role_has_rules") +} + enum ECivility { MALE FEMALE diff --git a/src/common/databases/seeders/seeder.ts b/src/common/databases/seeders/seeder.ts index 881e081f..c8eb63f8 100644 --- a/src/common/databases/seeders/seeder.ts +++ b/src/common/databases/seeders/seeder.ts @@ -19,6 +19,7 @@ import { ECivility, ECustomerStatus, PrismaClient, + Roles, } from "@prisma/client"; (async () => { @@ -49,6 +50,9 @@ import { const uidUser1: string = randomString(); const uidUser2: string = randomString(); + const uidRole1: string = randomString(); + const uidRole2: string = randomString(); + const uidOfficeFolder1: string = randomString(); const uidOfficeFolder2: string = randomString(); const uidOfficeFolder3: string = randomString(); @@ -223,6 +227,21 @@ import { }, ]; + const roles: Roles[] = [ + { + uid: uidRole1, + name: 'super-admin', + created_at: new Date(), + updated_at: new Date(), + }, + { + uid: uidRole2, + name: 'admin', + created_at: new Date(), + updated_at: new Date(), + } + ]; + const users: Users[] = [ { uid: uidUser1, @@ -231,6 +250,7 @@ import { idNot: randomString(), contact_uid: uidContact1, office_uid: uidOffice1, + roles_uid: uidRole1, }, { uid: uidUser2, @@ -239,6 +259,7 @@ import { idNot: randomString(), contact_uid: uidContact2, office_uid: uidOffice2, + roles_uid: uidRole2, }, ]; @@ -527,6 +548,10 @@ import { await prisma.offices.create({ data: office }); } + for (const role of roles) { + await prisma.roles.create({ data: role }); + } + for (const user of users) { await prisma.users.create({ data: user }); } diff --git a/src/common/databases/seeders/seeder2.ts b/src/common/databases/seeders/seeder2.ts index 7a3c82fe..ce81192e 100644 --- a/src/common/databases/seeders/seeder2.ts +++ b/src/common/databases/seeders/seeder2.ts @@ -17,6 +17,10 @@ import { ECivility, ECustomerStatus, PrismaClient, + Roles, + OfficesRolesHasRules, + RolesHasRules, + Rules, } from "@prisma/client"; (async () => { @@ -100,6 +104,12 @@ import { const uidUser4: string = randomString(); const uidUser5: string = randomString(); + const uidRole1: string = randomString(); + const uidRole2: string = randomString(); + + const uidRule1: string = randomString(); + const uidRule2: string = randomString(); + const uidOfficeFolder1: string = randomString(); const uidOfficeFolder2: string = randomString(); const uidOfficeFolder3: string = randomString(); @@ -163,6 +173,12 @@ import { const uidOfficeFolderHasCustomer3: string = randomString(); const uidOfficeFolderHasCustomer4: string = randomString(); + const uidOfficeRoleHasRule1: string = randomString(); + const uidOfficeRoleHasRule2: string = randomString(); + + const uidRoleHasRule1: string = randomString(); + const uidRoleHasRule2: string = randomString(); + const uidDeedHasDocumentType1: string = randomString(); const uidDeedHasDocumentType2: string = randomString(); const uidDeedHasDocumentType3: string = randomString(); @@ -785,6 +801,21 @@ import { } ]; + const roles: Roles[] = [ + { + uid: uidRole1, + name: 'super-admin', + created_at: new Date(), + updated_at: new Date(), + }, + { + uid: uidRole2, + name: 'admin', + created_at: new Date(), + updated_at: new Date(), + } + ]; + const users: Users[] = [ { uid: uidUser1, @@ -793,6 +824,7 @@ import { idNot: randomString(), contact_uid: uidContact16, office_uid: uidOffice1, + roles_uid: uidRole1, }, { uid: uidUser2, @@ -801,6 +833,7 @@ import { idNot: randomString(), contact_uid: uidContact17, office_uid: uidOffice1, + roles_uid: uidRole2, }, { uid: uidUser3, @@ -809,6 +842,7 @@ import { idNot: randomString(), contact_uid: uidContact18, office_uid: uidOffice1, + roles_uid: uidRole1, }, { uid: uidUser4, @@ -817,6 +851,7 @@ import { idNot: randomString(), contact_uid: uidContact19, office_uid: uidOffice1, + roles_uid: uidRole2, }, { uid: uidUser5, @@ -825,6 +860,7 @@ import { idNot: randomString(), contact_uid: uidContact20, office_uid: uidOffice1, + roles_uid: uidRole1, }, ]; @@ -1664,6 +1700,57 @@ import { }, ]; + const officeRoleHasRules: OfficesRolesHasRules[] = [ + { + uid: uidOfficeRoleHasRule1, + office_uid: uidOffice1, + role_uid: uidRole1, + rule_uid: uidRule1, + created_at: new Date(), + updated_at: new Date(), + }, + { + uid: uidOfficeRoleHasRule2, + office_uid: uidOffice1, + role_uid: uidRole2, + rule_uid: uidRule2, + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const roleHasRules: RolesHasRules[] = [ + { + uid: uidRoleHasRule1, + role_uid: uidRole1, + rule_uid: uidRule2, + created_at: new Date(), + updated_at: new Date(), + }, + { + uid: uidRoleHasRule2, + role_uid: uidRole2, + rule_uid: uidRule1, + created_at: new Date(), + updated_at: new Date(), + }, + ]; + + const rules: Rules[] = [ + { + uid: uidRule1, + name: 'GET users', + created_at: new Date(), + updated_at: new Date(), + }, + { + uid: uidRule2, + name: 'GET offices', + created_at: new Date(), + updated_at: new Date(), + } + ]; + const deedTypeHasDocumentTypes: DeedTypeHasDocumentTypes[] = [ { uid: uidDeedTypeHasDocumentType1, @@ -1840,6 +1927,14 @@ import { await prisma.offices.create({ data: office }); } + for (const role of roles) { + await prisma.roles.create({ data: role }); + } + + for (const rule of rules) { + await prisma.rules.create({ data: rule }); + } + for (const user of users) { await prisma.users.create({ data: user }); } @@ -1871,6 +1966,14 @@ import { await prisma.officeFolderHasCustomers.create({ data: officeFolderHasCustomer }); } + for (const officeRoleHasRule of officeRoleHasRules) { + await prisma.officesRolesHasRules.create({ data: officeRoleHasRule }); + } + + for (const roleHasRule of roleHasRules) { + await prisma.rolesHasRules.create({ data: roleHasRule }); + } + for (const deedHasDocumentType of deedHasDocumentTypes) { await prisma.deedHasDocumentTypes.create({ data: deedHasDocumentType }); } diff --git a/src/common/repositories/OfficeRoleHasRulesRepository.ts b/src/common/repositories/OfficeRoleHasRulesRepository.ts new file mode 100644 index 00000000..f36ccfd2 --- /dev/null +++ b/src/common/repositories/OfficeRoleHasRulesRepository.ts @@ -0,0 +1,42 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { OfficesRolesHasRules, Prisma } from "@prisma/client"; + +@Service() +export default class OfficeRoleHasRulesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().officesRolesHasRules; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many relations between office roles and rules + */ + public async findMany(query: any): Promise { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Find one relation between an office role and rules + */ + public async findOneByUid(uid: string, query?: any): Promise { + const findOneArgs: Prisma.OfficesRolesHasRulesFindUniqueArgs = { + where: { + uid: uid, + }, + }; + if (query) { + findOneArgs.include = query; + } + const roleEntity = await this.model.findUnique(findOneArgs); + + return roleEntity; + } +} diff --git a/src/common/repositories/RolesHasRulesRepository.ts b/src/common/repositories/RolesHasRulesRepository.ts new file mode 100644 index 00000000..7a255dc5 --- /dev/null +++ b/src/common/repositories/RolesHasRulesRepository.ts @@ -0,0 +1,42 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { RolesHasRules, Prisma } from "@prisma/client"; + +@Service() +export default class RolesHasRulesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().rolesHasRules; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many relations between basic roles and rules + */ + public async findMany(query: any): Promise { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Find one relation between an basic role and rules + */ + public async findOneByUid(uid: string, query?: any): Promise { + const findOneArgs: Prisma.RolesHasRulesFindUniqueArgs = { + where: { + uid: uid, + }, + }; + if (query) { + findOneArgs.include = query; + } + const roleEntity = await this.model.findUnique(findOneArgs); + + return roleEntity; + } +} diff --git a/src/common/repositories/RolesRepository.ts b/src/common/repositories/RolesRepository.ts new file mode 100644 index 00000000..3b69797a --- /dev/null +++ b/src/common/repositories/RolesRepository.ts @@ -0,0 +1,123 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Roles, Prisma } from "@prisma/client"; +import { Role } from "le-coffre-resources/dist/SuperAdmin"; + +@Service() +export default class RolesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().roles; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many roles + */ + public async findMany(query: any): Promise { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Create new role with rules + */ + public async create(role: Role): Promise { + const createArgs: Prisma.RolesCreateArgs = { + data: { + name: role.name, + role_has_rules: { + createMany: { + data: role.role_has_rules!.rules.map((relation) => ({ + rule_uid: relation.uid!, + })), + skipDuplicates: true, + }, + }, + }, + }; + if (role.office_role_has_rules) { + createArgs.data.office_role_has_rules = { + createMany: { + data: role.office_role_has_rules.rules.map((relation) => ({ + office_uid: role.office_role_has_rules!.office.uid!, + rule_uid: relation.uid!, + })), + skipDuplicates: true, + }, + }; + } + + return this.model.create(createArgs); + } + + /** + * @description : Update data of a role with rules + */ + public async update(role: Role): Promise { + const updateArgs: Prisma.RolesUpdateArgs = { + where: { + uid: role.uid, + }, + data: { + name: role.name, + role_has_rules: { + deleteMany: { role_uid: role.uid }, + createMany: { + data: role.role_has_rules!.rules.map((relation) => ({ + rule_uid: relation.uid!, + })), + skipDuplicates: true, + }, + }, + }, + }; + if (role.office_role_has_rules) { + updateArgs.data.office_role_has_rules = { + deleteMany: { role_uid: role.uid }, + createMany: { + data: role.office_role_has_rules.rules.map((relation) => ({ + office_uid: role.office_role_has_rules!.office.uid!, + rule_uid: relation.uid!, + })), + skipDuplicates: true, + }, + }; + } + + return this.model.update(updateArgs); + } + + /** + * @description : Find one role + */ + public async findOneByUid(uid: string, query?: any): Promise { + const findOneArgs: Prisma.RolesFindUniqueArgs = { + where: { + uid: uid, + }, + }; + if (query) { + findOneArgs.include = query; + } + const roleEntity = await this.model.findUnique(findOneArgs); + + return roleEntity; + } + + /** + * @description : Delete a role + */ + public async delete(uid: string): Promise { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/repositories/RulesRepository.ts b/src/common/repositories/RulesRepository.ts new file mode 100644 index 00000000..7d015429 --- /dev/null +++ b/src/common/repositories/RulesRepository.ts @@ -0,0 +1,83 @@ +import Database from "@Common/databases/database"; +import BaseRepository from "@Repositories/BaseRepository"; +import { Service } from "typedi"; +import { Rules, Prisma } from "@prisma/client"; +import { Rule } from "le-coffre-resources/dist/SuperAdmin"; + +@Service() +export default class RulesRepository extends BaseRepository { + constructor(private database: Database) { + super(); + } + protected get model() { + return this.database.getClient().rules; + } + protected get instanceDb() { + return this.database.getClient(); + } + + /** + * @description : Find many rules + */ + public async findMany(query: any): Promise { + query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + return this.model.findMany(query); + } + + /** + * @description : Create new rule + */ + public async create(rule: Rule): Promise { + const createArgs: Prisma.RulesCreateArgs = { + data: { + name: rule.name + }, + }; + + return this.model.create(createArgs); + } + + /** + * @description : Update data of a rule + */ + public async update(rule: Rule): Promise { + const updateArgs: Prisma.RulesUpdateArgs = { + where: { + uid: rule.uid, + }, + data: { + name: rule.name + }, + }; + + return this.model.update(updateArgs); + } + + /** + * @description : Find one rule + */ + public async findOneByUid(uid: string, query?: any): Promise { + const findOneArgs: Prisma.RulesFindUniqueArgs = { + where: { + uid: uid, + }, + }; + if (query) { + findOneArgs.include = query; + } + const ruleEntity = await this.model.findUnique(findOneArgs); + + return ruleEntity; + } + + /** + * @description : Delete a rule + */ + public async delete(uid: string): Promise { + return this.model.delete({ + where: { + uid: uid, + }, + }); + } +} diff --git a/src/common/repositories/UsersRepository.ts b/src/common/repositories/UsersRepository.ts index b051af69..a0f14234 100644 --- a/src/common/repositories/UsersRepository.ts +++ b/src/common/repositories/UsersRepository.ts @@ -61,6 +61,11 @@ export default class UsersRepository extends BaseRepository { address: {}, }, }, + role: { + connect: { + uid: user.role!.uid, + }, + } }, }; if (user.contact!.address) { diff --git a/src/common/system/OpenIdInterface.ts b/src/common/system/OpenIdInterface.ts new file mode 100644 index 00000000..d2d25049 --- /dev/null +++ b/src/common/system/OpenIdInterface.ts @@ -0,0 +1,16 @@ +export type Payload = { + sub: string; + email: string; +}; + +export type Tokens = { + access_token: string; + expires_in: number; + id_token: string; + token_type: string; +}; + +export default interface OpenIdInterface { + verifyIdToken(signingKey: string): Promise; + getSigningKeys(jwksUri: string): Promise; +} diff --git a/src/common/system/controller-pattern/BaseController.ts b/src/common/system/controller-pattern/BaseController.ts index edd1af03..39bd4be7 100644 --- a/src/common/system/controller-pattern/BaseController.ts +++ b/src/common/system/controller-pattern/BaseController.ts @@ -32,6 +32,10 @@ export default abstract class BaseController { return this.httpResponse(response, HttpCodes.INTERNAL_ERROR, responseData); } + protected httpUnauthorized(response: Response, responseData: IResponseData = "http Unauthorized Request") { + return this.httpResponse(response, HttpCodes.UNAUTHORIZED, responseData); + } + protected httpNotImplemented(response: Response, responseData: IResponseData = "Not implemented") { return this.httpResponse(response, HttpCodes.NOT_IMPLEMENTED, responseData); } diff --git a/src/common/system/controller-pattern/HttpCodes.ts b/src/common/system/controller-pattern/HttpCodes.ts index 2d6d92c5..648c30b1 100644 --- a/src/common/system/controller-pattern/HttpCodes.ts +++ b/src/common/system/controller-pattern/HttpCodes.ts @@ -7,5 +7,6 @@ enum HttpCodes { UNKNOWN_ERROR = 520, NOT_IMPLEMENTED = 501, NOT_FOUND = 404, + UNAUTHORIZED = 401, } export default HttpCodes; diff --git a/src/entries/App.ts b/src/entries/App.ts index d9874748..0b426b5d 100644 --- a/src/entries/App.ts +++ b/src/entries/App.ts @@ -11,6 +11,7 @@ import { BackendVariables } from "@Common/config/variables/Variables"; //import fileHandler from "@App/middlewares/FileHandler"; import multer from "multer"; + const storage = multer.memoryStorage(); (async () => { diff --git a/src/services/private-services/AddressesService/AddressesService.ts b/src/services/common/AddressesService/AddressesService.ts similarity index 100% rename from src/services/private-services/AddressesService/AddressesService.ts rename to src/services/common/AddressesService/AddressesService.ts diff --git a/src/services/common/AuthService/AuthService.ts b/src/services/common/AuthService/AuthService.ts new file mode 100644 index 00000000..8d497fa9 --- /dev/null +++ b/src/services/common/AuthService/AuthService.ts @@ -0,0 +1,65 @@ +import jwt, { VerifyCallback } from "jsonwebtoken"; +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { BackendVariables } from "@Common/config/variables/Variables"; +import { Service } from "typedi"; +import UsersService from "@Services/super-admin/UsersService/UsersService"; + +export type UserPayload = { + uid: string; + idNot: string; + office_idNot: string; + role: string; + rules: string[]; +}; + +@Service() +export default class AuthService extends BaseService { + constructor(protected variables: BackendVariables, private userService: UsersService) { + super(); + } + + public async getUserPayload(id: string): Promise { + const user: any = ( + await this.userService.get({ + where: { idNot: id }, + include: { + role: { include: { role_has_rules: { include: { rule: true } }, office_role_has_rules: { include: { rule: true } } } }, + office_membership: true, + }, + }) + )[0]; + + if (!user) throw new Error("User not found"); + + let rules: string[] = []; + if (user.role.office_role_has_rules.length) { + user.role.office_role_has_rules.forEach((relation: any) => { + if (relation.office_uid === user.office_membership.uid) rules.push(relation.rule.name); + }); + return { uid: user.uid, idNot: user.idNot, office_idNot: user.office_membership.idNot, role: user.role.name, rules: rules }; + } + if (!rules.length) { + user.role.role_has_rules.forEach((relation: any) => { + rules.push(relation.rule.name); + }); + } + return { uid: user.uid, idNot: user.idNot, office_idNot: user.office_membership.idNot, role: user.role.name, rules: rules }; + } + + public generateAccessToken(user: any): string { + return jwt.sign({ ...user }, this.variables.ACCESS_TOKEN_SECRET, { expiresIn: "15m" }); + } + + public generateRefreshToken(user: any): string { + return jwt.sign({ ...user }, this.variables.REFRESH_TOKEN_SECRET, { expiresIn: "1h" }); + } + + public verifyAccessToken(token: string, callback?: VerifyCallback) { + return jwt.verify(token, this.variables.ACCESS_TOKEN_SECRET, callback); + } + + public verifyRefreshToken(token: string, callback?: VerifyCallback) { + return jwt.verify(token, this.variables.REFRESH_TOKEN_SECRET, callback); + } +} diff --git a/src/services/private-services/ContactsService/ContactsService.ts b/src/services/common/ContactsService/ContactsService.ts similarity index 100% rename from src/services/private-services/ContactsService/ContactsService.ts rename to src/services/common/ContactsService/ContactsService.ts diff --git a/src/services/private-services/CryptoService/CryptoService.ts b/src/services/common/CryptoService/CryptoService.ts similarity index 100% rename from src/services/private-services/CryptoService/CryptoService.ts rename to src/services/common/CryptoService/CryptoService.ts diff --git a/src/services/private-services/FilesService/FilesService.ts b/src/services/common/FilesService/FilesService.ts similarity index 100% rename from src/services/private-services/FilesService/FilesService.ts rename to src/services/common/FilesService/FilesService.ts diff --git a/src/services/private-services/IpfsService/IpfsService.ts b/src/services/common/IpfsService/IpfsService.ts similarity index 100% rename from src/services/private-services/IpfsService/IpfsService.ts rename to src/services/common/IpfsService/IpfsService.ts diff --git a/src/services/private-services/NotificationsService/NotificationsService.ts b/src/services/common/NotificationsService/NotificationsService.ts similarity index 100% rename from src/services/private-services/NotificationsService/NotificationsService.ts rename to src/services/common/NotificationsService/NotificationsService.ts diff --git a/src/services/private-services/AuthService/AuthService.ts b/src/services/private-services/AuthService/AuthService.ts deleted file mode 100644 index ab528ec4..00000000 --- a/src/services/private-services/AuthService/AuthService.ts +++ /dev/null @@ -1,53 +0,0 @@ -import jwt from "jsonwebtoken"; -import BaseService from "@Services/BaseService"; -import "reflect-metadata"; -import { BackendVariables } from "@Common/config/variables/Variables"; -import Container, { Service } from "typedi"; - -type IdNotTokens = { - access_token: string; - id_token: string; -}; - -@Service() -export default class AuthService extends BaseService { - protected readonly variables = Container.get(BackendVariables); - private constructor() { - super(); - } - - /** - * @description : Get IdNot id_token and access_token - * @throws {Error} If jwt pair cannot be get - */ - public async getUserFromIdNotTokens(code: string) { - const tokens = await this.getIdNotTokens(code); - return jwt.decode(tokens.id_token); - } - - private async getIdNotTokens(code: string): Promise { - const url = new URL( - this.variables.IDNOT_CONNEXION_URL.concat("?") + - new URLSearchParams({ - client_id: this.variables.IDNOT_CLIENT_ID, - client_secret: this.variables.IDNOT_CLIENT_SECRET, - redirect_uri: this.variables.IDNOT_REDIRECT_URL, - code: code, - grant_type: "authorization_code", - }), - ); - try { - const headers = new Headers({ - "Content-Type": "application/x-www-form-urlencoded", - }); - const res = await fetch(url, { - method: "POST", - headers: headers, - }); - const data = await res.json(); - return data as IdNotTokens; - } catch (error) { - throw new Error(); - } - } -} diff --git a/src/services/super-admin/RolesService/RolesService.ts b/src/services/super-admin/RolesService/RolesService.ts new file mode 100644 index 00000000..bbe52248 --- /dev/null +++ b/src/services/super-admin/RolesService/RolesService.ts @@ -0,0 +1,45 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import RolesRepository from "@Repositories/RolesRepository"; +import { Role } from "le-coffre-resources/dist/SuperAdmin"; +import {Prisma, Roles } from "@prisma/client"; + +@Service() +export default class RolesService extends BaseService { + constructor(private roleRepository: RolesRepository) { + super(); + } + + /** + * @description : Get all roles + * @throws {Error} If roles cannot be get + */ + public get(query: Prisma.RolesFindManyArgs): Promise { + return this.roleRepository.findMany(query); + } + + /** + * @description : Create a role + * @throws {Error} If role couldn't be created + */ + public create(roleEntity: Role): Promise { + return this.roleRepository.create(roleEntity); + } + + /** + * @description : Modify a role + * @throws {Error} If role modification failed + */ + public update(roleEntity: Role): Promise { + return this.roleRepository.update(roleEntity); + } + + /** + * @description : Get a role by uid + * @throws {Error} If role cannot be get by uid + */ + public getByUid(uid: string, query?: any): Promise { + return this.roleRepository.findOneByUid(uid, query); + } +} diff --git a/src/services/super-admin/RulesService/RulesService.ts b/src/services/super-admin/RulesService/RulesService.ts new file mode 100644 index 00000000..edc4ce64 --- /dev/null +++ b/src/services/super-admin/RulesService/RulesService.ts @@ -0,0 +1,45 @@ +import BaseService from "@Services/BaseService"; +import "reflect-metadata"; +import { Service } from "typedi"; +import RulesRepository from "@Repositories/RulesRepository"; +import { Rule } from "le-coffre-resources/dist/SuperAdmin"; +import {Prisma, Rules } from "@prisma/client"; + +@Service() +export default class RulesService extends BaseService { + constructor(private ruleRepository: RulesRepository) { + super(); + } + + /** + * @description : Get all rules + * @throws {Error} If rules cannot be get + */ + public get(query: Prisma.RulesFindManyArgs): Promise { + return this.ruleRepository.findMany(query); + } + + /** + * @description : Create a rule + * @throws {Error} If rule couldn't be created + */ + public create(ruleEntity: Rule): Promise { + return this.ruleRepository.create(ruleEntity); + } + + /** + * @description : Modify a rule + * @throws {Error} If rule modification failed + */ + public update(ruleEntity: Rule): Promise { + return this.ruleRepository.update(ruleEntity); + } + + /** + * @description : Get a rule by uid + * @throws {Error} If rule cannot be get by uid + */ + public getByUid(uid: string, query?: any): Promise { + return this.ruleRepository.findOneByUid(uid, query); + } +} diff --git a/src/test/config/Init.ts b/src/test/config/Init.ts index 033fc8f1..a488d9a0 100644 --- a/src/test/config/Init.ts +++ b/src/test/config/Init.ts @@ -1,5 +1,16 @@ -import { Customers, DeedTypes, DocumentTypes, ECivility, ECustomerStatus, Offices, PrismaClient, Users } from "@prisma/client"; -import User, { Customer, DeedType, DocumentType, Office } from "le-coffre-resources/dist/SuperAdmin"; +import { + Customers, + DeedTypes, + DocumentTypes, + ECivility, + ECustomerStatus, + Offices, + PrismaClient, + Roles, + Rules, + Users, +} from "@prisma/client"; +import User, { Customer, DeedType, DocumentType, Office, Role, Rule } from "le-coffre-resources/dist/SuperAdmin"; const prisma = new PrismaClient(); @@ -54,68 +65,94 @@ export const initDeedType = (deedType: DeedType, office: Office, documentTypes?: export const initCustomers = (customer: Customer): Promise => { return prisma.customers.create({ data: { - status: ECustomerStatus.PENDING, - contact: { - create: { - first_name: customer.contact!.first_name, - last_name: customer.contact!.last_name, - email: customer.contact!.email, - phone_number: customer.contact!.phone_number, - cell_phone_number: customer.contact!?.cell_phone_number, - civility: ECivility[customer.contact!.civility as keyof typeof ECivility], - address: { - create: { - address: customer.contact!.address!.address, - zip_code: customer.contact!.address!.zip_code, - city: customer.contact!.address!.city, - }, - }, - }, - }, - }, + status: ECustomerStatus.PENDING, + contact: { + create: { + first_name: customer.contact!.first_name, + last_name: customer.contact!.last_name, + email: customer.contact!.email, + phone_number: customer.contact!.phone_number, + cell_phone_number: customer.contact!?.cell_phone_number, + civility: ECivility[customer.contact!.civility as keyof typeof ECivility], + address: { + create: { + address: customer.contact!.address!.address, + zip_code: customer.contact!.address!.zip_code, + city: customer.contact!.address!.city, + }, + }, + }, + }, + }, + }); +}; + +export const initRules = (rule: Rule): Promise => { + return prisma.rules.create({ + data: { + name: rule.name, + }, + }); +}; + +export const initRoles = (role: Role): Promise => { + return prisma.roles.create({ + data: { + name: role.name, + }, }); }; export const initUsers = (user: User): Promise => { return prisma.users.create({ data: { - idNot: user.idNot, - office_membership: { - connectOrCreate: { - where: { - idNot: user.office_membership!.idNot, - }, - create: { - idNot: user.office_membership!.idNot, - name: user.office_membership!.name, - crpcen: user.office_membership!.crpcen, - address: { - create: { - address: user.office_membership!.address!.address, - zip_code: user.office_membership!.address!.zip_code, - city: user.office_membership!.address!.city, - }, - }, - }, - }, - }, - contact: { - create: { - first_name: user.contact!.first_name, - last_name: user.contact!.last_name, - email: user.contact!.email, - phone_number: user.contact!.phone_number, - cell_phone_number: user.contact!.cell_phone_number, - civility: ECivility[user.contact!.civility as keyof typeof ECivility], - address: { - create: { - address: user.contact!.address!.address, - zip_code: user.contact!.address!.zip_code, - city: user.contact!.address!.city, - }, - }, - }, - }, - }, - }); + idNot: user.idNot, + office_membership: { + connectOrCreate: { + where: { + idNot: user.office_membership!.idNot, + }, + create: { + idNot: user.office_membership!.idNot, + name: user.office_membership!.name, + crpcen: user.office_membership!.crpcen, + address: { + create: { + address: user.office_membership!.address!.address, + zip_code: user.office_membership!.address!.zip_code, + city: user.office_membership!.address!.city, + }, + }, + }, + }, + }, + contact: { + create: { + first_name: user.contact!.first_name, + last_name: user.contact!.last_name, + email: user.contact!.email, + phone_number: user.contact!.phone_number, + cell_phone_number: user.contact!.cell_phone_number, + civility: ECivility[user.contact!.civility as keyof typeof ECivility], + address: { + create: { + address: user.contact!.address!.address, + zip_code: user.contact!.address!.zip_code, + city: user.contact!.address!.city, + }, + }, + }, + }, + role: { + connectOrCreate: { + where: { + uid: user.role!.uid, + }, + create: { + name: user.role!.name, + }, + }, + }, + }, + }); };