diff --git a/src/controllers/01-branch-controller.ts b/src/controllers/01-branch-controller.ts index 6db3b60..1b821ed 100644 --- a/src/controllers/01-branch-controller.ts +++ b/src/controllers/01-branch-controller.ts @@ -18,17 +18,19 @@ import prisma from "../db"; import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; import { RequestWithUser } from "../interfaces/user"; -import minio from "../services/minio"; -import { isSystem } from "../utils/keycloak"; -import { deleteFile, deleteFolder, fileLocation, listFile } from "../utils/minio"; -import { createPermCheck, createPermCondition } from "../services/permission"; +import { deleteFile, deleteFolder, fileLocation, getFile, listFile, setFile } from "../utils/minio"; +import { + branchRelationPermInclude, + createPermCheck, + createPermCondition, +} from "../services/permission"; import { filterStatus } from "../services/prisma"; +import { connectOrDisconnect, connectOrNot } from "../utils/relation"; if (!process.env.MINIO_BUCKET) { throw Error("Require MinIO bucket."); } -const MINIO_BUCKET = process.env.MINIO_BUCKET; const MANAGE_ROLES = ["system", "head_of_admin"]; function globalAllow(user: RequestWithUser["user"]) { @@ -401,10 +403,10 @@ export class BranchController extends Controller { telephoneNo: v, })), }, - province: { connect: provinceId ? { id: provinceId } : undefined }, - district: { connect: districtId ? { id: districtId } : undefined }, - subDistrict: { connect: subDistrictId ? { id: subDistrictId } : undefined }, - headOffice: { connect: headOfficeId ? { id: headOfficeId } : undefined }, + province: connectOrNot(provinceId), + district: connectOrNot(districtId), + subDistrict: connectOrNot(subDistrictId), + headOffice: connectOrNot(headOfficeId), createdBy: { connect: { id: req.user.sub } }, updatedBy: { connect: { id: req.user.sub } }, }, @@ -483,9 +485,8 @@ export class BranchController extends Controller { }) : []; - await minio.removeObjects( - MINIO_BUCKET, - listDeleted.map((v) => fileLocation.branch.bank(v.branchId, v.id)), + await Promise.all( + listDeleted.map((v) => deleteFile(fileLocation.branch.bank(v.branchId, v.id))), ); return await prisma.branch.update({ @@ -513,22 +514,10 @@ export class BranchController extends Controller { })), } : undefined, - province: { - connect: provinceId ? { id: provinceId } : undefined, - disconnect: provinceId === null || undefined, - }, - district: { - connect: districtId ? { id: districtId } : undefined, - disconnect: districtId === null || undefined, - }, - subDistrict: { - connect: subDistrictId ? { id: subDistrictId } : undefined, - disconnect: subDistrictId === null || undefined, - }, - headOffice: { - connect: headOfficeId ? { id: headOfficeId } : undefined, - disconnect: headOfficeId === null || undefined, - }, + province: connectOrDisconnect(provinceId), + district: connectOrDisconnect(districtId), + subDistrict: connectOrDisconnect(subDistrictId), + headOffice: connectOrDisconnect(headOfficeId), contact: contact ? { deleteMany: {}, @@ -548,15 +537,7 @@ export class BranchController extends Controller { @Security("keycloak", MANAGE_ROLES) async deleteBranch(@Request() req: RequestWithUser, @Path() branchId: string) { const record = await prisma.branch.findUnique({ - include: { - headOffice: { - include: { - branch: { where: { user: { some: { userId: req.user.sub } } } }, - user: { where: { userId: req.user.sub } }, - }, - }, - user: { where: { userId: req.user.sub } }, - }, + include: branchRelationPermInclude(req.user), where: { id: branchId }, }); @@ -564,28 +545,7 @@ export class BranchController extends Controller { throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found.", "branchNotFound"); } - if (!isSystem(req.user)) { - if (!globalAllow(req.user) && record.user.length === 0) { - throw new HttpError( - HttpStatus.FORBIDDEN, - "You do not have permission to perform this action.", - "noPermission", - ); - } else { - if ( - (record.user.length === 0 && !record.headOffice) || - (record.headOffice && - record.headOffice.user.length === 0 && - record.headOffice.branch.length === 0) - ) { - throw new HttpError( - HttpStatus.FORBIDDEN, - "You do not have permission to perform this action.", - "noPermission", - ); - } - } - } + await permissionCheck(req.user, record); if (!record) { throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found.", "branchNotFound"); @@ -619,149 +579,111 @@ export class BranchController extends Controller { await Promise.all([ deleteFolder(fileLocation.branch.img(branchId)), - minio.removeObject(MINIO_BUCKET, fileLocation.branch.line(branchId), { - forceDelete: true, - }), - ...data.bank.map(async (v) => { - await minio.removeObject(MINIO_BUCKET, fileLocation.branch.bank(branchId, v.id), { - forceDelete: true, - }); - }), + deleteFile(fileLocation.branch.line(branchId)), + ...data.bank.map((v) => deleteFile(fileLocation.branch.bank(branchId, v.id))), ]); return data; }); } +} - @Get("{branchId}/line-image") - async getLineImageByBranchId(@Request() req: RequestWithUser, @Path() branchId: string) { - const url = await minio.presignedGetObject( - MINIO_BUCKET, - fileLocation.branch.line(branchId), - 60 * 60, - ); - return req.res?.redirect(url); - } - - @Put("{branchId}/line-image") - @Security("keycloak", MANAGE_ROLES.concat("admin", "branch_manager")) - async setLineImageByBranchId(@Request() req: RequestWithUser, @Path() branchId: string) { - await permissionCheck(req.user, branchId); - return req.res?.redirect( - await minio.presignedPutObject( - MINIO_BUCKET, - fileLocation.branch.line(branchId), - 12 * 60 * 60, - ), - ); - } - - @Delete("{branchId}/line-image") - @Security("keycloak", MANAGE_ROLES.concat("admin", "branch_manager")) - async deleteLineImage(@Request() req: RequestWithUser, @Path() branchId: string) { - await permissionCheck(req.user, branchId); - - await deleteFile(fileLocation.branch.line(branchId)); - } - - @Get("{branchId}/bank-qr/{bankId}") - async getBankQRByBranchIdAndBankId( - @Request() req: RequestWithUser, - @Path() branchId: string, - @Path() bankId: string, - ) { - const url = await minio.presignedGetObject( - MINIO_BUCKET, - fileLocation.branch.bank(branchId, bankId), - 60 * 60, - ); - return req.res?.redirect(url); - } - - @Put("{branchId}/bank-qr/{bankId}") - @Security("keycloak", MANAGE_ROLES.concat("admin", "branch_manager")) - async setBankQRByBranchIdAndBankId( - @Request() req: RequestWithUser, - @Path() branchId: string, - @Path() bankId: string, - ) { - await permissionCheck(req.user, branchId); - return req.res?.redirect( - await minio.presignedPutObject( - MINIO_BUCKET, - fileLocation.branch.bank(branchId, bankId), - 12 * 60 * 60, - ), - ); - } - - @Delete("{branchId}/bank-qr/{bankId}") - @Security("keycloak", MANAGE_ROLES.concat("admin", "branch_manager")) - async deleteImage( - @Request() req: RequestWithUser, - @Path() branchId: string, - @Path() bankId: string, - ) { - await permissionCheck(req.user, branchId); - await deleteFile(fileLocation.branch.bank(branchId, bankId)); - } - - @Get("{branchId}/image") - @Security("keycloak") - async listImage(@Path() branchId: string) { - const record = await prisma.branch.findFirst({ - where: { id: branchId }, +@Route("api/v1/branch/{branchId}") +@Tags("Branch") +export class BranchFileController extends Controller { + private async checkPermission(user: RequestWithUser["user"], id: string) { + const data = await prisma.branch.findUnique({ + include: branchRelationPermInclude(user), + where: { id }, }); - - if (!record) { + if (!data) { throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found.", "branchNotFound"); } + await permissionCheck(user, data); + } + @Get("image") + @Security("keycloak") + async listImage(@Request() req: RequestWithUser, @Path() branchId: string) { + await this.checkPermission(req.user, branchId); return await listFile(fileLocation.branch.img(branchId)); } - @Get("{branchId}/image/{name}") - async getImageByName( - @Request() req: RequestWithUser, - @Path() branchId: string, - @Path() name: string, - ) { - return req.res?.redirect( - await minio.presignedGetObject( - MINIO_BUCKET, - fileLocation.branch.img(branchId, name), - 12 * 60 * 60, - ), - ); + @Get("image/{name}") + async getImage(@Request() req: RequestWithUser, @Path() branchId: string, @Path() name: string) { + return req.res?.redirect(await getFile(fileLocation.branch.img(branchId, name))); } - @Put("{branchId}/image/{name}") + @Put("image/{name}") @Security("keycloak") - async putImageByName( - @Request() req: RequestWithUser, - @Path() branchId: string, - @Path() name: string, - ) { - await permissionCheck(req.user, branchId); - return req.res?.redirect( - await minio.presignedPutObject( - MINIO_BUCKET, - fileLocation.branch.img(branchId, name), - 12 * 60 * 60, - ), - ); + async putImage(@Request() req: RequestWithUser, @Path() branchId: string, @Path() name: string) { + if (!req.headers["content-type"]?.startsWith("image/")) { + throw new HttpError(HttpStatus.BAD_REQUEST, "Not a valid image.", "notValidImage"); + } + await this.checkPermission(req.user, branchId); + return req.res?.redirect(await setFile(fileLocation.branch.img(branchId, name))); } - @Delete("{branchId}/image/{name}") + @Delete("image/{name}") @Security("keycloak") - async deleteImageByName( + async delImage(@Request() req: RequestWithUser, @Path() branchId: string, @Path() name: string) { + await this.checkPermission(req.user, branchId); + return await deleteFile(fileLocation.branch.img(branchId, name)); + } + + @Get("bank-qr/{bankId}") + async getBankImage( @Request() req: RequestWithUser, @Path() branchId: string, - @Path() name: string, + @Path() bankId: string, ) { - await permissionCheck(req.user, branchId); - await minio.removeObject(MINIO_BUCKET, fileLocation.branch.img(branchId, name), { - forceDelete: true, - }); + return req.res?.redirect(await getFile(fileLocation.branch.bank(branchId, bankId))); + } + + @Put("bank-qr/{bankId}") + @Security("keycloak") + async putBankImage( + @Request() req: RequestWithUser, + @Path() branchId: string, + @Path() bankId: string, + ) { + if (!req.headers["content-type"]?.startsWith("image/")) { + throw new HttpError(HttpStatus.BAD_REQUEST, "Not a valid image.", "notValidImage"); + } + await this.checkPermission(req.user, branchId); + return req.res?.redirect(await setFile(fileLocation.branch.bank(branchId, bankId))); + } + + @Delete("bank-qr/{bankId}") + @Security("keycloak") + async delBankImage( + @Request() req: RequestWithUser, + @Path() branchId: string, + @Path() bankId: string, + ) { + await this.checkPermission(req.user, branchId); + return await deleteFile(fileLocation.branch.bank(branchId, bankId)); + } + + @Get("line-image") + async getLineImage(@Request() req: RequestWithUser, @Path() branchId: string) { + return req.res?.redirect(await getFile(fileLocation.branch.line(branchId))); + } + + @Put("line-image") + @Security("keycloak") + async putLineImage(@Request() req: RequestWithUser, @Path() branchId: string) { + if (!req.headers["content-type"]?.startsWith("image/")) { + throw new HttpError(HttpStatus.BAD_REQUEST, "Not a valid image.", "notValidImage"); + } + await this.checkPermission(req.user, branchId); + return req.res?.redirect(await setFile(fileLocation.branch.line(branchId))); + } + + @Delete("line-image") + @Security("keycloak") + async delLineImage(@Request() req: RequestWithUser, @Path() branchId: string) { + await this.checkPermission(req.user, branchId); + return await deleteFile(fileLocation.branch.line(branchId)); } }