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] Alter "ScreeningTask" Entity Table #8801

Merged
merged 4 commits into from
Feb 24, 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
29 changes: 16 additions & 13 deletions packages/contracts/src/lib/screening-task.model.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import { IBasePerTenantAndOrganizationEntityModel, ID } from './base-entity.model';
import { IBasePerTenantAndOrganizationEntityModel, ID, OmitFields } from './base-entity.model';
import { IMentionEmployeeIds } from './mention.model';
import { ITask } from './task.model';
import { IUser } from './user.model';

export interface IScreeningTask extends IBasePerTenantAndOrganizationEntityModel {
status: ScreeningTaskStatusEnum;
taskId: ID;
task: ITask;
onHoldUntil?: Date;
creatorId?: ID;
creator?: IUser;
}
import { IHasUserCreator } from './user.model';

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

export interface IScreeningTaskCreateInput extends Omit<IScreeningTask, 'status'>, IMentionEmployeeIds {}
interface IScreeningTaskBase extends IBasePerTenantAndOrganizationEntityModel {
status: ScreeningTaskStatusEnum; // Represents the current state or phase of the screening task.
onHoldUntil?: Date; // The date and time until which the screening task is temporarily paused or put on hold.
}

interface IScreeningTaskAssociations extends IHasUserCreator {
task: ITask;
taskId: ID;
}

export interface IScreeningTask extends IScreeningTaskBase, IScreeningTaskAssociations {}

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

