import { Body, Controller, Delete, Get, Path, Post, Query, Request, Route, Security, Tags, } from "tsoa"; import { RequestWithUser } from "../interfaces/user"; import prisma from "../db"; import { Prisma } from "@prisma/client"; import { queryOrNot } from "../utils/relation"; import { notFoundError } from "../utils/error"; import dayjs from "dayjs"; import { createPermCondition } from "../services/permission"; const permissionCondCompany = createPermCondition((_) => true); @Route("/api/v1/notification") @Tags("Notification") export class NotificationController extends Controller { @Get() @Security("keycloak") async getNotificationList( @Request() req: RequestWithUser, @Query() page: number = 1, @Query() pageSize: number = 30, @Query() query = "", ) { 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: { OR: [ { readByUser: { some: { id: req.user.sub } }, createdAt: { lte: dayjs().subtract(7, "days").toDate() }, }, { deleteByUser: { some: { id: req.user.sub } } }, ], }, }; const [result, total] = await prisma.$transaction([ prisma.notification.findMany({ where, include: { readByUser: true }, orderBy: { createdAt: "desc" }, }), prisma.notification.count({ where }), ]); return { 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, }; } @Get("{notificationId}") @Security("keycloak") async getNotification(@Request() req: RequestWithUser, @Path() notificationId: string) { const record = await prisma.notification.update({ where: { id: notificationId }, data: { readByUser: { connect: { id: req.user.sub }, }, }, }); if (!record) throw notFoundError("Notification"); return record; } @Post("mark-read") @Security("keycloak") async markRead(@Request() req: RequestWithUser, @Body() body?: { id: string[] }) { const record = await prisma.notification.findMany({ where: { id: body ? { in: body.id } : undefined, OR: !body ? [ { receiverId: req.user.sub }, req.user.roles.length > 0 ? { groupReceiver: { some: { name: { in: req.user.roles } } }, registeredBranch: { OR: permissionCondCompany(req.user) }, } : {}, ] : undefined, }, }); await prisma.$transaction( record.map((v) => prisma.notification.update({ where: { id: v.id }, data: { readByUser: { connect: { id: req.user.sub } }, }, }), ), ); } @Delete() @Security("keycloak") async deleteNotificationMany(@Request() req: RequestWithUser, @Body() notificationId: string[]) { if (!notificationId.length) return; return await prisma.notification .findMany({ where: { id: { in: notificationId } } }) .then(async (v) => { await prisma.$transaction( v.map((v) => prisma.notification.update({ where: { id: v.id }, data: { deleteByUser: { connect: { id: req.user.sub } }, }, }), ), ); }); } @Delete("{notificationId}") @Security("keycloak") async deleteNotification(@Request() req: RequestWithUser, @Path() notificationId: string) { const record = await prisma.notification.findFirst({ where: { id: notificationId } }); if (!record) throw notFoundError("Notification"); return await prisma.notification.update({ where: { id: notificationId }, data: { deleteByUser: { connect: { id: req.user.sub }, }, }, }); } }