Commit 877f3f7a by Augusto

version 0.0.1

parent 8bbe41f2
...@@ -11,7 +11,7 @@ export class CandidatesService { ...@@ -11,7 +11,7 @@ export class CandidatesService {
constructor(private prisma: PrismaService) { } constructor(private prisma: PrismaService) { }
async create(createCandidateDto: CreateCandidateDto, userId?: number) { async create(createCandidateDto: CreateCandidateDto, userId?: number) {
const { comment, ...candidateData } = createCandidateDto; const { comment, siteIds, ...candidateData } = createCandidateDto;
// Create the candidate with a transaction to ensure both operations succeed or fail together // Create the candidate with a transaction to ensure both operations succeed or fail together
return this.prisma.$transaction(async (prisma) => { return this.prisma.$transaction(async (prisma) => {
...@@ -21,8 +21,20 @@ export class CandidatesService { ...@@ -21,8 +21,20 @@ export class CandidatesService {
...candidateData, ...candidateData,
createdById: userId, createdById: userId,
updatedById: userId, updatedById: userId,
sites: {
create: siteIds.map(siteId => ({
site: {
connect: { id: siteId }
}
}))
}
}, },
include: { include: {
sites: {
include: {
site: true
}
},
comments: { comments: {
include: { include: {
createdBy: { createdBy: {
...@@ -54,6 +66,11 @@ export class CandidatesService { ...@@ -54,6 +66,11 @@ export class CandidatesService {
return prisma.candidate.findUnique({ return prisma.candidate.findUnique({
where: { id: candidate.id }, where: { id: candidate.id },
include: { include: {
sites: {
include: {
site: true
}
},
comments: { comments: {
include: { include: {
createdBy: { createdBy: {
...@@ -172,10 +189,29 @@ export class CandidatesService { ...@@ -172,10 +189,29 @@ export class CandidatesService {
async update(id: number, updateCandidateDto: UpdateCandidateDto) { async update(id: number, updateCandidateDto: UpdateCandidateDto) {
try { try {
const { siteIds, ...candidateData } = updateCandidateDto;
return await this.prisma.candidate.update({ return await this.prisma.candidate.update({
where: { id }, where: { id },
data: updateCandidateDto, data: {
...candidateData,
...(siteIds && {
sites: {
deleteMany: {}, // Remove all existing site associations
create: siteIds.map(siteId => ({
site: {
connect: { id: siteId }
}
}))
}
})
},
include: {
sites: {
include: { include: {
site: true
}
},
comments: { comments: {
include: { include: {
createdBy: { createdBy: {
......
...@@ -12,6 +12,11 @@ export enum CandidateStatus { ...@@ -12,6 +12,11 @@ export enum CandidateStatus {
PENDING = 'PENDING', PENDING = 'PENDING',
APPROVED = 'APPROVED', APPROVED = 'APPROVED',
REJECTED = 'REJECTED', REJECTED = 'REJECTED',
NEGOTIATION_ONGOING = 'NEGOTIATION_ONGOING',
MNO_VALIDATION = 'MNO_VALIDATION',
CLOSING = 'CLOSING',
SEARCH_AREA = 'SEARCH_AREA',
} }
export class CreateCandidateDto { export class CreateCandidateDto {
...@@ -43,9 +48,9 @@ export class CreateCandidateDto { ...@@ -43,9 +48,9 @@ export class CreateCandidateDto {
@IsBoolean() @IsBoolean()
onGoing: boolean; onGoing: boolean;
@ApiProperty({ description: 'ID of the site this candidate belongs to' }) @ApiProperty({ description: 'IDs of the sites this candidate belongs to', type: [Number] })
@IsNumber() @IsNumber({}, { each: true })
siteId: number; siteIds: number[];
@ApiPropertyOptional({ description: 'Initial comment for the candidate' }) @ApiPropertyOptional({ description: 'Initial comment for the candidate' })
@IsString() @IsString()
......
...@@ -38,8 +38,8 @@ export class UpdateCandidateDto { ...@@ -38,8 +38,8 @@ export class UpdateCandidateDto {
@IsBoolean() @IsBoolean()
onGoing?: boolean; onGoing?: boolean;
@ApiPropertyOptional({ description: 'ID of the site this candidate belongs to' }) @ApiPropertyOptional({ description: 'IDs of the sites this candidate belongs to', type: [Number] })
@IsOptional() @IsOptional()
@IsNumber() @IsNumber({}, { each: true })
siteId?: number; siteIds?: number[];
} }
\ No newline at end of file
import { Controller, Get, Post, Body, Param, Delete, UseGuards, ParseIntPipe } from '@nestjs/common'; import { Controller, Get, Post, Body, Param, Delete, UseGuards, ParseIntPipe, Req, Put } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiBody } from '@nestjs/swagger';
import { CommentsService } from './comments.service'; import { CommentsService } from './comments.service';
import { CreateCommentDto } from './dto/create-comment.dto'; import { CreateCommentDto } from './dto/create-comment.dto';
import { UpdateCommentDto } from './dto/update-comment.dto';
import { CommentResponseDto } from './dto/comment-response.dto'; import { CommentResponseDto } from './dto/comment-response.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard'; import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator'; import { Roles } from '../auth/decorators/roles.decorator';
import { Role } from '@prisma/client'; import { Role } from '@prisma/client';
import { Request } from 'express';
@ApiTags('comments') @ApiTags('comments')
@Controller('comments') @Controller('comments')
...@@ -16,11 +18,14 @@ export class CommentsController { ...@@ -16,11 +18,14 @@ export class CommentsController {
constructor(private readonly commentsService: CommentsService) { } constructor(private readonly commentsService: CommentsService) { }
@Post() @Post()
@Roles(Role.ADMIN, Role.MANAGER, Role.OPERATOR) @Roles(Role.ADMIN, Role.MANAGER, Role.OPERATOR, Role.SUPERADMIN)
@ApiOperation({ summary: 'Create a new comment' }) @ApiOperation({ summary: 'Create a new comment' })
@ApiBody({ type: CreateCommentDto })
@ApiResponse({ status: 201, description: 'The comment has been successfully created.', type: CommentResponseDto }) @ApiResponse({ status: 201, description: 'The comment has been successfully created.', type: CommentResponseDto })
@ApiResponse({ status: 400, description: 'Bad Request.' }) @ApiResponse({ status: 400, description: 'Bad Request.' })
create(@Body() createCommentDto: CreateCommentDto) { create(@Body() createCommentDto: CreateCommentDto, @Req() req: Request) {
const user = req.user as any;
createCommentDto.createdById = user.id;
return this.commentsService.create(createCommentDto); return this.commentsService.create(createCommentDto);
} }
...@@ -44,11 +49,21 @@ export class CommentsController { ...@@ -44,11 +49,21 @@ export class CommentsController {
} }
@Delete(':id') @Delete(':id')
@Roles(Role.ADMIN, Role.MANAGER) @Roles(Role.ADMIN, Role.MANAGER, Role.SUPERADMIN)
@ApiOperation({ summary: 'Delete a comment' }) @ApiOperation({ summary: 'Delete a comment' })
@ApiResponse({ status: 200, description: 'The comment has been successfully deleted.', type: CommentResponseDto }) @ApiResponse({ status: 200, description: 'The comment has been successfully deleted.', type: CommentResponseDto })
@ApiResponse({ status: 404, description: 'Comment not found.' }) @ApiResponse({ status: 404, description: 'Comment not found.' })
remove(@Param('id', ParseIntPipe) id: number) { remove(@Param('id', ParseIntPipe) id: number) {
return this.commentsService.remove(id); return this.commentsService.remove(id);
} }
@Put(':id')
@Roles(Role.ADMIN, Role.MANAGER, Role.OPERATOR, Role.SUPERADMIN)
@ApiOperation({ summary: 'Update a comment' })
@ApiBody({ type: UpdateCommentDto })
@ApiResponse({ status: 200, description: 'The comment has been successfully updated.', type: CommentResponseDto })
@ApiResponse({ status: 404, description: 'Comment not found.' })
update(@Param('id', ParseIntPipe) id: number, @Body() updateCommentDto: UpdateCommentDto) {
return this.commentsService.update(id, updateCommentDto);
}
} }
\ No newline at end of file
import { Injectable } from '@nestjs/common'; import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma/prisma.service'; import { PrismaService } from '../../common/prisma/prisma.service';
import { CreateCommentDto } from './dto/create-comment.dto'; import { CreateCommentDto } from './dto/create-comment.dto';
import { UpdateCommentDto } from './dto/update-comment.dto';
@Injectable() @Injectable()
export class CommentsService { export class CommentsService {
...@@ -65,4 +66,27 @@ export class CommentsService { ...@@ -65,4 +66,27 @@ export class CommentsService {
where: { id }, where: { id },
}); });
} }
async update(id: number, updateCommentDto: UpdateCommentDto) {
try {
return await this.prisma.comment.update({
where: { id },
data: {
content: updateCommentDto.content,
updatedAt: new Date(),
},
include: {
createdBy: {
select: {
id: true,
name: true,
email: true,
},
},
},
});
} catch (error) {
throw new NotFoundException(`Comment with ID ${id} not found`);
}
}
} }
\ No newline at end of file
import { IsString, IsNotEmpty, IsInt, IsOptional } from 'class-validator'; import { IsString, IsNotEmpty, IsInt, IsOptional } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateCommentDto { export class CreateCommentDto {
@ApiProperty({
description: 'The content of the comment',
example: 'This is a comment about the candidate'
})
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
content: string; content: string;
@ApiProperty({
description: 'The ID of the candidate this comment is for',
example: 64
})
@IsInt() @IsInt()
@IsNotEmpty() @IsNotEmpty()
candidateId: number; candidateId: number;
@ApiProperty({
description: 'The ID of the user creating the comment (optional, will be set automatically)',
example: 1,
required: false
})
@IsInt() @IsInt()
@IsOptional() @IsOptional()
createdById?: number; createdById?: number;
......
import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class UpdateCommentDto {
@ApiProperty({
description: 'The updated content of the comment',
example: 'This is an updated comment about the candidate'
})
@IsString()
@IsNotEmpty()
content: string;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment