From ed832148fcff89f7bfbc8746fd21e814df49951f Mon Sep 17 00:00:00 2001 From: Methapon Metanipat Date: Tue, 10 Sep 2024 09:56:46 +0700 Subject: [PATCH] feat: upload and select multiple image --- .../migration.sql | 2 + prisma/schema.prisma | 2 + src/controllers/03-customer-controller.ts | 95 ++++++++++++++----- src/utils/minio.ts | 3 + 4 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 prisma/migrations/20240910025635_add_image_field/migration.sql diff --git a/prisma/migrations/20240910025635_add_image_field/migration.sql b/prisma/migrations/20240910025635_add_image_field/migration.sql new file mode 100644 index 0000000..2fc5818 --- /dev/null +++ b/prisma/migrations/20240910025635_add_image_field/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Customer" ADD COLUMN "selectedImage" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a2ca59c..bfcfad5 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -418,6 +418,8 @@ model Customer { registeredBranchId String? registeredBranch Branch? @relation(fields: [registeredBranchId], references: [id]) + selectedImage String? + createdAt DateTime @default(now()) createdBy User? @relation(name: "CustomerCreatedByUser", fields: [createdByUserId], references: [id], onDelete: SetNull) createdByUserId String? diff --git a/src/controllers/03-customer-controller.ts b/src/controllers/03-customer-controller.ts index b2c4545..a92c677 100644 --- a/src/controllers/03-customer-controller.ts +++ b/src/controllers/03-customer-controller.ts @@ -15,12 +15,13 @@ import { } from "tsoa"; import { RequestWithUser } from "../interfaces/user"; import prisma from "../db"; -import minio, { deleteFolder, presignedGetObjectIfExist } from "../services/minio"; +import minio, { deleteFolder } from "../services/minio"; import HttpStatus from "../interfaces/http-status"; import HttpError from "../interfaces/http-error"; import { isSystem } from "../utils/keycloak"; import { branchRelationPermInclude, createPermCheck } from "../services/permission"; import { filterStatus } from "../services/prisma"; +import { fileLocation, listFile } from "../utils/minio"; if (!process.env.MINIO_BUCKET) { throw Error("Require MinIO bucket."); @@ -74,10 +75,6 @@ export type CustomerUpdate = { birthDate?: Date; }; -function imageLocation(id: string) { - return `customer/${id}/profile-image`; -} - @Route("api/v1/customer") @Tags("Customer") export class CustomerController extends Controller { @@ -397,22 +394,46 @@ export class CustomerController extends Controller { async (data) => await deleteFolder(MINIO_BUCKET, `customer/${customerId}`).then(() => data), ); } +} - @Get("{customerId}/image") - async getCustomerImageById(@Request() req: RequestWithUser, @Path() customerId: string) { - const url = await presignedGetObjectIfExist(MINIO_BUCKET, imageLocation(customerId), 60 * 60); - - if (!url) { - throw new HttpError(HttpStatus.NOT_FOUND, "Image cannot be found", "imageNotFound"); +@Route("api/v1/customer/{customerId}/image") +@Tags("Customer") +export class CustomerImageController extends Controller { + @Get() + @Security("keycloak") + async listImage(@Path() customerId: string) { + const customer = await prisma.customer.findUnique({ + where: { id: customerId }, + }); + if (!customer) { + throw new HttpError(HttpStatus.NOT_FOUND, "Customer cannot be found", "customerNotFound"); } - - return req.res?.redirect(url); + return await listFile(fileLocation.customer.img(customerId)); } - @Put("{customerId}/image") - @Security("keycloak", MANAGE_ROLES) - async setCustomerImageById(@Request() req: RequestWithUser, @Path() customerId: string) { - const record = await prisma.customer.findFirst({ + @Get("{name}") + async getImage( + @Request() req: RequestWithUser, + @Path() customerId: string, + @Path() name: string, + ) { + return req.res?.redirect( + await minio.presignedGetObject( + MINIO_BUCKET, + fileLocation.customer.img(customerId, name), + 12 * 60 * 60, + ), + ); + } + + @Put("{name}") + @Security("keycloak") + async putImage( + @Request() req: RequestWithUser, + @Path() customerId: string, + @Path() name: string, + ) { + const customer = await prisma.customer.findUnique({ where: { id: customerId }, include: { registeredBranch: { @@ -420,15 +441,41 @@ export class CustomerController extends Controller { }, }, }); - - if (!record) { - throw new HttpError(HttpStatus.NOT_FOUND, "Customer cannot be found.", "customerNotFound"); + if (!customer) { + throw new HttpError(HttpStatus.NOT_FOUND, "Image cannot be found", "imageNotFound"); } - - await permissionCheck(req.user, record.registeredBranch); - + console.log(customer.registeredBranch); + await permissionCheck(req.user, customer.registeredBranch); return req.res?.redirect( - await minio.presignedPutObject(MINIO_BUCKET, imageLocation(customerId), 12 * 60 * 60), + await minio.presignedPutObject( + MINIO_BUCKET, + fileLocation.customer.img(customerId, name), + 12 * 60 * 60, + ), ); } + + @Delete("{name}") + @Security("keycloak") + async deleteImage( + @Request() req: RequestWithUser, + @Path() customerId: string, + @Path() name: string, + ) { + const customer = await prisma.customer.findUnique({ + where: { id: customerId }, + include: { + registeredBranch: { + include: branchRelationPermInclude(req.user), + }, + }, + }); + if (!customer) { + throw new HttpError(HttpStatus.NOT_FOUND, "Image cannot be found", "imageNotFound"); + } + await permissionCheck(req.user, customer.registeredBranch); + await minio.removeObject(MINIO_BUCKET, fileLocation.customer.img(customerId, name), { + forceDelete: true, + }); + } } diff --git a/src/utils/minio.ts b/src/utils/minio.ts index 7fccef3..9635e21 100644 --- a/src/utils/minio.ts +++ b/src/utils/minio.ts @@ -50,4 +50,7 @@ export const fileLocation = { profile: (userId: string, name?: string) => `user/profile-image-${userId}/${name || ""}`, attachment: (userId: string, name?: string) => `user/attachment-${userId}/${name || ""}`, }, + customer: { + img: (customerId: string, name?: string) => `customer/img-${customerId}/${name || ""}`, + }, };