export interface IScreeningTaskUpdateInput extends Omit<IScreeningTask, 'task' | 'taskId'> {}
export interface IScreeningTaskUpdateInput extends IScreeningTaskBase {}
1 change: 1 addition & 0 deletions packages/core/src/lib/core/entities/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export * from '../../tags/tag.subscriber';
export * from '../../tasks/issue-type/issue-type.subscriber';
export * from '../../tasks/priorities/priority.subscriber';
export * from '../../tasks/related-issue-type/related-issue-type.subscriber';
export * from '../../tasks/screening-tasks/screening-task.subscriber';
export * from '../../tasks/sizes/size.subscriber';
export * from '../../tasks/statuses/status.subscriber';
export * from '../../tasks/task.subscriber';
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/lib/core/entities/subscribers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
ReportSubscriber,
ResourceLinkSubscriber,
RoleSubscriber,
ScreeningTaskSubscriber,
ScreenshotSubscriber,
TagSubscriber,
TaskPrioritySubscriber,
Expand Down Expand Up @@ -92,6 +93,7 @@ export const coreSubscribers = [
ReportSubscriber,
ResourceLinkSubscriber,
RoleSubscriber,
ScreeningTaskSubscriber,
ScreenshotSubscriber,
TagSubscriber,
TaskPrioritySubscriber,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HttpException, HttpStatus } from '@nestjs/common';
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { IScreeningTask } from '@gauzy/contracts';
import { ScreeningTasksService } from '../../screening-tasks.service';
Expand All @@ -7,8 +8,18 @@ import { ScreeningTaskCreateCommand } from '../screening-task.create.command';
export class ScreeningTaskCreateHandler implements ICommandHandler<ScreeningTaskCreateCommand> {
constructor(private readonly screeningTasksService: ScreeningTasksService) {}

/**
* Executes the create command for a screening task.
*
* @param command - The command containing the creation input for a screening task.
* @returns A promise that resolves to the newly created screening task.
*/
public async execute(command: ScreeningTaskCreateCommand): Promise<IScreeningTask> {
const { input } = command;
return await this.screeningTasksService.create(input);
try {
const { input } = command;
return await this.screeningTasksService.create(input);
} catch (error) {
throw new HttpException('Screening task creation failed', HttpStatus.BAD_REQUEST);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
import { HttpException, HttpStatus } from '@nestjs/common';
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { IScreeningTask } from '@gauzy/contracts';
import { ScreeningTasksService } from '../../screening-tasks.service';
import { ScreeningTaskUpdateCommand } from '../screening-task.update.command';
import { IScreeningTask } from '@gauzy/contracts';

@CommandHandler(ScreeningTaskUpdateCommand)
export class ScreeningTaskUpdateHandler implements ICommandHandler<ScreeningTaskUpdateCommand> {
constructor(private readonly screeningTasksService: ScreeningTasksService) {}

/**
* Executes the update command for a screening task.
*
* @param command - Contains the screening task ID and update input.
* @returns The updated screening task.
*/
public async execute(command: ScreeningTaskUpdateCommand): Promise<IScreeningTask> {
const { id, input } = command;
return await this.screeningTasksService.update(id, input);
try {
const { id, input } = command;
return await this.screeningTasksService.update(id, input);
} catch (error) {
throw new HttpException(
`Screening task update failed: ${error.message}`,
error instanceof HttpException ? error.getStatus() : HttpStatus.BAD_REQUEST
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,5 @@ import { ScreeningTask } from '../screening-task.entity';
* Create Screening Task data validation request DTO
*/
export class CreateScreeningTaskDTO
extends IntersectionType(
TenantOrganizationBaseDTO,
IntersectionType(OmitType(ScreeningTask, ['status']), MentionEmployeeIdsDTO)
)
extends IntersectionType(TenantOrganizationBaseDTO, MentionEmployeeIdsDTO, OmitType(ScreeningTask, ['status']))
implements IScreeningTaskCreateInput {}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ import { MikroOrmScreeningTaskRepository } from './repository/mikro-orm-screenin
export class ScreeningTask extends TenantOrganizationBaseEntity implements IScreeningTask {
[EntityRepositoryType]?: MikroOrmScreeningTaskRepository;

/**
* Represents the current state or phase of the screening task.
*/
@ApiProperty({ enum: ScreeningTaskStatusEnum })
@IsNotEmpty()
@IsEnum(ScreeningTaskStatusEnum)
@ColumnIndex()
@MultiORMColumn()
status: ScreeningTaskStatusEnum;

/**
* Represents the date and time when the screening task is set to on hold.
*/
@ApiPropertyOptional({ type: () => Date })
@IsOptional()
@IsDateString()
Expand All @@ -37,21 +43,19 @@ export class ScreeningTask extends TenantOrganizationBaseEntity implements IScre
|--------------------------------------------------------------------------
*/
/**
* Task
* The task associated with the screening task.
*/
@MultiORMOneToOne(() => Task, {
/** If set to true then it means that related object can be allowed to be inserted or updated in the database. */
cascade: true,

/** Database cascade action on delete. */
onDelete: 'CASCADE',

/** This column is a boolean flag indicating whether the current entity is the 'owning' side of a relationship. */
owner: true
cascade: true, // If set to true then it means that related object can be allowed to be inserted or updated in the database.
onDelete: 'CASCADE', // Defines the database cascade action on delete.
owner: true // This column is a boolean flag indicating whether the current entity is the 'owning' side of a relationship.
})
@JoinColumn()
task: ITask;

/**
* The ID unique identifier of the associated task.
*/
@ApiProperty({ type: () => String })
@IsNotEmpty()
@IsUUID()
Expand All @@ -65,19 +69,20 @@ export class ScreeningTask extends TenantOrganizationBaseEntity implements IScre
| @ManyToOne
|--------------------------------------------------------------------------
*/

/**
* Creator
* The creator of the screening task.
*/
@MultiORMManyToOne(() => User, {
/** Indicates if relation column value can be nullable or not. */
nullable: true
nullable: true // Indicates if the relation column value can be nullable or not.
})
@JoinColumn()
creator?: IUser;
createdByUser?: IUser;

@RelationId((it: ScreeningTask) => it.creator)
/**
* The ID of the creator of the screening task.
*/
@RelationId((it: ScreeningTask) => it.createdByUser)
@ColumnIndex()
@MultiORMColumn({ nullable: true, relationId: true })
creatorId?: ID;
createdByUserId?: ID;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { EventSubscriber } from 'typeorm';
import { ScreeningTask } from './screening-task.entity';
import { RequestContext } from '../../core/context';
import { BaseEntityEventSubscriber } from '../../core/entities/subscribers/base-entity-event.subscriber';

@EventSubscriber()
export class ScreeningTaskSubscriber extends BaseEntityEventSubscriber<ScreeningTask> {
/**
* Indicates that this subscriber only listen to Task events.
*/
listenTo() {
return ScreeningTask;
}

/**
* Called before a Task entity is inserted into the database. This method sets the creator ID
* of the task based on the current user context.
*
* @param {ScreeningTask} entity - The `ScreeningTask` entity that is about to be created.
* @returns {Promise<void>} - A promise that resolves when the operation is complete.
*/
async beforeEntityCreate(entity: ScreeningTask): Promise<void> {
try {
// Retrieve the current user's ID from RequestContext and assign it as the creator
if (entity) {
entity.createdByUserId = RequestContext.currentUserId();
}
} catch (error) {
console.error('ScreeningTaskSubscriber: An error occurred during the beforeEntityCreate process:', error);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { ScreeningTaskCreateCommand, ScreeningTaskUpdateCommand } from './comman
@ApiTags('Screening Tasks')
@UseGuards(TenantPermissionGuard, PermissionGuard)
@Permissions()
@Controller('screening-tasks')
@Controller('/screening-tasks')
export class ScreeningTasksController extends CrudController<ScreeningTask> {
constructor(
private readonly screeningTasksService: ScreeningTasksService,
Expand All @@ -36,41 +36,59 @@ export class ScreeningTasksController extends CrudController<ScreeningTask> {
super(screeningTasksService);
}

@ApiOperation({
summary: 'Find all screening tasks'
})
/**
* Find all screening tasks with pagination.
*
* @param params - Pagination parameters and optional filters.
* @returns A paginated response containing screening tasks.
*/
@ApiOperation({ summary: 'Find all screening tasks' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Found screening tasks',
description: 'Found screening tasks.',
type: ScreeningTask
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@Get()
@Get('/')
@UseValidationPipe()
async findAll(@Query() params: PaginationParams<ScreeningTask>): Promise<IPagination<IScreeningTask>> {
return await this.screeningTasksService.findAll(params);
}

@ApiOperation({ summary: 'Find by id' })
/**
* Find a screening task by its unique identifier.
*
* @param id - The UUID of the screening task.
* @param params - Optional query parameters for additional filtering.
* @returns The screening task that matches the given ID.
*/
@ApiOperation({ summary: 'Find screening task by id' })
@ApiResponse({
status: HttpStatus.OK,
description: 'Found one record' /*, type: T*/
description: 'Found one screening task',
type: ScreeningTask
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
description: 'Screening task not found'
})
@Get(':id')
@Get('/:id')
async findById(
@Param('id', UUIDValidationPipe) id: ID,
@Query() params: OptionParams<ScreeningTask>
): Promise<IScreeningTask> {
return this.screeningTasksService.findOneByIdString(id, params);
}

/**
* Creates a new screening task.
*
* @param entity - The DTO containing data required to create a new screening task.
* @returns A promise that resolves to the newly created screening task.
*/
@ApiOperation({ summary: 'Creates Screening Task' })
@ApiResponse({
status: HttpStatus.CREATED,
Expand All @@ -81,12 +99,19 @@ export class ScreeningTasksController extends CrudController<ScreeningTask> {
description: 'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Post()
@Post('/')
@UseValidationPipe()
async create(@Body() entity: CreateScreeningTaskDTO): Promise<IScreeningTask> {
return await this.commandBus.execute(new ScreeningTaskCreateCommand(entity));
}

/**
* Updates an existing screening task.
*
* @param id - The UUID of the screening task to update.
* @param entity - The DTO containing updated screening task data.
* @returns A promise that resolves to the updated screening task.
*/
@ApiOperation({ summary: 'Updates an existing screening task' })
@ApiResponse({
status: HttpStatus.CREATED,
Expand All @@ -101,7 +126,7 @@ export class ScreeningTasksController extends CrudController<ScreeningTask> {
description: 'Invalid input, The response body may contain clues as to what went wrong'
})
@HttpCode(HttpStatus.ACCEPTED)
@Put(':id')
@Put('/:id')
@UseValidationPipe()
async update(
@Param('id', UUIDValidationPipe) id: ID,
Expand All @@ -110,6 +135,12 @@ export class ScreeningTasksController extends CrudController<ScreeningTask> {
return await this.commandBus.execute(new ScreeningTaskUpdateCommand(id, entity));
}

/**
* Delete a screening task by its unique identifier.
*
* @param id - The UUID of the screening task to delete.
* @returns A DeleteResult indicating the outcome of the deletion.
*/
@ApiOperation({ summary: 'Delete screening task' })
@ApiResponse({
status: HttpStatus.NO_CONTENT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import { TypeOrmScreeningTaskRepository } from './repository/type-orm-screening-
imports: [
TypeOrmModule.forFeature([ScreeningTask]),
MikroOrmModule.forFeature([ScreeningTask]),
OrganizationProjectModule,
RolePermissionModule,
TaskModule,
OrganizationProjectModule,
CqrsModule
],
providers: [ScreeningTasksService, TypeOrmScreeningTaskRepository, ...CommandHandlers],
controllers: [ScreeningTasksController],
exports: [ScreeningTasksService, TypeOrmScreeningTaskRepository]
exports: []
})
export class ScreeningTasksModule {}
Loading
Loading