diff --git a/src/controllers/service/service-controller.ts b/src/controllers/service/service-controller.ts new file mode 100644 index 0000000..b6391f0 --- /dev/null +++ b/src/controllers/service/service-controller.ts @@ -0,0 +1,181 @@ +import { + Body, + Controller, + Delete, + Get, + Put, + Path, + Post, + Query, + Request, + Route, + Security, + Tags, +} from "tsoa"; +import { Prisma, Status } from "@prisma/client"; + +import prisma from "../../db"; +import minio from "../../services/minio"; +import { RequestWithUser } from "../../interfaces/user"; +import HttpError from "../../interfaces/http-error"; +import HttpStatus from "../../interfaces/http-status"; + +if (!process.env.MINIO_BUCKET) { + throw Error("Require MinIO bucket."); +} + +const MINIO_BUCKET = process.env.MINIO_BUCKET; + +type ServiceCreate = { + code: string; + name: string; + detail: string; +}; + +type ServiceUpdate = { + code: string; + name: string; + detail: string; +}; + +function imageLocation(id: string) { + return `service/img-${id}`; +} + +@Route("api/service") +@Tags("Service") +@Security("keycloak") +export class ServiceController extends Controller { + @Get() + async getService( + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + OR: [{ name: { contains: query } }, { detail: { contains: query } }], + } satisfies Prisma.ServiceWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.service.findMany({ + orderBy: { createdAt: "asc" }, + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.service.count({ where }), + ]); + + return { + result: await Promise.all( + result.map(async (v) => ({ + ...v, + imageUrl: await minio.presignedGetObject(MINIO_BUCKET, imageLocation(v.id), 12 * 60 * 60), + })), + ), + page, + pageSize, + total, + }; + } + + @Get("{serviceId}") + async getServiceById(@Path() serviceId: string) { + const record = await prisma.service.findFirst({ + where: { id: serviceId }, + }); + + if (!record) + throw new HttpError(HttpStatus.NOT_FOUND, "Service cannot be found.", "data_not_found"); + + return Object.assign(record, { + imageUrl: await minio.presignedGetObject(MINIO_BUCKET, `service/img-${record.id}`, 60 * 60), + }); + } + + @Get("{serviceId}/work") + async getWorkOfService( + @Path() serviceId: string, + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const [result, total] = await prisma.$transaction([ + prisma.work.findMany({ + where: { serviceId }, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.work.count({ where: { serviceId } }), + ]); + return { result, page, pageSize, total }; + } + + @Post() + async createService(@Request() req: RequestWithUser, @Body() body: ServiceCreate) { + const record = await prisma.service.create({ + data: { + ...body, + createdBy: req.user.name, + updateBy: req.user.name, + }, + }); + + this.setStatus(HttpStatus.CREATED); + + return Object.assign(record, { + imageUrl: await minio.presignedGetObject( + MINIO_BUCKET, + imageLocation(record.id), + 12 * 60 * 60, + ), + imageUploadUrl: await minio.presignedPutObject( + MINIO_BUCKET, + imageLocation(record.id), + 12 * 60 * 60, + ), + }); + } + + @Put("{serviceId}") + async editService( + @Request() req: RequestWithUser, + @Body() body: ServiceUpdate, + @Path() serviceId: string, + ) { + if (!(await prisma.service.findUnique({ where: { id: serviceId } }))) { + throw new HttpError(HttpStatus.NOT_FOUND, "Service cannot be found.", "data_not_found"); + } + + const record = await prisma.service.update({ + data: { ...body, updateBy: req.user.name }, + where: { id: serviceId }, + }); + return Object.assign(record, { + profileImageUrl: await minio.presignedGetObject( + MINIO_BUCKET, + imageLocation(record.id), + 12 * 60 * 60, + ), + profileImageUploadUrl: await minio.presignedPutObject( + MINIO_BUCKET, + imageLocation(record.id), + 12 * 60 * 60, + ), + }); + } + + @Delete("{serviceId}") + async deleteService(@Path() serviceId: string) { + const record = await prisma.service.findFirst({ where: { id: serviceId } }); + + if (!record) { + throw new HttpError(HttpStatus.NOT_FOUND, "Service cannot be found.", "data_not_found"); + } + + if (record.status !== Status.CREATED) { + throw new HttpError(HttpStatus.FORBIDDEN, "Service is in used.", "data_in_used"); + } + + return await prisma.service.delete({ where: { id: serviceId } }); + } +}