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 12 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);
}
}
}
34 changes: 24 additions & 10 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,10 @@ export class CommentController extends CrudController<Comment> {
super(commentService);
}

@ApiOperation({
summary: 'Find all comments filtered by type.'
})
/**
* Find all comments filtered by type.
*/
@ApiOperation({ summary: 'Find all comments filtered by type.' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Found comments',
Expand All @@ -43,26 +44,33 @@ 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);
}

/**
* Find by id
*/
@ApiOperation({ summary: 'Find by id' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Found one record' /*, type: T*/
description: 'Found one record'
// You can specify a type here if needed: type: Comment,
})
@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);
}

/**
* Create/Post a comment
*/
@ApiOperation({ summary: 'Create/Post a comment' })
@ApiResponse({
status: HttpStatus.CREATED,
Expand All @@ -73,12 +81,15 @@ export class CommentController extends CrudController<Comment> {
description: 'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Post()
@Post('/')
@UseValidationPipe({ whitelist: true })
async create(@Body() entity: CreateCommentDTO): Promise<IComment> {
return await this.commandBus.execute(new CommentCreateCommand(entity));
}

/**
* Update an existing comment
*/
@ApiOperation({ summary: 'Update an existing comment' })
@ApiResponse({
status: HttpStatus.CREATED,
Expand All @@ -93,12 +104,15 @@ 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));
}

/**
* Delete comment
*/
@ApiOperation({ summary: 'Delete comment' })
@ApiResponse({
status: HttpStatus.NO_CONTENT,
Expand Down
Loading
Loading