Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Warnings:
- You are about to drop the column `downVotes` on the `aiWorkflowRunItem` table. All the data in the column will be lost.
- You are about to drop the column `upVotes` on the `aiWorkflowRunItem` table. All the data in the column will be lost.
- You are about to drop the column `downVotes` on the `aiWorkflowRunItemComment` table. All the data in the column will be lost.
- You are about to drop the column `upVotes` on the `aiWorkflowRunItemComment` table. All the data in the column will be lost.
*/
-- CreateEnum
CREATE TYPE "VoteType" AS ENUM ('UPVOTE', 'DOWNVOTE');

-- AlterTable
ALTER TABLE "aiWorkflowRunItem" DROP COLUMN "downVotes",
DROP COLUMN "upVotes";

-- AlterTable
ALTER TABLE "aiWorkflowRunItemComment" DROP COLUMN "downVotes",
DROP COLUMN "upVotes";

-- CreateTable
CREATE TABLE "aiWorkflowRunItemVote" (
"id" VARCHAR(14) NOT NULL DEFAULT nanoid(),
"workflowRunItemId" VARCHAR(14) NOT NULL,
"voteType" "VoteType" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"createdBy" TEXT NOT NULL,

CONSTRAINT "aiWorkflowRunItemVote_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "aiWorkflowRunItemCommentVote" (
"id" VARCHAR(14) NOT NULL DEFAULT nanoid(),
"workflowRunItemCommentId" VARCHAR(14) NOT NULL,
"voteType" "VoteType" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"createdBy" TEXT NOT NULL,

CONSTRAINT "aiWorkflowRunItemCommentVote_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "aiWorkflowRunItemVote_workflowRunItemId_idx" ON "aiWorkflowRunItemVote"("workflowRunItemId");

-- CreateIndex
CREATE UNIQUE INDEX "aiWorkflowRunItemVote_workflowRunItemId_createdBy_key" ON "aiWorkflowRunItemVote"("workflowRunItemId", "createdBy");

-- CreateIndex
CREATE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_idx" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId");

-- CreateIndex
CREATE UNIQUE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_creat_key" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId", "createdBy");

-- AddForeignKey
ALTER TABLE "aiWorkflowRunItemVote" ADD CONSTRAINT "aiWorkflowRunItemVote_workflowRunItemId_fkey" FOREIGN KEY ("workflowRunItemId") REFERENCES "aiWorkflowRunItem"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "aiWorkflowRunItemCommentVote" ADD CONSTRAINT "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_fkey" FOREIGN KEY ("workflowRunItemCommentId") REFERENCES "aiWorkflowRunItemComment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
39 changes: 35 additions & 4 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,37 @@ model llmModel {
workflows aiWorkflow[]
}

model aiWorkflowRunItemVote {
id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14)
workflowRunItemId String @db.VarChar(14)
voteType VoteType
createdAt DateTime @default(now()) @db.Timestamp(3)
createdBy String @db.Text

item aiWorkflowRunItem @relation(fields: [workflowRunItemId], references: [id], onDelete: Cascade)

@@index([workflowRunItemId])
@@unique([workflowRunItemId, createdBy])
}

model aiWorkflowRunItemCommentVote {
id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14)
workflowRunItemCommentId String @db.VarChar(14)
voteType VoteType
createdAt DateTime @default(now()) @db.Timestamp(3)
createdBy String @db.Text

Choose a reason for hiding this comment

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

[❗❗ correctness]
The createdBy field has been changed from String? to String, making it mandatory. Verify that this change is compatible with existing data and logic, as it may cause issues if createdBy is not consistently set.


comment aiWorkflowRunItemComment @relation(fields: [workflowRunItemCommentId], references: [id], onDelete: Cascade)

@@index([workflowRunItemCommentId])
@@unique([workflowRunItemCommentId, createdBy])
}

enum VoteType {
UPVOTE
DOWNVOTE
}

model aiWorkflow {
id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14)
name String @unique @db.VarChar
Expand Down Expand Up @@ -690,24 +721,22 @@ model aiWorkflowRunItem {
workflowRunId String @db.VarChar(14)
scorecardQuestionId String @db.VarChar(14)
content String @db.Text
upVotes Int @default(0)
downVotes Int @default(0)
questionScore Float? @db.DoublePrecision
createdAt DateTime @db.Timestamp(3)
createdBy String? @db.Text

run aiWorkflowRun @relation(fields: [workflowRunId], references: [id])
question scorecardQuestion @relation(fields: [scorecardQuestionId], references: [id])
comments aiWorkflowRunItemComment[]

votes aiWorkflowRunItemVote[]
}

model aiWorkflowRunItemComment {
id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14)
workflowRunItemId String @db.VarChar(14)
userId String @db.Text
content String @db.Text
upVotes Int @default(0)
downVotes Int @default(0)
parentId String? @db.VarChar(14)
createdAt DateTime @default(now()) @db.Timestamp(3)
createdBy String? @db.Text
Expand All @@ -717,4 +746,6 @@ model aiWorkflowRunItemComment {
item aiWorkflowRunItem @relation(fields: [workflowRunItemId], references: [id])
parent aiWorkflowRunItemComment? @relation("CommentHierarchy", fields: [parentId], references: [id])
replies aiWorkflowRunItemComment[] @relation("CommentHierarchy")

votes aiWorkflowRunItemCommentVote[]
}
116 changes: 101 additions & 15 deletions src/api/ai-workflow/ai-workflow.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { UserRole } from 'src/shared/enums/userRole.enum';
import { ChallengeStatus } from 'src/shared/enums/challengeStatus.enum';
import { LoggerService } from 'src/shared/modules/global/logger.service';
import { GiteaService } from 'src/shared/modules/global/gitea.service';
import { VoteType } from '@prisma/client';

