diff --git a/prisma/migrations/20241024085453_add_field_to_workflow/migration.sql b/prisma/migrations/20241024085453_add_field_to_workflow/migration.sql new file mode 100644 index 0000000..0a23d55 --- /dev/null +++ b/prisma/migrations/20241024085453_add_field_to_workflow/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - Added the required column `registeredBranchId` to the `WorkflowTemplate` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "WorkflowTemplate" ADD COLUMN "registeredBranchId" TEXT NOT NULL; + +-- AddForeignKey +ALTER TABLE "WorkflowTemplate" ADD CONSTRAINT "WorkflowTemplate_registeredBranchId_fkey" FOREIGN KEY ("registeredBranchId") REFERENCES "Branch"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 85b54c7..19ca1a7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -259,6 +259,7 @@ model Branch { customerRegistration Customer[] productGroup ProductGroup[] quotation Quotation[] + workflowTemplate WorkflowTemplate[] } model BranchBank { @@ -894,6 +895,9 @@ model WorkflowTemplate { step WorkflowTemplateStep[] + registeredBranch Branch @relation(fields: [registeredBranchId], references: [id]) + registeredBranchId String + status Status @default(CREATED) statusOrder Int @default(0) diff --git a/src/controllers/04-flow-template-controller.ts b/src/controllers/04-flow-template-controller.ts index 36ffd65..2941402 100644 --- a/src/controllers/04-flow-template-controller.ts +++ b/src/controllers/04-flow-template-controller.ts @@ -1,6 +1,28 @@ -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 { Prisma } from "@prisma/client"; +import { + branchRelationPermInclude, + createPermCheck, + createPermCondition, +} from "../services/permission"; +import HttpError from "../interfaces/http-error"; +import HttpStatus from "../interfaces/http-status"; +import { notFoundError } from "../utils/error"; type WorkflowPayload = { name: string; @@ -10,19 +32,39 @@ type WorkflowPayload = { value?: string[]; responsiblePersonId?: string[]; }[]; + registeredBranchId?: string; }; +const permissionCondCompany = createPermCondition((_) => true); +const permissionCheckCompany = createPermCheck((_) => true); + @Route("api/v1/workflow-template") @Tags("Workflow") +@Security("keycloak") export class FlowTemplateController extends Controller { @Get() async getFlowTemplate( - @Request() _req: RequestWithUser, + @Request() req: RequestWithUser, @Query() page: number = 1, @Query() pageSize: number = 30, + @Query() query = "", ) { + const where = { + OR: [ + { name: { contains: query } }, + { + step: { + some: { name: { contains: query } }, + }, + }, + ], + registeredBranch: { + OR: permissionCondCompany(req.user), + }, + } satisfies Prisma.WorkflowTemplateWhereInput; const [result, total] = await prisma.$transaction([ prisma.workflowTemplate.findMany({ + where, include: { step: { include: { @@ -37,7 +79,7 @@ export class FlowTemplateController extends Controller { take: pageSize, skip: (page - 1) * pageSize, }), - prisma.workflowTemplate.count(), + prisma.workflowTemplate.count({ where }), ]); return { result, page, pageSize, total }; } @@ -61,10 +103,29 @@ export class FlowTemplateController extends Controller { } @Post() - async createFlowTemplate(@Request() _req: RequestWithUser, @Body() body: WorkflowPayload) { + async createFlowTemplate(@Request() req: RequestWithUser, @Body() body: WorkflowPayload) { + const userAffiliatedBranch = await prisma.branch.findFirst({ + include: branchRelationPermInclude(req.user), + where: body.registeredBranchId + ? { id: body.registeredBranchId } + : { + user: { some: { userId: req.user.sub } }, + }, + }); + if (!userAffiliatedBranch) { + throw new HttpError( + HttpStatus.BAD_REQUEST, + "You must be affilated with at least one branch or specifiy branch to be registered (System permission required).", + "reqMinAffilatedBranch", + ); + } + + await permissionCheckCompany(req.user, userAffiliatedBranch); + return await prisma.workflowTemplate.create({ data: { ...body, + registeredBranchId: userAffiliatedBranch.id, step: { create: body.step.map((v, i) => ({ type: v.type, @@ -88,10 +149,23 @@ export class FlowTemplateController extends Controller { @Put("{templateId}") async updateFlowTemplate( - @Request() _req: RequestWithUser, + @Request() req: RequestWithUser, @Path() templateId: string, @Body() body: WorkflowPayload, ) { + const record = await prisma.workflowTemplate.findUnique({ + where: { id: templateId }, + include: { + registeredBranch: { + include: branchRelationPermInclude(req.user), + }, + }, + }); + + if (!record) throw notFoundError("Workflow"); + + await permissionCheckCompany(req.user, record.registeredBranch); + return await prisma.workflowTemplate.update({ where: { id: templateId }, data: { @@ -114,7 +188,20 @@ export class FlowTemplateController extends Controller { } @Delete("{templateId}") - async deleteFlowTemplateById(@Path() templateId: string) { + async deleteFlowTemplateById(@Request() req: RequestWithUser, @Path() templateId: string) { + const record = await prisma.workflowTemplate.findUnique({ + where: { id: templateId }, + include: { + registeredBranch: { + include: branchRelationPermInclude(req.user), + }, + }, + }); + + if (!record) throw notFoundError("Workflow"); + + await permissionCheckCompany(req.user, record.registeredBranch); + return await prisma.workflowTemplate.delete({ where: { id: templateId }, });