diff --git a/prisma/migrations/20250305041645_add_noti_perm_related_field/migration.sql b/prisma/migrations/20250305041645_add_noti_perm_related_field/migration.sql new file mode 100644 index 0000000..95388f6 --- /dev/null +++ b/prisma/migrations/20250305041645_add_noti_perm_related_field/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "Notification" ADD COLUMN "registeredBranchId" TEXT; + +-- AddForeignKey +ALTER TABLE "Notification" ADD CONSTRAINT "Notification_registeredBranchId_fkey" FOREIGN KEY ("registeredBranchId") REFERENCES "Branch"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5cfd276..671b21d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -21,6 +21,9 @@ model Notification { groupReceiver NotificationGroup[] + registeredBranchId String? + registeredBranch Branch? @relation(fields: [registeredBranchId], references: [id]) + receiver User? @relation(name: "NotificationReceiver", fields: [receiverId], references: [id], onDelete: Cascade) receiverId String? @@ -313,6 +316,7 @@ model Branch { quotation Quotation[] workflowTemplate WorkflowTemplate[] taskOrder TaskOrder[] + notification Notification[] } model BranchBank { diff --git a/src/controllers/00-notification-controller.ts b/src/controllers/00-notification-controller.ts index 1718e04..00baff7 100644 --- a/src/controllers/00-notification-controller.ts +++ b/src/controllers/00-notification-controller.ts @@ -14,10 +14,19 @@ import { } from "tsoa"; import { RequestWithUser } from "../interfaces/user"; import HttpStatus from "../interfaces/http-status"; +import prisma from "../db"; +import { Prisma } from "@prisma/client"; +import { queryOrNot } from "../utils/relation"; +import { notFoundError } from "../utils/error"; +import dayjs from "dayjs"; +import HttpError from "../interfaces/http-error"; +import { createPermCondition } from "../services/permission"; type NotificationCreate = {}; type NotificationUpdate = {}; +const permissionCondCompany = createPermCondition((_) => true); + @Route("/api/v1/notification") @Tags("Notification") export class NotificationController extends Controller { @@ -29,12 +38,44 @@ export class NotificationController extends Controller { @Query() pageSize: number = 30, @Query() query = "", ) { - const total = 0; - - // TODO: implement + const where: Prisma.NotificationWhereInput = { + AND: [ + { + OR: queryOrNot<(typeof where)[]>(query, [ + { title: { contains: query } }, + { detail: { contains: query } }, + ]), + }, + { + OR: [ + { receiverId: req.user.sub }, + req.user.roles.length > 0 + ? { + groupReceiver: { some: { name: { in: req.user.roles } } }, + registeredBranch: { OR: permissionCondCompany(req.user) }, + } + : {}, + ], + }, + ], + NOT: { + readByUser: { some: { id: req.user.sub } }, + createdAt: dayjs().subtract(7, "days").toDate(), + }, + }; + const [result, total] = await prisma.$transaction([ + prisma.notification.findMany({ where, include: { readByUser: true } }), + prisma.notification.count({ where }), + ]); return { - result: [], + result: result.map((v) => ({ + id: v.id, + title: v.title, + detail: v.detail, + createdAt: v.createdAt, + read: v.readByUser.some((v) => v.id === req.user.sub), + })), page, pageSize, total, @@ -44,9 +85,18 @@ export class NotificationController extends Controller { @Get("{notificationId}") @Security("keycloak") async getNotification(@Request() req: RequestWithUser, @Path() notificationId: string) { - // TODO: implement + const record = await prisma.notification.update({ + where: { id: notificationId }, + data: { + readByUser: { + connect: { id: req.user.sub }, + }, + }, + }); - return {}; + if (!record) throw notFoundError("Notification"); + + return record; } @Post() @@ -54,8 +104,9 @@ export class NotificationController extends Controller { async createNotification(@Request() req: RequestWithUser, @Body() body: NotificationCreate) { // TODO: implement - this.setStatus(HttpStatus.CREATED); - return {}; + // this.setStatus(HttpStatus.CREATED); + + throw new HttpError(HttpStatus.NOT_IMPLEMENTED, "Not implemented.", "notImplemented"); } @Put("{notificationId}") @@ -67,14 +118,14 @@ export class NotificationController extends Controller { ) { // TODO: implement - return {}; + throw new HttpError(HttpStatus.NOT_IMPLEMENTED, "Not implemented.", "notImplemented"); } @Delete("{notificationId}") @Security("keycloak") async deleteNotification(@Request() req: RequestWithUser, @Path() notificationId: string) { - // TODO: implement - - return {}; + const record = await prisma.notification.deleteMany({ where: { id: notificationId } }); + if (record.count === 0) throw notFoundError("Notification"); + return record; } }