From 41c27dced5f7dd83bf480976c46764670488edeb Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 10:53:52 +0700 Subject: [PATCH 01/10] feat: customer create endpoint --- src/controllers/customer-controller.ts | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/controllers/customer-controller.ts diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts new file mode 100644 index 0000000..97f3625 --- /dev/null +++ b/src/controllers/customer-controller.ts @@ -0,0 +1,63 @@ +import { Prisma, Status } from "@prisma/client"; +import { Body, Controller, Delete, Get, Path, Post, Put, Query, Request, Route, Tags } from "tsoa"; +import { RequestWithUser } from "../interfaces/user"; +import prisma from "../db"; +import minio from "../services/minio"; +import HttpStatus from "../interfaces/http-status"; +import HttpError from "../interfaces/http-error"; + +if (!process.env.MINIO_BUCKET) { + throw Error("Require MinIO bucket."); +} + +const MINIO_BUCKET = process.env.MINIO_BUCKET; + +export type CustomerCreate = { + code?: string; + status?: Status; + customerType: string; + customerName: string; + customerNameEN: string; +}; + +export type CustomerUpdate = { + code?: string; + status?: "ACTIVE" | "INACTIVE"; + customerType?: string; + customerName?: string; + customerNameEN?: string; +}; + +function imageLocation(id: string) { + return `customer/img-${id}`; +} + +@Route("api/customer") +@Tags("Customer") +export class CustomerController extends Controller { + @Post() + async create(@Request() req: RequestWithUser, @Body() body: CustomerCreate) { + const record = await prisma.customer.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, + ), + }); + } +} From 62bbc0a0712328e366e8426d3a8d9c650740a22f Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 10:57:14 +0700 Subject: [PATCH 02/10] fix: missing auth --- src/controllers/customer-controller.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index 97f3625..d993eb5 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -34,6 +34,7 @@ function imageLocation(id: string) { @Route("api/customer") @Tags("Customer") +@Security("keycloak") export class CustomerController extends Controller { @Post() async create(@Request() req: RequestWithUser, @Body() body: CustomerCreate) { From 578fc225d964423d5c0fe764242eeb2ddd62a971 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 10:57:43 +0700 Subject: [PATCH 03/10] chore: format --- src/controllers/customer-controller.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index d993eb5..68ce96c 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -1,5 +1,19 @@ import { Prisma, Status } from "@prisma/client"; import { Body, Controller, Delete, Get, Path, Post, Put, Query, Request, Route, Tags } from "tsoa"; +import { + Body, + Controller, + Delete, + Get, + Path, + Post, + Put, + Query, + Request, + Route, + Security, + Tags, +} from "tsoa"; import { RequestWithUser } from "../interfaces/user"; import prisma from "../db"; import minio from "../services/minio"; From e76650bfce5ec89dab6fe287aa3ffed725aedb72 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:00:31 +0700 Subject: [PATCH 04/10] feat: list customer --- src/controllers/customer-controller.ts | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index 68ce96c..a02da59 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -50,6 +50,38 @@ function imageLocation(id: string) { @Tags("Customer") @Security("keycloak") export class CustomerController extends Controller { + @Get() + async list( + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + OR: [{ customerName: { contains: query } }, { customerNameEN: { contains: query } }], + } satisfies Prisma.CustomerWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.customer.findMany({ + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.customer.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, + }; + } + @Post() async create(@Request() req: RequestWithUser, @Body() body: CustomerCreate) { const record = await prisma.customer.create({ From 239582b4722ea6b9a2c48f1915c1f59d60ec5564 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:00:44 +0700 Subject: [PATCH 05/10] feat: list customer by id --- src/controllers/customer-controller.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index a02da59..74748bf 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -82,6 +82,14 @@ export class CustomerController extends Controller { }; } + @Get("{customerId}") + async getById(@Path() customerId: string) { + const record = await prisma.customer.findFirst({ where: { id: customerId } }); + if (!record) + throw new HttpError(HttpStatus.NOT_FOUND, "Customer cannot be found.", "data_not_found"); + return record; + } + @Post() async create(@Request() req: RequestWithUser, @Body() body: CustomerCreate) { const record = await prisma.customer.create({ From 6e07e0658eb6d0309d3fb4d419214ab188e69109 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:02:23 +0700 Subject: [PATCH 06/10] feat: delete customer --- src/controllers/customer-controller.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index 74748bf..e11957c 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -115,4 +115,19 @@ export class CustomerController extends Controller { ), }); } + + @Delete("{customerId}") + async deleteById(@Path() customerId: string) { + const record = await prisma.customer.findFirst({ where: { id: customerId } }); + + if (!record) { + throw new HttpError(HttpStatus.NOT_FOUND, "Customer cannot be found.", "data_not_found"); + } + + if (record.status !== Status.CREATED) { + throw new HttpError(HttpStatus.FORBIDDEN, "Customer is in used.", "data_in_used"); + } + + return await prisma.customer.delete({ where: { id: customerId } }); + } } From f9fdfce9bacc7449251a0ffd31b143d5eb75ef02 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:02:40 +0700 Subject: [PATCH 07/10] fix: bad commit 578fc225 --- src/controllers/customer-controller.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index e11957c..e93c2ae 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -1,5 +1,4 @@ import { Prisma, Status } from "@prisma/client"; -import { Body, Controller, Delete, Get, Path, Post, Put, Query, Request, Route, Tags } from "tsoa"; import { Body, Controller, From 7bd3c2ebd35180e8cfbfe79c3e430ba431467134 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:06:01 +0700 Subject: [PATCH 08/10] fix: missing image url --- src/controllers/customer-controller.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index e93c2ae..acc12a2 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -86,7 +86,13 @@ export class CustomerController extends Controller { const record = await prisma.customer.findFirst({ where: { id: customerId } }); if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "Customer cannot be found.", "data_not_found"); - return record; + return Object.assign(record, { + imageUrl: await minio.presignedGetObject( + MINIO_BUCKET, + imageLocation(record.id), + 12 * 60 * 60, + ), + }); } @Post() From ef88a48d0cf3cd335e8df1fdd7807650fec784ae Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:18:01 +0700 Subject: [PATCH 09/10] feat: edit customer endpoint --- src/controllers/customer-controller.ts | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/controllers/customer-controller.ts b/src/controllers/customer-controller.ts index acc12a2..fe7d347 100644 --- a/src/controllers/customer-controller.ts +++ b/src/controllers/customer-controller.ts @@ -121,6 +121,39 @@ export class CustomerController extends Controller { }); } + @Put("{customerId}") + async editById( + @Path() customerId: string, + @Request() req: RequestWithUser, + @Body() body: CustomerUpdate, + ) { + const record = await prisma.customer.update({ + where: { id: customerId }, + data: { + ...body, + createdBy: req.user.name, + updateBy: req.user.name, + }, + }); + + if (!record) { + throw new HttpError(HttpStatus.NOT_FOUND, "Customer cannot be found."); + } + + 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, + ), + }); + } + @Delete("{customerId}") async deleteById(@Path() customerId: string) { const record = await prisma.customer.findFirst({ where: { id: customerId } }); From d5ce9a4bb8b15aa2b4c9e68de7d65dead8acdbf8 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:18:36 +0700 Subject: [PATCH 10/10] chore: add tags to open api spec (for sorting purpose) --- tsoa.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tsoa.json b/tsoa.json index 2f059de..92b82d2 100644 --- a/tsoa.json +++ b/tsoa.json @@ -12,6 +12,19 @@ "description": "Keycloak Bearer Token", "in": "header" } + }, + "spec": { + "tags": [ + { "name": "OpenAPI" }, + { "name": "Address" }, + { "name": "Branch" }, + { "name": "User" }, + { "name": "Branch User" }, + { "name": "User Branch" }, + { "name": "Customer" }, + { "name": "Customer Branch" }, + { "name": "Employee" } + ] } }, "routes": {