@Injectable()
export class AiWorkflowService {
Expand Down Expand Up @@ -96,7 +97,49 @@ export class AiWorkflowService {
);
}

const allowedFields = ['content', 'upVotes', 'downVotes'];
// Handle vote updates
if (patchData.upVote !== undefined || patchData.downVote !== undefined) {
if (!user.userId) {
throw new BadRequestException('User id is not available');
}

// Remove existing votes by this user for this comment
await this.prisma.aiWorkflowRunItemCommentVote.deleteMany({
where: {
workflowRunItemCommentId: commentId,
createdBy: user.userId.toString(),
},
});

// Add new vote if upVote or downVote is true
if (patchData.upVote) {
await this.prisma.aiWorkflowRunItemCommentVote.create({
data: {
workflowRunItemCommentId: commentId,
voteType: VoteType.UPVOTE,
createdBy: user.userId.toString(),
},
});
} else if (patchData.downVote) {
await this.prisma.aiWorkflowRunItemCommentVote.create({
data: {
workflowRunItemCommentId: commentId,
voteType: VoteType.DOWNVOTE,
createdBy: user.userId.toString(),
},
});
}

delete patchData.downVote;
delete patchData.upVote;
}

// No other fields to update apart from likes
if (Object.keys(patchData).length === 0) {
return;
}

const allowedFields = ['content'];
const updateData: any = {};
for (const key of allowedFields) {
if (key in patchData) {
Expand Down Expand Up @@ -388,8 +431,6 @@ export class AiWorkflowService {
workflowRunId: runId,
scorecardQuestionId: item.scorecardQuestionId,
content: item.content,
upVotes: item.upVotes ?? 0,
downVotes: item.downVotes ?? 0,
questionScore: item.questionScore ?? null,
createdAt: new Date(),
// TODO: Remove this once prisma middleware implementation is done
Expand Down Expand Up @@ -770,7 +811,12 @@ export class AiWorkflowService {
const items = await this.prisma.aiWorkflowRunItem.findMany({
where: { workflowRunId: runId },
include: {
comments: true,
comments: {
include: {
votes: true,
}
},
votes: true,
},
orderBy: {
createdAt: 'asc',
Expand Down Expand Up @@ -819,15 +865,6 @@ export class AiWorkflowService {
);
}

const updateData: any = {};

if (patchData.upVotes !== undefined) {
updateData.upVotes = patchData.upVotes;
}
if (patchData.downVotes !== undefined) {
updateData.downVotes = patchData.downVotes;
}

if (!user.isMachine) {
const keys = Object.keys(patchData);
const prohibitedKeys = ['content', 'questionScore'];
Expand All @@ -838,21 +875,70 @@ export class AiWorkflowService {
}
}

// Update properties which can be updated only via m2m
if (patchData.upVote !== undefined || patchData.downVote !== undefined) {
// Remove existing votes by this user for this item
if (!user.userId) {
throw new BadRequestException('User id is not available');
}

await this.prisma.aiWorkflowRunItemVote.deleteMany({
where: {
workflowRunItemId: itemId,
createdBy: user.userId.toString(),
},
});

// Add new vote if upVote or downVote is true
if (patchData.upVote) {
await this.prisma.aiWorkflowRunItemVote.create({
data: {
workflowRunItemId: itemId,
voteType: VoteType.UPVOTE,
createdBy: user.userId.toString(),
},
});
} else if (patchData.downVote) {
await this.prisma.aiWorkflowRunItemVote.create({
data: {
workflowRunItemId: itemId,
voteType: VoteType.DOWNVOTE,
createdBy: user.userId.toString(),
},
});
}

delete patchData.downVote;
delete patchData.upVote;
}

// Update other properties only allowed for machine users
const updateData: any = {};
if (user.isMachine) {
if (patchData.content) {
updateData.content = patchData.content;
}

if (patchData.questionScore) {
updateData.questionScore = patchData.questionScore;
}
}

// If there are no other fields to update
// just return the run item
if (Object.keys(updateData).length === 0) {
return this.prisma.aiWorkflowRunItem.findUnique({
where: { id: itemId },
include: {
comments: true,
votes: true,
},
});
}

return this.prisma.aiWorkflowRunItem.update({
where: { id: itemId },
include: {
comments: true,
votes: true,
},
data: updateData,
});
Expand Down
19 changes: 9 additions & 10 deletions src/dto/aiWorkflow.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
IsUUID,
Max,
IsEmpty,
IsBoolean,
} from 'class-validator';
import { Type, Transform } from 'class-transformer';

Expand Down Expand Up @@ -134,15 +135,13 @@ export class CreateAiWorkflowRunItemDto {

@ApiProperty({ required: false })
@IsOptional()
@IsInt()
@Min(0)
upVotes?: number;
@IsBoolean()
upVote?: boolean;

@ApiProperty({ required: false })
@IsOptional()
@IsInt()
@Min(0)
downVotes?: number;
@IsBoolean()
downVote?: boolean;

@ApiProperty({ required: false })
@IsOptional()
Expand Down Expand Up @@ -202,14 +201,14 @@ export class UpdateRunItemCommentDto {
content?: string;

@ApiProperty({ required: false })
@IsInt()
@IsBoolean()
@IsOptional()
upVotes?: number;
upVote?: boolean;

@ApiProperty({ required: false })
@IsInt()
@IsBoolean()
@IsOptional()
downVotes?: number;
downVote?: boolean;

@ApiHideProperty()
@IsEmpty({ message: 'parentId cannot be updated' })
Expand Down
Loading