diff --git a/src/controllers/branch-controller.ts b/src/controllers/branch-controller.ts index 23a1719..4930bd6 100644 --- a/src/controllers/branch-controller.ts +++ b/src/controllers/branch-controller.ts @@ -27,6 +27,10 @@ if (!process.env.MINIO_BUCKET) { const MINIO_BUCKET = process.env.MINIO_BUCKET; const MANAGE_ROLES = ["system", "head_of_admin"]; +function globalAllow(user: RequestWithUser["user"]) { + return MANAGE_ROLES.some((v) => user.roles?.includes(v)); +} + type BranchCreate = { status?: Status; code: string; @@ -191,10 +195,17 @@ export class BranchController extends Controller { AND: { zipCode, headOfficeId: headOfficeId ?? (filter === "head" || tree ? null : undefined), - user: !MANAGE_ROLES.some((v) => req.user.roles?.includes(v)) - ? { some: { userId: req.user.sub } } - : undefined, NOT: { headOfficeId: filter === "sub" && !headOfficeId ? null : undefined }, + OR: globalAllow(req.user) + ? undefined + : [ + { user: !globalAllow(req.user) ? { some: { userId: req.user.sub } } : undefined }, + { + headOffice: !globalAllow(req.user) + ? { user: { some: { userId: req.user.sub } } } + : undefined, + }, + ], }, OR: [ { nameEN: { contains: query } }, diff --git a/src/controllers/branch-user-controller.ts b/src/controllers/branch-user-controller.ts index 57f6c7b..cf5167e 100644 --- a/src/controllers/branch-user-controller.ts +++ b/src/controllers/branch-user-controller.ts @@ -18,6 +18,13 @@ import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; import { RequestWithUser } from "../interfaces/user"; +const MANAGE_ROLES = ["system", "head_of_admin", "admin", "branch_manager"]; + +function globalAllow(user: RequestWithUser["user"]) { + const listAllowed = ["system", "head_of_admin", "admin"]; + return user.roles?.some((v) => listAllowed.includes(v)) || false; +} + type BranchUserBody = { user: string[] }; async function userBranchCodeGen(branch: Branch, user: User[]) { @@ -60,7 +67,7 @@ async function userBranchCodeGen(branch: Branch, user: User[]) { @Route("api/v1/branch/{branchId}/manager") @Tags("Branch User") -export class BranchAdminUserController extends Controller { +export class BranchManagerUserController extends Controller { @Get() @Security("keycloak") async getBranchAdmin(@Path() branchId: string) { @@ -75,6 +82,55 @@ export class BranchAdminUserController extends Controller { } } +@Route("api/v1/user/{userId}/branch") +@Tags("Branch User") +export class UserBranchController extends Controller { + @Get() + @Security("keycloak") + async getUserBranch( + @Path() userId: string, + @Query() zipCode?: string, + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + OR: [ + { branch: { name: { contains: query }, zipCode }, userId }, + { branch: { nameEN: { contains: query }, zipCode }, userId }, + ], + } satisfies Prisma.BranchUserWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.branchUser.findMany({ + orderBy: { branch: { createdAt: "asc" } }, + include: { + branch: { + include: { + province: true, + district: true, + subDistrict: true, + headOffice: { + include: { + province: true, + district: true, + subDistrict: true, + }, + }, + }, + }, + }, + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.branchUser.count({ where }), + ]); + + return { result: result.map((v) => v.branch), page, pageSize, total }; + } +} + @Route("api/v1/branch/{branchId}/user") @Tags("Branch User") export class BranchUserController extends Controller { @@ -121,7 +177,7 @@ export class BranchUserController extends Controller { } @Post() - @Security("keycloak", ["system", "head_of_admin", "admin", "branch_admin", "branch_manager"]) + @Security("keycloak", MANAGE_ROLES) async createBranchUser( @Request() req: RequestWithUser, @Path() branchId: string, @@ -143,7 +199,7 @@ export class BranchUserController extends Controller { ]); if ( - !["system", "head_of_admin", "admin"].some((v) => req.user.roles?.includes(v)) && + !globalAllow(req.user) && branch?.createdByUserId !== req.user.sub && !branch?.user.find((v) => v.userId === req.user.sub) ) { @@ -187,10 +243,37 @@ export class BranchUserController extends Controller { } @Delete() - async deleteBranchUser(@Path() branchId: string, @Body() body: BranchUserBody) { + @Security("keycloak", MANAGE_ROLES) + async deleteBranchUser( + @Request() req: RequestWithUser, + @Path() branchId: string, + @Body() body: BranchUserBody, + ) { + const branch = await prisma.branch.findUnique({ + include: { + user: { + where: { userId: req.user.sub }, + }, + }, + where: { id: branchId }, + }); + + if ( + !globalAllow(req.user) && + branch?.createdByUserId !== req.user.sub && + !branch?.user.find((v) => v.userId === req.user.sub) + ) { + throw new HttpError( + HttpStatus.FORBIDDEN, + "You do not have permission to perform this action.", + "noPermission", + ); + } + await prisma.$transaction( body.user.map((v) => prisma.branchUser.deleteMany({ where: { branchId, userId: v } })), ); + await prisma.user.updateMany({ where: { branch: { none: {} }, @@ -200,123 +283,31 @@ export class BranchUserController extends Controller { } @Delete("{userId}") - async deleteBranchUserById(@Path() branchId: string, @Path() userId: string) { - await prisma.branchUser.deleteMany({ - where: { branchId, userId }, - }); - await prisma.user.updateMany({ - where: { - id: userId, - branch: { none: {} }, - }, - data: { code: null }, - }); - } -} - -type UserBranchBody = { branch: string[] }; - -@Route("api/v1/user/{userId}/branch") -@Tags("Branch User") -@Security("keycloak") -export class UserBranchController extends Controller { - @Get() - async getUserBranch( - @Path() userId: string, - @Query() zipCode?: string, - @Query() query: string = "", - @Query() page: number = 1, - @Query() pageSize: number = 30, - ) { - const where = { - OR: [ - { branch: { name: { contains: query }, zipCode }, userId }, - { branch: { nameEN: { contains: query }, zipCode }, userId }, - ], - } satisfies Prisma.BranchUserWhereInput; - - const [result, total] = await prisma.$transaction([ - prisma.branchUser.findMany({ - orderBy: { branch: { createdAt: "asc" } }, - include: { - branch: { - include: { - province: true, - district: true, - subDistrict: true, - headOffice: { - include: { - province: true, - district: true, - subDistrict: true, - }, - }, - }, - }, - }, - where, - take: pageSize, - skip: (page - 1) * pageSize, - }), - prisma.branchUser.count({ where }), - ]); - - return { result: result.map((v) => v.branch), page, pageSize, total }; - } - - @Post() - async createUserBranch( + async deleteBranchUserById( @Request() req: RequestWithUser, + @Path() branchId: string, @Path() userId: string, - @Body() body: UserBranchBody, ) { - const branch = await prisma.branch.findMany({ - include: { user: true }, - where: { id: { in: body.branch } }, + const branch = await prisma.branch.findUnique({ + include: { + user: { + where: { userId: req.user.sub }, + }, + }, + where: { id: branchId }, }); - if (branch.length !== body.branch.length) { + if ( + !globalAllow(req.user) && + branch?.createdByUserId !== req.user.sub && + !branch?.user.find((v) => v.userId === req.user.sub) + ) { throw new HttpError( - HttpStatus.BAD_REQUEST, - "One or more branch cannot be found.", - "oneOrMoreBranchBadReq", + HttpStatus.FORBIDDEN, + "You do not have permission to perform this action.", + "noPermission", ); } - - await prisma.branch.updateMany({ - where: { id: { in: body.branch }, status: Status.CREATED }, - data: { status: Status.ACTIVE }, - }); - - await prisma.branchUser.createMany({ - data: branch - .filter((a) => !a.user.some((b) => b.userId === userId)) - .map((v) => ({ - branchId: v.id, - userId, - createdByUserId: req.user.sub, - updatedByUserId: req.user.sub, - })), - }); - - this.setStatus(HttpStatus.CREATED); - } - - @Delete() - async deleteUserBranch(@Path() userId: string, @Body() body: UserBranchBody) { - await prisma.$transaction( - body.branch.map((v) => prisma.branchUser.deleteMany({ where: { userId, branchId: v } })), - ); - await prisma.user.updateMany({ - where: { - branch: { none: {} }, - }, - data: { code: null }, - }); - } - - @Delete("{branchId}") - async deleteUserBranchById(@Path() branchId: string, @Path() userId: string) { await prisma.branchUser.deleteMany({ where: { branchId, userId }, }); diff --git a/tsoa.json b/tsoa.json index ca7209f..53d9ee0 100644 --- a/tsoa.json +++ b/tsoa.json @@ -20,7 +20,6 @@ { "name": "Permission" }, { "name": "Address" }, { "name": "Branch" }, - { "name": "Branch Contact" }, { "name": "User" }, { "name": "Branch User" }, { "name": "Customer" },