Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] Comment entity employee based #8769

Merged
merged 17 commits into from
Feb 13, 2025
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
1 change: 1 addition & 0 deletions packages/contracts/src/lib/base-entity.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export enum ActorTypeEnum {
User = 'User' // User performed the action
}

// BaseEntityEnum defines the type of the entity, used in BaseEntity model
export enum BaseEntityEnum {
Candidate = 'Candidate',
Comment = 'Comment',
Expand Down
24 changes: 11 additions & 13 deletions packages/contracts/src/lib/comment.model.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
import { ActorTypeEnum, IBasePerEntityType, ID } from './base-entity.model';
import { IUser } from './user.model';
import { IEmployee } from './employee.model';
import { IEmployee, IEmployeeEntityInput as ICommentAuthor } from './employee.model';
import { IOrganizationTeam } from './organization-team.model';
import { IMentionUserIds } from './mention.model';
import { IMentionEmployeeIds } from './mention.model';

export interface IComment extends IBasePerEntityType {
export interface IComment extends IBasePerEntityType, ICommentAuthor {
comment: string;
creator?: IUser;
creatorId?: ID; // The comment's user author ID
actorType?: ActorTypeEnum;
resolved?: boolean;
resolvedAt?: Date;
resolvedBy?: IUser;
resolvedById?: ID;
editedAt?: Date;
members?: IEmployee[]; // Indicates members assigned to comment
teams?: IOrganizationTeam[]; // Indicates teams assigned to comment
parent?: IComment;
parentId?: ID; // Specify the parent comment if current one is a reply
replies?: IComment[];
resolvedByEmployee?: IEmployee; // Indicates the employee who resolved the comment
resolvedByEmployeeId?: ID; // Indicates the employee ID who resolved the comment
}

export interface ICommentCreateInput extends IBasePerEntityType, IMentionUserIds {
export interface ICommentCreateInput extends IBasePerEntityType, ICommentAuthor, IMentionEmployeeIds {
comment: string;
entityName?: string;
parentId?: ID;
parent?: IComment;
parentId?: ID; // Specify the parent comment if current one is a reply
members?: IEmployee[];
teams?: IOrganizationTeam[];
}

export interface ICommentUpdateInput
extends IMentionUserIds,
Partial<Omit<IComment, 'entity' | 'entityId' | 'creatorId' | 'creator'>> { }
extends IMentionEmployeeIds,
Partial<Omit<IComment, 'entity' | 'entityId' | 'employeeId' | 'employee'>> {}

export interface ICommentFindInput extends Pick<IComment, 'entity' | 'entityId'> { }
export interface ICommentFindInput extends Pick<IComment, 'entity' | 'entityId'> {}
4 changes: 2 additions & 2 deletions packages/contracts/src/lib/mention.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ export interface IMentionCreateInput extends Omit<IMention, 'mentionBy'> {
entityName?: string;
}

export interface IMentionUserIds {
mentionUserIds?: ID[];
export interface IMentionEmployeeIds {
mentionEmployeeIds?: ID[];
}
4 changes: 2 additions & 2 deletions packages/contracts/src/lib/screening-task.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IBasePerTenantAndOrganizationEntityModel, ID } from './base-entity.model';
import { IMentionUserIds } from './mention.model';
import { IMentionEmployeeIds } from './mention.model';
import { ITask } from './task.model';
import { IUser } from './user.model';

Expand All @@ -20,6 +20,6 @@ export enum ScreeningTaskStatusEnum {
PENDING = 'pending'
}

export interface IScreeningTaskCreateInput extends Omit<IScreeningTask, 'status'>, IMentionUserIds {}
export interface IScreeningTaskCreateInput extends Omit<IScreeningTask, 'status'>, IMentionEmployeeIds {}

export interface IScreeningTaskUpdateInput extends Omit<IScreeningTask, 'task' | 'taskId'> {}
4 changes: 2 additions & 2 deletions packages/contracts/src/lib/task.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ITaskPriority, TaskPriorityEnum } from './task-priority.model';
import { ITaskSize, TaskSizeEnum } from './task-size.model';
import { IOrganizationProjectModule } from './organization-project-module.model';
import { IIssueType, TaskTypeEnum } from './issue-type.model';
import { IMentionUserIds } from './mention.model';
import { IMentionEmployeeIds } from './mention.model';

export interface ITask
extends IBasePerTenantAndOrganizationEntityModel,
Expand Down Expand Up @@ -80,7 +80,7 @@ export enum TaskParticipantEnum {
TEAMS = 'teams'
}

export interface ITaskCreateInput extends ITask, IMentionUserIds {}
export interface ITaskCreateInput extends ITask, IMentionEmployeeIds {}

export interface ITaskUpdateInput extends ITaskCreateInput {
taskSprintMoveReason?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/lib/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type ExcludeCreatorFields<T> = Omit<T, 'creator' | 'creatorId'>;
* Interface representing a relationship with a creator.
*/
export interface IHasCreator {
creator?: IUser;
creator?: IUser; // TODO : Replace these properties with `createdBy` and `createdById`
creatorId?: ID;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import { BadRequestException } from '@nestjs/common';
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { IComment } from '@gauzy/contracts';
import { CommentService } from '../../comment.service';
import { CommentCreateCommand } from '../comment.create.command';

@CommandHandler(CommentCreateCommand)
export class CommentCreateHandler implements ICommandHandler<CommentCreateCommand> {
constructor(private readonly commentService: CommentService) {}
constructor(readonly commentService: CommentService) {}

/**
* Executes the CommentCreateCommand to create a new comment.
*
* This function extracts the input data from the provided command and invokes the comment service
* to create a comment. If an error occurs during the process, it logs the error and throws a
* BadRequestException.
*
* @param {CommentCreateCommand} command - The command containing the input data for creating the comment.
* @returns {Promise<IComment>} A promise that resolves to the newly created comment.
* @throws {BadRequestException} If the comment creation fails.
*/
public async execute(command: CommentCreateCommand): Promise<IComment> {
const { input } = command;
return await this.commentService.create(input);
try {
const { input } = command;
return await this.commentService.create(input);
} catch (error) {
console.log(`Error while creating comment: ${error.message}`, error);
throw new BadRequestException('Comment post failed', error);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
import { BadRequestException } from '@nestjs/common';
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { UpdateResult } from 'typeorm';
import { IComment } from '@gauzy/contracts';
import { CommentService } from '../../comment.service';
import { CommentUpdateCommand } from '../comment.update.command';
import { IComment } from '@gauzy/contracts';

@CommandHandler(CommentUpdateCommand)
export class CommentUpdateHandler implements ICommandHandler<CommentUpdateCommand> {
constructor(private readonly commentService: CommentService) {}

constructor(readonly commentService: CommentService) {}
/**
* Executes the CommentUpdateCommand to update an existing comment.
*
* This function extracts the comment ID and the update input from the command, and then invokes the
* comment service's update method to perform the update. It returns a promise that resolves to either
* the updated comment or an update result.
*
* If an error occurs during the update, the error is logged and a BadRequestException is thrown.
*
* @param {CommentUpdateCommand} command - The command containing the comment ID and update data.
* @returns {Promise<IComment | UpdateResult>} A promise that resolves to the updated comment or update result.
* @throws {BadRequestException} If the update process fails.
*/
public async execute(command: CommentUpdateCommand): Promise<IComment | UpdateResult> {
const { id, input } = command;
return await this.commentService.update(id, input);
try {
const { id, input } = command;
return await this.commentService.update(id, input);
} catch (error) {
console.log(`Error while updating comment: ${error.message}`, error);
throw new BadRequestException('Comment update failed', error);
}
}
}
54 changes: 43 additions & 11 deletions packages/core/src/lib/comment/comment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { CommandBus } from '@nestjs/cqrs';
import { DeleteResult } from 'typeorm';
import { IComment, ID, IPagination } from '@gauzy/contracts';
import { UUIDValidationPipe, UseValidationPipe } from './../shared/pipes';
import { CrudController, OptionParams, PaginationParams } from '../core/crud';
import { UUIDValidationPipe, UseValidationPipe } from '../shared/pipes';
import { PermissionGuard, TenantPermissionGuard } from '../shared/guards';
import { CrudController, OptionParams, PaginationParams } from './../core/crud';
import { Comment } from './comment.entity';
import { CommentService } from './comment.service';
import { CommentCreateCommand, CommentUpdateCommand } from './commands';
Expand All @@ -31,9 +31,13 @@ export class CommentController extends CrudController<Comment> {
super(commentService);
}

@ApiOperation({
summary: 'Find all comments filtered by type.'
})
/**
* Finds all comments filtered by type (or other criteria) with pagination.
*
* @param params - Pagination and filter parameters.
* @returns A promise that resolves with paginated comments.
*/
@ApiOperation({ summary: 'Find all comments filtered by type.' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Found comments',
Expand All @@ -43,26 +47,39 @@ export class CommentController extends CrudController<Comment> {
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@Get()
@Get('/')
@UseValidationPipe()
async findAll(@Query() params: PaginationParams<Comment>): Promise<IPagination<IComment>> {
return await this.commentService.findAll(params);
}

/**
* Finds a comment by its id.
*
* @param id - The id of the comment.
* @param params - Optional parameters (e.g., relations to load).
* @returns The found comment record.
*/
@ApiOperation({ summary: 'Find by id' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Found one record' /*, type: T*/
description: 'Found one record'
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@Get(':id')
@Get('/:id')
async findById(@Param('id', UUIDValidationPipe) id: ID, @Query() params: OptionParams<Comment>): Promise<Comment> {
return this.commentService.findOneByIdString(id, params);
}

/**
* Creates a new comment using the provided DTO.
*
* @param createCommentDto - Data transfer object containing comment data.
* @returns A promise resolving to the created comment.
*/
@ApiOperation({ summary: 'Create/Post a comment' })
@ApiResponse({
status: HttpStatus.CREATED,
Expand All @@ -72,13 +89,21 @@ export class CommentController extends CrudController<Comment> {
status: HttpStatus.BAD_REQUEST,
description: 'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Post()
@HttpCode(HttpStatus.CREATED)
@Post('/')
@UseValidationPipe({ whitelist: true })
async create(@Body() entity: CreateCommentDTO): Promise<IComment> {
return await this.commandBus.execute(new CommentCreateCommand(entity));
}

/**
* Updates an existing comment identified by the provided id.
*
* @param id - The unique identifier of the comment.
* @param updateCommentDto - The data transfer object containing update data.
* @returns The updated comment.
* @throws NotFoundException if the comment does not exist.
*/
@ApiOperation({ summary: 'Update an existing comment' })
@ApiResponse({
status: HttpStatus.CREATED,
Expand All @@ -93,12 +118,19 @@ export class CommentController extends CrudController<Comment> {
description: 'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Put(':id')
@Put('/:id')
@UseValidationPipe({ whitelist: true })
async update(@Param('id', UUIDValidationPipe) id: ID, @Body() entity: UpdateCommentDTO): Promise<IComment> {
return await this.commandBus.execute(new CommentUpdateCommand(id, entity));
}

/**
* Deletes a comment identified by the given id.
*
* @param id - The unique identifier of the comment to delete.
* @returns A promise resolving to the result of the delete operation.
* @throws NotFoundException if the comment is not found.
*/
@ApiOperation({ summary: 'Delete comment' })
@ApiResponse({
status: HttpStatus.NO_CONTENT,
Expand Down
Loading
Loading