Skip to content

Commit

Permalink
Merge pull request #8514 from ever-co/feat/task-linked-issue-activity…
Browse files Browse the repository at this point in the history
…-log

[Feat] Task Linked Issue Activity Log
  • Loading branch information
rahul-rocket authored Nov 5, 2024
2 parents 6994627 + 25e8828 commit d7be486
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 68 deletions.
1 change: 1 addition & 0 deletions packages/contracts/src/base-entity.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,6 @@ export enum BaseEntityEnum {
OrganizationVendor = 'OrganizationVendor',
Task = 'Task',
TaskView = 'TaskView',
TaskLinkedIssue = 'TaskLinkedIssue',
User = 'User'
}
16 changes: 7 additions & 9 deletions packages/contracts/src/task-linked-issue.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IBasePerTenantAndOrganizationEntityModel } from './base-entity.model';
import { IBasePerTenantAndOrganizationEntityModel, ID } from './base-entity.model';
import { ITask } from './task.model';

export enum TaskRelatedIssuesRelationEnum {
Expand All @@ -8,23 +8,21 @@ export enum TaskRelatedIssuesRelationEnum {
CLONES = 4,
IS_DUPLICATED_BY = 5,
DUPLICATES = 6,
RELATES_TO = 7,
RELATES_TO = 7
}

export interface ITaskLinkedIssue
extends IBasePerTenantAndOrganizationEntityModel {
export interface ITaskLinkedIssue extends IBasePerTenantAndOrganizationEntityModel {
action: TaskRelatedIssuesRelationEnum;
taskFrom?: ITask;
taskFromId: ITask['id'];
taskFromId: ID;
taskTo?: ITask;
taskToId: ITask['id'];
taskToId: ID;
}

export interface ITaskLinkedIssueCreateInput extends ITaskLinkedIssue {}

export interface ITaskLinkedIssueUpdateInput
extends Partial<ITaskLinkedIssueCreateInput> {
id?: string;
export interface ITaskLinkedIssueUpdateInput extends Partial<ITaskLinkedIssueCreateInput> {
id?: ID;
}

export interface ILinkedIssueFindInput
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/activity-log/activity-log.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class ActivityLogService extends TenantAwareCrudService<ActivityLog> {
/**
* @description Create or Update Activity Log
* @template T
* @param {BaseEntityEnum} entityType - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.)
* @param {BaseEntityEnum} entity - Entity type for whom creating activity log (E.g : Task, OrganizationProject, etc.)
* @param {string} entityName - Name or Title of the entity
* @param {ActorTypeEnum} actor - The actor type performing the action (User or System)
* @param {ID} organizationId
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { TaskLinkedIssueCreateHandler } from './task-linked-issue-create.handler';
import { TaskLinkedIssueUpdateHandler } from './task-linked-issue-update.handler';

export const CommandHandlers = [TaskLinkedIssueCreateHandler, TaskLinkedIssueUpdateHandler];
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { ITaskLinkedIssue } from '@gauzy/contracts';
import { TaskLinkedIssueCreateCommand } from '../task-linked-issue-create.command';
import { TaskLinkedIssueService } from '../../task-linked-issue.service';

@CommandHandler(TaskLinkedIssueCreateCommand)
export class TaskLinkedIssueCreateHandler implements ICommandHandler<TaskLinkedIssueCreateCommand> {
constructor(private readonly taskLinkedIssueService: TaskLinkedIssueService) {}

public async execute(command: TaskLinkedIssueCreateCommand): Promise<ITaskLinkedIssue> {
const { input } = command;

return await this.taskLinkedIssueService.create(input);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { ITaskLinkedIssue } from '@gauzy/contracts';
import { TaskLinkedIssueUpdateCommand } from '../task-linked-issue-update.command';
import { TaskLinkedIssueService } from '../../task-linked-issue.service';

@CommandHandler(TaskLinkedIssueUpdateCommand)
export class TaskLinkedIssueUpdateHandler implements ICommandHandler<TaskLinkedIssueUpdateCommand> {
constructor(private readonly taskLinkedIssueService: TaskLinkedIssueService) {}

public async execute(command: TaskLinkedIssueUpdateCommand): Promise<ITaskLinkedIssue> {
const { id, input } = command;

return await this.taskLinkedIssueService.update(id, input);
}
}
2 changes: 2 additions & 0 deletions packages/core/src/tasks/linked-issue/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './task-linked-issue-create.command';
export * from './task-linked-issue-update.command';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ICommand } from '@nestjs/cqrs';
import { ITaskLinkedIssueCreateInput } from '@gauzy/contracts';

export class TaskLinkedIssueCreateCommand implements ICommand {
static readonly type = '[Task Linked Issue] Create';

constructor(public readonly input: ITaskLinkedIssueCreateInput) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ICommand } from '@nestjs/cqrs';
import { ID, ITaskLinkedIssueUpdateInput } from '@gauzy/contracts';

export class TaskLinkedIssueUpdateCommand implements ICommand {
static readonly type = '[Task Linked Issue] Update';

constructor(public readonly id: ID, public readonly input: ITaskLinkedIssueUpdateInput) {}
}
22 changes: 6 additions & 16 deletions packages/core/src/tasks/linked-issue/dto/task-linked-issue.dto.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
import { TaskRelatedIssuesRelationEnum } from '@gauzy/contracts';
import { ApiProperty } from '@nestjs/swagger';
import { ITaskLinkedIssue } from '@gauzy/contracts';
import { IntersectionType } from '@nestjs/swagger';
import { TenantOrganizationBaseDTO } from '../../../core/dto';
import { IsEnum, IsUUID } from 'class-validator';
import { TaskLinkedIssue } from '../task-linked-issue.entity';

export class TaskLinkedIssueDTO extends TenantOrganizationBaseDTO {
@ApiProperty({ type: () => String, enum: TaskRelatedIssuesRelationEnum })
@IsEnum(TaskRelatedIssuesRelationEnum)
action: TaskRelatedIssuesRelationEnum;

@ApiProperty({ type: () => String })
@IsUUID()
taskFromId: string;

@ApiProperty({ type: () => String })
@IsUUID()
taskToId: string;
}
export class TaskLinkedIssueDTO
extends IntersectionType(TenantOrganizationBaseDTO, TaskLinkedIssue)
implements ITaskLinkedIssue {}
145 changes: 126 additions & 19 deletions packages/core/src/tasks/linked-issue/task-linked-issue.controller.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,162 @@
import { Body, Controller, HttpCode, HttpStatus, Param, Post, Put, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ITaskLinkedIssue, PermissionsEnum } from '@gauzy/contracts';
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Param,
Post,
Put,
Query,
UseGuards
} from '@nestjs/common';
import { CommandBus } from '@nestjs/cqrs';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { DeleteResult } from 'typeorm';
import { ID, IPagination, ITaskLinkedIssue, PermissionsEnum } from '@gauzy/contracts';
import { CrudController, PaginationParams } from '../../core/crud';
import { PermissionGuard, TenantPermissionGuard } from '../../shared/guards';
import { UUIDValidationPipe, UseValidationPipe } from '../../shared/pipes';
import { Permissions } from '../../shared/decorators';
import { CrudController } from '../../core/crud';
import { TaskLinkedIssue } from './task-linked-issue.entity';
import { TaskLinkedIssueService } from './task-linked-issue.service';
import { CreateTaskLinkedIssueDTO, UpdateTaskLinkedIssueDTO } from './dto';
import { TaskLinkedIssueCreateCommand, TaskLinkedIssueUpdateCommand } from './commands';

@ApiTags('Linked Issue')
@UseGuards(TenantPermissionGuard, PermissionGuard)
@Permissions(PermissionsEnum.ALL_ORG_EDIT)
@Permissions(PermissionsEnum.ALL_ORG_EDIT, PermissionsEnum.ORG_TASK_EDIT)
@Controller()
export class TaskLinkedIssueController extends CrudController<TaskLinkedIssue> {
constructor(protected readonly taskLinkedIssueService: TaskLinkedIssueService) {
constructor(
private readonly taskLinkedIssueService: TaskLinkedIssueService,
private readonly commandBus: CommandBus
) {
super(taskLinkedIssueService);
}

/**
* Create new Linked Issue
* Finds all task linked issues based on the provided query parameters.
*
* @param entity
* @returns
* @param params - The pagination and filter parameters for the query.
* @returns A promise that resolves to a paginated list of task linked issues.
*/
@ApiOperation({
summary: 'Find all'
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Found task linked issues',
type: TaskLinkedIssue
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_TASK_VIEW)
@Get()
@UseValidationPipe()
async findAll(@Query() params: PaginationParams<TaskLinkedIssue>): Promise<IPagination<ITaskLinkedIssue>> {
return this.taskLinkedIssueService.findAll(params);
}

/**
* Creates a new task linked issue.
*
* @param entity - The input data for creating a task linked issue.
* @returns A promise that resolves to the created task linked issue.
*/
@ApiOperation({ summary: 'Create Task Linked Issue' })
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The record has been successfully created.'
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'Invalid input. The response body may contain clues as to what went wrong.'
})
@HttpCode(HttpStatus.CREATED)
@Permissions(PermissionsEnum.ALL_ORG_EDIT, PermissionsEnum.ORG_TASK_ADD)
@Post()
@UseValidationPipe({ whitelist: true })
async create(@Body() entity: CreateTaskLinkedIssueDTO): Promise<ITaskLinkedIssue> {
return await this.taskLinkedIssueService.create(entity);
return this.commandBus.execute(new TaskLinkedIssueCreateCommand(entity));
}

/**
* Update existing Linked Issue
* Updates an existing task linked issue.
*
* @param id
* @param entity
* @returns
* @param id - The ID of the task linked issue to update.
* @param entity - The input data for updating the task linked issue.
* @returns A promise that resolves to the updated task linked issue.
*/
@ApiOperation({ summary: 'Update an existing task linked issue' })
@ApiResponse({
status: HttpStatus.CREATED,
description: 'The record has been successfully edited.'
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'Invalid input. The response body may contain clues as to what went wrong.'
})
@HttpCode(HttpStatus.ACCEPTED)
@Permissions(PermissionsEnum.ALL_ORG_EDIT, PermissionsEnum.ORG_TASK_EDIT)
@Put(':id')
@UseValidationPipe({ whitelist: true })
async update(
@Param('id', UUIDValidationPipe) id: ITaskLinkedIssue['id'],
@Param('id', UUIDValidationPipe) id: ID,
@Body() entity: UpdateTaskLinkedIssueDTO
): Promise<ITaskLinkedIssue> {
return await this.taskLinkedIssueService.create({
...entity,
id
});
return this.commandBus.execute(new TaskLinkedIssueUpdateCommand(id, entity));
}

/**
* Deletes a task linked issue.
*
* @param id - The ID of the task linked issue to delete.
* @returns A promise that resolves to the result of the delete operation.
*/
@ApiOperation({ summary: 'Delete Task Linked Issue' })
@ApiResponse({
status: HttpStatus.NO_CONTENT,
description: 'The record has been successfully deleted'
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Record not found'
})
@HttpCode(HttpStatus.ACCEPTED)
@Permissions(PermissionsEnum.ALL_ORG_EDIT, PermissionsEnum.ORG_TASK_DELETE)
@Delete(':id')
async delete(@Param('id', UUIDValidationPipe) id: ID): Promise<DeleteResult> {
return this.taskLinkedIssueService.delete(id);
}

/**
* Soft deletes a task linked issue record.
*
* @param id - The ID of the task linked issue to soft delete.
* @returns A promise that resolves to the result of the soft delete operation.
*/
@ApiOperation({ summary: 'Soft delete Task Linked Issue record' })
@ApiResponse({
status: HttpStatus.OK,
description: 'The record has been successfully soft-deleted'
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Task Linked Issue record not found'
})
@HttpCode(HttpStatus.ACCEPTED)
@Permissions(PermissionsEnum.ALL_ORG_EDIT, PermissionsEnum.ORG_TASK_DELETE)
@Delete(':id/soft')
@UseValidationPipe({ whitelist: true })
async softRemove(@Param('id', UUIDValidationPipe) id: ID): Promise<any> {
return this.taskLinkedIssueService.softDelete(id);
}
}
23 changes: 9 additions & 14 deletions packages/core/src/tasks/linked-issue/task-linked-issue.entity.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
JoinColumn,
RelationId,
} from 'typeorm';
import { IsEnum, IsUUID } from 'class-validator';
import {
ITask,
ITaskLinkedIssue,
TaskRelatedIssuesRelationEnum,
} from '@gauzy/contracts';
import { JoinColumn, RelationId } from 'typeorm';
import { IsEnum, IsOptional, IsUUID } from 'class-validator';
import { ID, ITask, ITaskLinkedIssue, TaskRelatedIssuesRelationEnum } from '@gauzy/contracts';
import { Task } from './../task.entity';
import { TenantOrganizationBaseEntity } from './../../core/entities/internal';
import { ColumnIndex, MultiORMColumn, MultiORMEntity, MultiORMManyToOne } from './../../core/decorators/entity';
import { MikroOrmTaskLinkedIssueRepository } from './repository/mikro-orm-linked-issue.repository';

@MultiORMEntity('task_linked_issues', { mikroOrmRepository: () => MikroOrmTaskLinkedIssueRepository })
export class TaskLinkedIssue extends TenantOrganizationBaseEntity implements ITaskLinkedIssue {
@ApiProperty({ type: () => String, enum: TaskRelatedIssuesRelationEnum })
@MultiORMColumn()
@ApiProperty({ enum: TaskRelatedIssuesRelationEnum })
@IsEnum(TaskRelatedIssuesRelationEnum)
@MultiORMColumn()
action: TaskRelatedIssuesRelationEnum;

/*
Expand All @@ -27,6 +20,7 @@ export class TaskLinkedIssue extends TenantOrganizationBaseEntity implements ITa
|--------------------------------------------------------------------------
*/
@ApiPropertyOptional({ type: () => Task })
@IsOptional()
@MultiORMManyToOne(() => Task)
@JoinColumn()
taskFrom?: ITask;
Expand All @@ -36,12 +30,13 @@ export class TaskLinkedIssue extends TenantOrganizationBaseEntity implements ITa
@RelationId((it: TaskLinkedIssue) => it.taskFrom)
@ColumnIndex()
@MultiORMColumn({ relationId: true })
taskFromId: ITask['id'];
taskFromId: ID;

/**
* Task Linked Issues
*/
@ApiPropertyOptional({ type: () => Object })
@IsOptional()
@MultiORMManyToOne(() => Task, (it) => it.linkedIssues)
@JoinColumn()
taskTo?: ITask;
Expand All @@ -51,5 +46,5 @@ export class TaskLinkedIssue extends TenantOrganizationBaseEntity implements ITa
@RelationId((it: TaskLinkedIssue) => it.taskTo)
@ColumnIndex()
@MultiORMColumn({ relationId: true })
taskToId: ITask['id'];
taskToId: ID;
}
Loading

0 comments on commit d7be486

Please sign in to comment.