Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions src/api/ai_workflow/aiWorkflow.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Injectable, BadRequestException } from '@nestjs/common';
import { Injectable, BadRequestException, Logger } from '@nestjs/common';
import { PrismaService } from '../../shared/modules/global/prisma.service';
import { CreateAiWorkflowDto } from '../../dto/aiWorkflow.dto';
import { CreateAiWorkflowDto, UpdateAiWorkflowDto } from '../../dto/aiWorkflow.dto';
import { ScorecardStatus } from 'src/dto/scorecard.dto';

@Injectable()
export class AiWorkflowService {
private readonly logger: Logger = new Logger(AiWorkflowService.name);
constructor(private readonly prisma: PrismaService) {}

async scorecardExists(scorecardId: string): Promise<boolean> {
Expand All @@ -27,13 +28,15 @@ export class AiWorkflowService {

const scorecardExists = await this.scorecardExists(scorecardId);
if (!scorecardExists) {
this.logger.error(`Active scorecard with id ${scorecardId} does not exist.`);
throw new BadRequestException(
`Active scorecard with id ${scorecardId} does not exist.`,
);
}

const llmExists = await this.llmModelExists(llmId);
if (!llmExists) {
this.logger.error(`LLM model with id ${llmId} does not exist.`);
throw new BadRequestException(
`LLM model with id ${llmId} does not exist.`,
);
Expand All @@ -57,8 +60,52 @@ export class AiWorkflowService {
where: { id },
});
if (!workflow) {
this.logger.error(`AI workflow with id ${id} not found.`);
throw new Error(`AI workflow with id ${id} not found.`);
}
return workflow;
}

async updateWorkflow(
id: string,
updateDto: UpdateAiWorkflowDto,
updatedBy?: string,
) {
const existingWorkflow = await this.prisma.aiWorkflow.findUnique({
where: { id },
});
if (!existingWorkflow) {
this.logger.error(`AI workflow with id ${id} not found.`);
throw new Error(`AI workflow with id ${id} not found.`);
}

if (updateDto.scorecardId) {
const scorecardExists = await this.scorecardExists(updateDto.scorecardId);
if (!scorecardExists) {
this.logger.error(`Active scorecard with id ${updateDto.scorecardId} does not exist.`);
throw new BadRequestException(
`Active scorecard with id ${updateDto.scorecardId} does not exist.`,
);
}
}

if (updateDto.llmId) {
const llmExists = await this.llmModelExists(updateDto.llmId);
if (!llmExists) {
this.logger.error(`LLM model with id ${updateDto.llmId} does not exist.`);
throw new BadRequestException(
`LLM model with id ${updateDto.llmId} does not exist.`,
);
}
}

return this.prisma.aiWorkflow.update({
where: { id },
data: {
...updateDto,
updatedBy,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is either user handle making the call or system in case of M2M.

updatedAt: new Date(),
},
});
}
}
29 changes: 26 additions & 3 deletions src/api/ai_workflow/ai_workflow.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Controller, Post, Body, Get, Param, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { Controller, Post, Body, Get, Param, UseGuards, Patch, ValidationPipe } from '@nestjs/common';
import { ApiBearerAuth, ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
import { AiWorkflowService } from './aiWorkflow.service';
import { CreateAiWorkflowDto } from '../../dto/aiWorkflow.dto';
import { CreateAiWorkflowDto, UpdateAiWorkflowDto } from '../../dto/aiWorkflow.dto';
import { Scopes } from 'src/shared/decorators/scopes.decorator';
import { UserRole } from 'src/shared/enums/userRole.enum';
import { Scope } from 'src/shared/enums/scopes.enum';
import { Roles } from 'src/shared/guards/tokenRoles.guard';
import { User } from 'src/shared/decorators/user.decorator';
import { JwtUser } from 'src/shared/modules/global/jwt.service';

@ApiTags('ai_workflow')
@ApiBearerAuth()
Expand Down Expand Up @@ -39,4 +41,25 @@ export class AiWorkflowController {
async getById(@Param('id') id: string) {
return this.aiWorkflowService.getWorkflowById(id);
}

@Patch('/:id')
@Scopes(Scope.UpdateWorkflow)
@Roles(UserRole.Admin)
@ApiOperation({ summary: 'Update an existing AI workflow' })
@ApiParam({
name: 'id',
description: 'The ID of the AI workflow',
example: 'abc123',
})
@ApiBody({ description: 'AI workflow data', type: UpdateAiWorkflowDto })
@ApiResponse({ status: 200, description: 'AI workflow updated successfully.' })
@ApiResponse({ status: 403, description: 'Forbidden.' })
@ApiResponse({ status: 404, description: 'AI workflow not found.' })
async update(
@Param('id') id: string,
@Body(new ValidationPipe({ whitelist: true, transform: true })) updateDto: UpdateAiWorkflowDto,
@User() user: JwtUser,
) {
return this.aiWorkflowService.updateWorkflow(id, updateDto, user.userId);
}
}
4 changes: 3 additions & 1 deletion src/dto/aiWorkflow.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApiProperty } from '@nestjs/swagger';
import { ApiProperty, PartialType } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';

export class CreateAiWorkflowDto {
Expand Down Expand Up @@ -48,3 +48,5 @@ export class CreateAiWorkflowDto {
@ApiProperty({ required: false })
updatedAt?: Date;
}

export class UpdateAiWorkflowDto extends PartialType(CreateAiWorkflowDto) {}
2 changes: 2 additions & 0 deletions src/shared/enums/scopes.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ export enum Scope {
DeleteSubmission = 'delete:submission',
AllSubmission = 'all:submission',


// AI workflow scopes
CreateWorkflow = 'create:workflow',
ReadWorkflow = 'read:workflow',
UpdateWorkflow = 'update:workflow',
}

/**
Expand Down