Compare commits
11 Commits
9b32f35582
...
743d1eb79d
| Author | SHA1 | Date | |
|---|---|---|---|
| 743d1eb79d | |||
| c2e0cb1bc6 | |||
| 6ad18d8f3e | |||
| db61030b44 | |||
| 31e3b5f00d | |||
| ff4a8dedba | |||
| 87772f46dd | |||
| 26b8268f73 | |||
| 3d59a2fa40 | |||
| bf98b8b9ce | |||
| 89d85e6d24 |
@@ -0,0 +1,28 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class TaskmanagerProject1782889623829 implements MigrationInterface {
|
||||
name = 'TaskmanagerProject1782889623829'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "tm_project_users" ("projectId" uuid NOT NULL, "userId" uuid NOT NULL, CONSTRAINT "PK_5969064e19a1efa76b91de6a065" PRIMARY KEY ("projectId", "userId"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_fcc8e135e4891925d288dbb14e" ON "tm_project_users" ("projectId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_8e2d2c9d639d5fd806159f8698" ON "tm_project_users" ("userId") `);
|
||||
await queryRunner.query(`ALTER TABLE "tm_projects" ADD "backgroundPicture" text`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_projects" ADD "backgroundColor" character varying(20)`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_projects" ADD "isActive" boolean NOT NULL DEFAULT true`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_project_users" ADD CONSTRAINT "FK_fcc8e135e4891925d288dbb14e5" FOREIGN KEY ("projectId") REFERENCES "tm_projects"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_project_users" ADD CONSTRAINT "FK_8e2d2c9d639d5fd806159f86980" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "tm_project_users" DROP CONSTRAINT "FK_8e2d2c9d639d5fd806159f86980"`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_project_users" DROP CONSTRAINT "FK_fcc8e135e4891925d288dbb14e5"`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_projects" DROP COLUMN "isActive"`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_projects" DROP COLUMN "backgroundColor"`);
|
||||
await queryRunner.query(`ALTER TABLE "tm_projects" DROP COLUMN "backgroundPicture"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_8e2d2c9d639d5fd806159f8698"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_fcc8e135e4891925d288dbb14e"`);
|
||||
await queryRunner.query(`DROP TABLE "tm_project_users"`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
import { CheckListItemService } from '../providers/check-list-item.service';
|
||||
import { CreateCheckListItemDto } from '../dto/check-list-item/create-check-list-item.dto';
|
||||
import { UpdateCheckListItemDto } from '../dto/check-list-item/update-check-list-item.dto';
|
||||
import { TMCheckListItem } from '../entities/check-list-item.entity';
|
||||
|
||||
@ApiTags('Task Manager - Check List Items')
|
||||
@Controller('task-manager/check-list-items')
|
||||
export class CheckListItemController {
|
||||
constructor(private readonly checkListItemService: CheckListItemService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get all check list items, optionally filtered by task' })
|
||||
@ApiQuery({ name: 'taskId', required: false, description: 'Filter check list items by task ID' })
|
||||
@ApiResponse({ status: 200, description: 'List of check list items', type: [TMCheckListItem] })
|
||||
findAll(@Query('taskId') taskId?: string): Promise<TMCheckListItem[]> {
|
||||
if (taskId) return this.checkListItemService.findByTask(taskId);
|
||||
return this.checkListItemService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get a check list item by ID' })
|
||||
@ApiParam({ name: 'id', description: 'CheckListItem ID' })
|
||||
@ApiResponse({ status: 200, description: 'CheckListItem found', type: TMCheckListItem })
|
||||
@ApiResponse({ status: 404, description: 'CheckListItem not found' })
|
||||
findOne(@Param('id') id: string): Promise<TMCheckListItem> {
|
||||
return this.checkListItemService.findOne(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new check list item' })
|
||||
@ApiResponse({ status: 201, description: 'CheckListItem created', type: TMCheckListItem })
|
||||
@ApiResponse({ status: 404, description: 'Task not found' })
|
||||
create(@Body() body: CreateCheckListItemDto): Promise<TMCheckListItem> {
|
||||
return this.checkListItemService.create(body);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@ApiOperation({ summary: 'Update a check list item' })
|
||||
@ApiParam({ name: 'id', description: 'CheckListItem ID' })
|
||||
@ApiResponse({ status: 200, description: 'CheckListItem updated', type: TMCheckListItem })
|
||||
@ApiResponse({ status: 404, description: 'CheckListItem or Task not found' })
|
||||
update(@Param('id') id: string, @Body() body: UpdateCheckListItemDto): Promise<TMCheckListItem> {
|
||||
return this.checkListItemService.update(id, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete a check list item' })
|
||||
@ApiParam({ name: 'id', description: 'CheckListItem ID' })
|
||||
@ApiResponse({ status: 200, description: 'CheckListItem deleted' })
|
||||
@ApiResponse({ status: 404, description: 'CheckListItem not found' })
|
||||
remove(@Param('id') id: string): Promise<void> {
|
||||
return this.checkListItemService.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
import { ProjectService } from '../providers/project.service';
|
||||
import { CreateProjectDto } from '../dto/project/create-project.dto';
|
||||
import { UpdateProjectDto } from '../dto/project/update-project.dto';
|
||||
import { TMProject } from '../entities/project.entity';
|
||||
|
||||
@ApiTags('Task Manager - Projects')
|
||||
@Controller('task-manager/projects')
|
||||
export class ProjectController {
|
||||
constructor(private readonly projectService: ProjectService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get all projects, optionally filtered by workspace' })
|
||||
@ApiQuery({ name: 'workspaceId', required: false, description: 'Filter projects by workspace ID' })
|
||||
@ApiResponse({ status: 200, description: 'List of projects', type: [TMProject] })
|
||||
findAll(@Query('workspaceId') workspaceId?: string): Promise<TMProject[]> {
|
||||
if (workspaceId) return this.projectService.findByWorkspace(workspaceId);
|
||||
return this.projectService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get a project by ID' })
|
||||
@ApiParam({ name: 'id', description: 'Project ID' })
|
||||
@ApiResponse({ status: 200, description: 'Project found', type: TMProject })
|
||||
@ApiResponse({ status: 404, description: 'Project not found' })
|
||||
findOne(@Param('id') id: string): Promise<TMProject> {
|
||||
return this.projectService.findOne(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new project' })
|
||||
@ApiResponse({ status: 201, description: 'Project created', type: TMProject })
|
||||
@ApiResponse({ status: 400, description: 'One or more users are not members of the workspace' })
|
||||
@ApiResponse({ status: 404, description: 'Workspace not found' })
|
||||
create(@Body() body: CreateProjectDto): Promise<TMProject> {
|
||||
return this.projectService.create(body);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@ApiOperation({ summary: 'Update a project' })
|
||||
@ApiParam({ name: 'id', description: 'Project ID' })
|
||||
@ApiResponse({ status: 200, description: 'Project updated', type: TMProject })
|
||||
@ApiResponse({ status: 400, description: 'One or more users are not members of the workspace' })
|
||||
@ApiResponse({ status: 404, description: 'Project not found' })
|
||||
update(@Param('id') id: string, @Body() body: UpdateProjectDto): Promise<TMProject> {
|
||||
return this.projectService.update(id, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete a project' })
|
||||
@ApiParam({ name: 'id', description: 'Project ID' })
|
||||
@ApiResponse({ status: 200, description: 'Project deleted' })
|
||||
@ApiResponse({ status: 404, description: 'Project not found' })
|
||||
remove(@Param('id') id: string): Promise<TMProject> {
|
||||
return this.projectService.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from "@nestjs/common";
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from "@nestjs/swagger";
|
||||
import { TaskPhaseService } from "../providers/task-phase.service";
|
||||
import { CreateTaskPhaseDto } from "../dto/task-phase/create-task-phase.dto";
|
||||
import { UpdateTaskPhaseDto } from "../dto/task-phase/update-task-phase.dto";
|
||||
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||
|
||||
@ApiTags("Task Manager - Task Phases")
|
||||
@Controller("task-manager/task-phases")
|
||||
export class TaskPhaseController {
|
||||
constructor(private readonly taskPhaseService: TaskPhaseService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: "Get all task phases, optionally filtered by project" })
|
||||
@ApiQuery({ name: "projectId", required: false, description: "Filter task phases by project ID" })
|
||||
@ApiResponse({ status: 200, description: "List of task phases", type: [TMTaskPhase] })
|
||||
findAll(@Query("projectId") projectId?: string): Promise<TMTaskPhase[]> {
|
||||
if (projectId) return this.taskPhaseService.findByProject(projectId);
|
||||
return this.taskPhaseService.findAll();
|
||||
}
|
||||
|
||||
@Get(":id")
|
||||
@ApiOperation({ summary: "Get a task phase by ID" })
|
||||
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
||||
@ApiResponse({ status: 200, description: "TaskPhase found", type: TMTaskPhase })
|
||||
@ApiResponse({ status: 404, description: "TaskPhase not found" })
|
||||
findOne(@Param("id") id: string): Promise<TMTaskPhase> {
|
||||
return this.taskPhaseService.findOne(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: "Create a new task phase" })
|
||||
@ApiResponse({ status: 201, description: "TaskPhase created", type: TMTaskPhase })
|
||||
@ApiResponse({ status: 404, description: "Project not found" })
|
||||
create(@Body() body: CreateTaskPhaseDto): Promise<TMTaskPhase> {
|
||||
return this.taskPhaseService.create(body);
|
||||
}
|
||||
|
||||
@Patch(":id")
|
||||
@ApiOperation({ summary: "Update a task phase" })
|
||||
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
||||
@ApiResponse({ status: 200, description: "TaskPhase updated", type: TMTaskPhase })
|
||||
@ApiResponse({ status: 404, description: "TaskPhase or Project not found" })
|
||||
update(@Param("id") id: string, @Body() body: UpdateTaskPhaseDto): Promise<TMTaskPhase> {
|
||||
return this.taskPhaseService.update(id, body);
|
||||
}
|
||||
|
||||
@Delete(":id")
|
||||
@ApiOperation({ summary: "Delete a task phase" })
|
||||
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
||||
@ApiResponse({ status: 200, description: "TaskPhase deleted" })
|
||||
@ApiResponse({ status: 404, description: "TaskPhase not found" })
|
||||
remove(@Param("id") id: string): Promise<void> {
|
||||
return this.taskPhaseService.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
import { TaskService } from '../providers/task.service';
|
||||
import { CreateTaskDto } from '../dto/task/create-task.dto';
|
||||
import { UpdateTaskDto } from '../dto/task/update-task.dto';
|
||||
import { ChangeTaskPhaseDto } from '../dto/task/change-task-phase.dto';
|
||||
import { TMTask } from '../entities/task.entity';
|
||||
|
||||
@ApiTags('Task Manager - Tasks')
|
||||
@Controller('task-manager/tasks')
|
||||
export class TaskController {
|
||||
constructor(private readonly taskService: TaskService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get all tasks, optionally filtered by phase' })
|
||||
@ApiQuery({ name: 'taskPhaseId', required: false, description: 'Filter tasks by task phase ID' })
|
||||
@ApiResponse({ status: 200, description: 'List of tasks', type: [TMTask] })
|
||||
findAll(@Query('taskPhaseId') taskPhaseId?: string): Promise<TMTask[]> {
|
||||
if (taskPhaseId) return this.taskService.findByPhase(taskPhaseId);
|
||||
return this.taskService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get a task by ID' })
|
||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
||||
@ApiResponse({ status: 200, description: 'Task found', type: TMTask })
|
||||
@ApiResponse({ status: 404, description: 'Task not found' })
|
||||
findOne(@Param('id') id: string): Promise<TMTask> {
|
||||
return this.taskService.findOne(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new task' })
|
||||
@ApiResponse({ status: 201, description: 'Task created', type: TMTask })
|
||||
@ApiResponse({ status: 404, description: 'TaskPhase not found' })
|
||||
create(@Body() body: CreateTaskDto): Promise<TMTask> {
|
||||
return this.taskService.create(body);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@ApiOperation({ summary: 'Update a task' })
|
||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
||||
@ApiResponse({ status: 200, description: 'Task updated', type: TMTask })
|
||||
@ApiResponse({ status: 404, description: 'Task or TaskPhase not found' })
|
||||
update(@Param('id') id: string, @Body() body: UpdateTaskDto): Promise<TMTask> {
|
||||
return this.taskService.update(id, body);
|
||||
}
|
||||
|
||||
@Patch(':id/change-phase')
|
||||
@ApiOperation({ summary: 'Move a task to a different phase within the same project' })
|
||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
||||
@ApiResponse({ status: 200, description: 'Task phase changed', type: TMTask })
|
||||
@ApiResponse({ status: 400, description: 'Target phase belongs to a different project' })
|
||||
@ApiResponse({ status: 404, description: 'Task or TaskPhase not found' })
|
||||
changePhase(@Param('id') id: string, @Body() body: ChangeTaskPhaseDto): Promise<TMTask> {
|
||||
return this.taskService.changePhase(id, body);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete a task' })
|
||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
||||
@ApiResponse({ status: 200, description: 'Task deleted' })
|
||||
@ApiResponse({ status: 404, description: 'Task not found' })
|
||||
remove(@Param('id') id: string): Promise<void> {
|
||||
return this.taskService.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsString, IsNotEmpty, IsUUID, IsBoolean, MaxLength } from "class-validator";
|
||||
|
||||
export class CreateCheckListItemDto {
|
||||
@ApiProperty({ description: "Title of the check list item", example: "Write unit tests" })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(150)
|
||||
title: string;
|
||||
|
||||
@ApiProperty({ description: "Whether the check list item is done", example: false })
|
||||
@IsBoolean()
|
||||
@IsNotEmpty()
|
||||
isDone: boolean;
|
||||
|
||||
@ApiProperty({ description: "ID of the task this check list item belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
taskId: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { CreateCheckListItemDto } from './create-check-list-item.dto';
|
||||
|
||||
export class UpdateCheckListItemDto extends PartialType(CreateCheckListItemDto) {}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsString, IsOptional, IsNotEmpty, IsUUID, IsDateString, MaxLength } from "class-validator";
|
||||
import { IsString, IsOptional, IsNotEmpty, IsUUID, IsDateString, IsBoolean, MaxLength } from "class-validator";
|
||||
|
||||
export class CreateProjectDto {
|
||||
@ApiProperty({ description: "Name of the project", example: "Mobile App Redesign" })
|
||||
@@ -33,8 +33,29 @@ export class CreateProjectDto {
|
||||
@IsOptional()
|
||||
backgroundPicture?: string;
|
||||
|
||||
@ApiProperty({ description: "Background color of the project (hex or named)", required: false, example: "#4F46E5" })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@MaxLength(20)
|
||||
backgroundColor?: string;
|
||||
|
||||
@ApiProperty({ description: "Whether the project is active", required: false, default: true, example: true })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
isActive?: boolean;
|
||||
|
||||
@ApiProperty({ description: "ID of the workspace this project belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
workspaceId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "IDs of users to assign to the project (must be members of the workspace)",
|
||||
required: false,
|
||||
type: [String],
|
||||
example: ["b2c3d4e5-f6a7-8901-bcde-f12345678901"],
|
||||
})
|
||||
@IsUUID("4", { each: true })
|
||||
@IsOptional()
|
||||
userIds?: string[];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { CreateProjectDto } from './create-project.dto';
|
||||
import { PartialType } from "@nestjs/swagger";
|
||||
import { CreateProjectDto } from "./create-project.dto";
|
||||
|
||||
export class UpdateProjectDto extends PartialType(CreateProjectDto) {}
|
||||
export class UpdateProjectDto extends PartialType(CreateProjectDto) {}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsString, IsOptional, IsNotEmpty, IsUUID, IsInt, MaxLength, Min } from "class-validator";
|
||||
|
||||
export class CreateTaskPhaseDto {
|
||||
@ApiProperty({ description: "Name of the task phase", example: "In Progress" })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(100)
|
||||
name: string;
|
||||
|
||||
@ApiProperty({ description: "Display order of the task phase", required: false, example: 1 })
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
@Min(0)
|
||||
order?: number;
|
||||
|
||||
@ApiProperty({ description: "Color code for the task phase", required: false, example: "#4F46E5" })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@MaxLength(20)
|
||||
color?: string;
|
||||
|
||||
@ApiProperty({ description: "ID of the project this phase belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
projectId: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from "@nestjs/swagger";
|
||||
import { CreateTaskPhaseDto } from "./create-task-phase.dto";
|
||||
|
||||
export class UpdateTaskPhaseDto extends PartialType(CreateTaskPhaseDto) {}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsUUID, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class ChangeTaskPhaseDto {
|
||||
@ApiProperty({ description: 'ID of the new task phase', example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890' })
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
taskPhaseId: string;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsString, IsOptional, IsNotEmpty, IsUUID, IsDateString, MaxLength } from "class-validator";
|
||||
|
||||
export class CreateTaskDto {
|
||||
@ApiProperty({ description: "Title of the task", example: "Implement login page" })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(150)
|
||||
title: string;
|
||||
|
||||
@ApiProperty({ description: "Description of the task", required: false, example: "Implement the login page with JWT auth" })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string;
|
||||
|
||||
@ApiProperty({ description: "Color code for the task", required: false, example: "#4F46E5" })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@MaxLength(20)
|
||||
color?: string;
|
||||
|
||||
@ApiProperty({ description: "Start date of the task", required: false, example: "2026-07-01" })
|
||||
@IsDateString()
|
||||
@IsOptional()
|
||||
startDate?: string;
|
||||
|
||||
@ApiProperty({ description: "End date of the task", required: false, example: "2026-07-15" })
|
||||
@IsDateString()
|
||||
@IsOptional()
|
||||
endDate?: string;
|
||||
|
||||
@ApiProperty({ description: "ID of the task phase this task belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
taskPhaseId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "IDs of users to assign to the task",
|
||||
required: false,
|
||||
type: [String],
|
||||
example: ["b2c3d4e5-f6a7-8901-bcde-f12345678901"],
|
||||
})
|
||||
@IsUUID("4", { each: true })
|
||||
@IsOptional()
|
||||
userIds?: string[];
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from "@nestjs/swagger";
|
||||
import { CreateTaskDto } from "./create-task.dto";
|
||||
|
||||
export class UpdateTaskDto extends PartialType(CreateTaskDto) {}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm";
|
||||
import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany } from "typeorm";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { TMWorkspace } from "./workspace.entity";
|
||||
import { TMTaskPhase } from "./task-phase.entity";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
|
||||
@Entity("tm_projects")
|
||||
export class TMProject extends BaseEntity {
|
||||
@@ -20,6 +21,12 @@ export class TMProject extends BaseEntity {
|
||||
@Column({ type: "text", nullable: true })
|
||||
backgroundPicture: string;
|
||||
|
||||
@Column({ type: "varchar", length: 20, nullable: true })
|
||||
backgroundColor: string;
|
||||
|
||||
@Column({ type: "boolean", default: true })
|
||||
isActive: boolean;
|
||||
|
||||
// --- Relations ---
|
||||
|
||||
@ManyToOne(() => TMWorkspace, (workspace) => workspace.projects, {
|
||||
@@ -36,4 +43,12 @@ export class TMProject extends BaseEntity {
|
||||
cascade: ["insert", "update"],
|
||||
})
|
||||
taskPhases: TMTaskPhase[];
|
||||
|
||||
@ManyToMany(() => User, (user) => user.projects)
|
||||
@JoinTable({
|
||||
name: "tm_project_users",
|
||||
joinColumn: { name: "projectId", referencedColumnName: "id" },
|
||||
inverseJoinColumn: { name: "userId", referencedColumnName: "id" },
|
||||
})
|
||||
users: User[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { CheckListItemRepository } from "../repositories/check-list-item.repository";
|
||||
import { TaskRepository } from "../repositories/task.repository";
|
||||
import { TMCheckListItem } from "../entities/check-list-item.entity";
|
||||
import { CreateCheckListItemDto } from "../dto/check-list-item/create-check-list-item.dto";
|
||||
import { UpdateCheckListItemDto } from "../dto/check-list-item/update-check-list-item.dto";
|
||||
|
||||
@Injectable()
|
||||
export class CheckListItemService {
|
||||
constructor(
|
||||
private readonly checkListItemRepository: CheckListItemRepository,
|
||||
private readonly taskRepository: TaskRepository,
|
||||
) {}
|
||||
|
||||
findAll(): Promise<TMCheckListItem[]> {
|
||||
return this.checkListItemRepository.findAll();
|
||||
}
|
||||
|
||||
findByTask(taskId: string): Promise<TMCheckListItem[]> {
|
||||
return this.checkListItemRepository.findByTask(taskId);
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<TMCheckListItem> {
|
||||
const checkListItem = await this.checkListItemRepository.findOneById(id);
|
||||
if (!checkListItem) throw new NotFoundException(`CheckListItem #${id} not found`);
|
||||
return checkListItem;
|
||||
}
|
||||
|
||||
async create(dto: CreateCheckListItemDto): Promise<TMCheckListItem> {
|
||||
const task = await this.taskRepository.findOneById(dto.taskId);
|
||||
if (!task) throw new NotFoundException(`Task #${dto.taskId} not found`);
|
||||
|
||||
const checkListItem = this.checkListItemRepository.create(dto);
|
||||
return this.checkListItemRepository.save(checkListItem);
|
||||
}
|
||||
|
||||
async update(id: string, dto: UpdateCheckListItemDto): Promise<TMCheckListItem> {
|
||||
const checkListItem = await this.findOne(id);
|
||||
|
||||
if (dto.taskId) {
|
||||
const task = await this.taskRepository.findOneById(dto.taskId);
|
||||
if (!task) throw new NotFoundException(`Task #${dto.taskId} not found`);
|
||||
}
|
||||
|
||||
Object.assign(checkListItem, dto);
|
||||
return this.checkListItemRepository.save(checkListItem);
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.findOne(id);
|
||||
await this.checkListItemRepository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { In, Repository } from "typeorm";
|
||||
import { ProjectRepository } from "../repositories/project.repository";
|
||||
import { TMProject } from "../entities/project.entity";
|
||||
import { CreateProjectDto } from "../dto/project/create-project.dto";
|
||||
import { UpdateProjectDto } from "../dto/project/update-project.dto";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
import { WorkspaceRepository } from "../repositories/workspace.repository";
|
||||
|
||||
@Injectable()
|
||||
export class ProjectService {
|
||||
constructor(
|
||||
private readonly projectRepository: ProjectRepository,
|
||||
private readonly workspaceRepository: WorkspaceRepository,
|
||||
@InjectRepository(User)
|
||||
private readonly userRepository: Repository<User>,
|
||||
) {}
|
||||
|
||||
findAll(): Promise<TMProject[]> {
|
||||
return this.projectRepository.findAll();
|
||||
}
|
||||
|
||||
findByWorkspace(workspaceId: string): Promise<TMProject[]> {
|
||||
return this.projectRepository.findByWorkspace(workspaceId);
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<TMProject> {
|
||||
const project = await this.projectRepository.findOneById(id);
|
||||
if (!project) throw new NotFoundException(`Project #${id} not found`);
|
||||
return project;
|
||||
}
|
||||
|
||||
async create(dto: CreateProjectDto): Promise<TMProject> {
|
||||
const { userIds, startDate, ...rest } = dto;
|
||||
|
||||
const workspace = await this.workspaceRepository.findOneById(dto.workspaceId);
|
||||
if (!workspace) throw new NotFoundException(`Workspace #${dto.workspaceId} not found`);
|
||||
|
||||
const project = this.projectRepository.create({
|
||||
...rest,
|
||||
startDate: new Date(startDate),
|
||||
});
|
||||
|
||||
if (userIds?.length) {
|
||||
const workspaceUserIds = workspace.users.map((u) => u.id);
|
||||
const invalidUsers = userIds.filter((id) => !workspaceUserIds.includes(id));
|
||||
if (invalidUsers.length) {
|
||||
throw new BadRequestException(`Users [${invalidUsers.join(", ")}] are not members of this workspace`);
|
||||
}
|
||||
project.users = await this.userRepository.findBy({ id: In(userIds) });
|
||||
}
|
||||
|
||||
return this.projectRepository.save(project);
|
||||
}
|
||||
|
||||
async update(id: string, dto: UpdateProjectDto): Promise<TMProject> {
|
||||
const project = await this.findOne(id);
|
||||
const { userIds, startDate, ...rest } = dto;
|
||||
|
||||
Object.assign(project, {
|
||||
...rest,
|
||||
startDate: startDate ? new Date(startDate) : project.startDate,
|
||||
});
|
||||
|
||||
if (userIds) {
|
||||
if (userIds.length) {
|
||||
const workspaceId = dto.workspaceId ?? project.workspaceId;
|
||||
const workspace = await this.workspaceRepository.findOneById(workspaceId);
|
||||
if (!workspace) throw new NotFoundException(`Workspace #${workspaceId} not found`);
|
||||
|
||||
const workspaceUserIds = workspace.users.map((u) => u.id);
|
||||
const invalidUsers = userIds.filter((uid) => !workspaceUserIds.includes(uid));
|
||||
if (invalidUsers.length) {
|
||||
throw new BadRequestException(`Users [${invalidUsers.join(", ")}] are not members of this workspace`);
|
||||
}
|
||||
project.users = await this.userRepository.findBy({ id: In(userIds) });
|
||||
} else {
|
||||
project.users = [];
|
||||
}
|
||||
}
|
||||
|
||||
return this.projectRepository.save(project);
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<TMProject> {
|
||||
const project = await this.findOne(id);
|
||||
await this.projectRepository.delete(id);
|
||||
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { TaskPhaseRepository } from "../repositories/task-phase.repository";
|
||||
import { ProjectRepository } from "../repositories/project.repository";
|
||||
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||
import { CreateTaskPhaseDto } from "../dto/task-phase/create-task-phase.dto";
|
||||
import { UpdateTaskPhaseDto } from "../dto/task-phase/update-task-phase.dto";
|
||||
|
||||
@Injectable()
|
||||
export class TaskPhaseService {
|
||||
constructor(
|
||||
private readonly taskPhaseRepository: TaskPhaseRepository,
|
||||
private readonly projectRepository: ProjectRepository,
|
||||
) {}
|
||||
|
||||
findAll(): Promise<TMTaskPhase[]> {
|
||||
return this.taskPhaseRepository.findAll();
|
||||
}
|
||||
|
||||
findByProject(projectId: string): Promise<TMTaskPhase[]> {
|
||||
return this.taskPhaseRepository.findByProject(projectId);
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<TMTaskPhase> {
|
||||
const taskPhase = await this.taskPhaseRepository.findOneById(id);
|
||||
if (!taskPhase) throw new NotFoundException(`TaskPhase #${id} not found`);
|
||||
return taskPhase;
|
||||
}
|
||||
|
||||
async create(dto: CreateTaskPhaseDto): Promise<TMTaskPhase> {
|
||||
const project = await this.projectRepository.findOneById(dto.projectId);
|
||||
if (!project) throw new NotFoundException(`Project #${dto.projectId} not found`);
|
||||
|
||||
const taskPhase = this.taskPhaseRepository.create(dto);
|
||||
return this.taskPhaseRepository.save(taskPhase);
|
||||
}
|
||||
|
||||
async update(id: string, dto: UpdateTaskPhaseDto): Promise<TMTaskPhase> {
|
||||
const taskPhase = await this.findOne(id);
|
||||
|
||||
if (dto.projectId) {
|
||||
const project = await this.projectRepository.findOneById(dto.projectId);
|
||||
if (!project) throw new NotFoundException(`Project #${dto.projectId} not found`);
|
||||
}
|
||||
|
||||
Object.assign(taskPhase, dto);
|
||||
return this.taskPhaseRepository.save(taskPhase);
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.findOne(id);
|
||||
await this.taskPhaseRepository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { TaskRepository } from '../repositories/task.repository';
|
||||
import { TaskPhaseRepository } from '../repositories/task-phase.repository';
|
||||
import { TMTask } from '../entities/task.entity';
|
||||
import { CreateTaskDto } from '../dto/task/create-task.dto';
|
||||
import { UpdateTaskDto } from '../dto/task/update-task.dto';
|
||||
import { ChangeTaskPhaseDto } from '../dto/task/change-task-phase.dto';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class TaskService {
|
||||
constructor(
|
||||
private readonly taskRepository: TaskRepository,
|
||||
private readonly taskPhaseRepository: TaskPhaseRepository,
|
||||
@InjectRepository(User)
|
||||
private readonly userRepository: Repository<User>,
|
||||
) {}
|
||||
|
||||
findAll(): Promise<TMTask[]> {
|
||||
return this.taskRepository.findAll();
|
||||
}
|
||||
|
||||
findByPhase(taskPhaseId: string): Promise<TMTask[]> {
|
||||
return this.taskRepository.findByPhase(taskPhaseId);
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<TMTask> {
|
||||
const task = await this.taskRepository.findOneById(id);
|
||||
if (!task) throw new NotFoundException(`Task #${id} not found`);
|
||||
return task;
|
||||
}
|
||||
|
||||
async create(dto: CreateTaskDto): Promise<TMTask> {
|
||||
const { userIds, startDate, endDate, ...rest } = dto;
|
||||
|
||||
const taskPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId);
|
||||
if (!taskPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`);
|
||||
|
||||
const task = this.taskRepository.create({
|
||||
...rest,
|
||||
startDate: startDate ? new Date(startDate) : undefined,
|
||||
endDate: endDate ? new Date(endDate) : undefined,
|
||||
});
|
||||
|
||||
if (userIds?.length) {
|
||||
task.users = await this.userRepository.findBy({ id: In(userIds) });
|
||||
}
|
||||
|
||||
return this.taskRepository.save(task);
|
||||
}
|
||||
|
||||
async update(id: string, dto: UpdateTaskDto): Promise<TMTask> {
|
||||
const task = await this.findOne(id);
|
||||
const { userIds, startDate, endDate, ...rest } = dto;
|
||||
|
||||
if (dto.taskPhaseId) {
|
||||
const taskPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId);
|
||||
if (!taskPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`);
|
||||
}
|
||||
|
||||
Object.assign(task, {
|
||||
...rest,
|
||||
startDate: startDate ? new Date(startDate) : task.startDate,
|
||||
endDate: endDate ? new Date(endDate) : task.endDate,
|
||||
});
|
||||
|
||||
if (userIds) {
|
||||
task.users = userIds.length
|
||||
? await this.userRepository.findBy({ id: In(userIds) })
|
||||
: [];
|
||||
}
|
||||
|
||||
return this.taskRepository.save(task);
|
||||
}
|
||||
|
||||
async changePhase(id: string, dto: ChangeTaskPhaseDto): Promise<TMTask> {
|
||||
const task = await this.findOne(id);
|
||||
|
||||
const newPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId);
|
||||
if (!newPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`);
|
||||
|
||||
if (task.taskPhase.projectId !== newPhase.projectId) {
|
||||
throw new BadRequestException(
|
||||
`TaskPhase #${dto.taskPhaseId} does not belong to the same project as the current phase`,
|
||||
);
|
||||
}
|
||||
|
||||
task.taskPhaseId = dto.taskPhaseId;
|
||||
task.taskPhase = newPhase;
|
||||
|
||||
return this.taskRepository.save(task);
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.findOne(id);
|
||||
await this.taskRepository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { TMCheckListItem } from '../entities/check-list-item.entity';
|
||||
|
||||
@Injectable()
|
||||
export class CheckListItemRepository {
|
||||
constructor(
|
||||
@InjectRepository(TMCheckListItem)
|
||||
private readonly repository: Repository<TMCheckListItem>,
|
||||
) {}
|
||||
|
||||
findAll() {
|
||||
return this.repository.find({
|
||||
relations: ['task'],
|
||||
});
|
||||
}
|
||||
|
||||
findByTask(taskId: string) {
|
||||
return this.repository.find({
|
||||
where: { taskId },
|
||||
});
|
||||
}
|
||||
|
||||
findOneById(id: string) {
|
||||
return this.repository.findOne({
|
||||
where: { id },
|
||||
relations: ['task'],
|
||||
});
|
||||
}
|
||||
|
||||
create(data: Partial<TMCheckListItem>) {
|
||||
return this.repository.create(data);
|
||||
}
|
||||
|
||||
save(checkListItem: TMCheckListItem) {
|
||||
return this.repository.save(checkListItem);
|
||||
}
|
||||
|
||||
update(id: string, data: Partial<TMCheckListItem>) {
|
||||
return this.repository.update(id, data);
|
||||
}
|
||||
|
||||
delete(id: string) {
|
||||
return this.repository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { TMProject } from "../entities/project.entity";
|
||||
|
||||
@Injectable()
|
||||
export class ProjectRepository {
|
||||
constructor(
|
||||
@InjectRepository(TMProject)
|
||||
private readonly repository: Repository<TMProject>,
|
||||
) {}
|
||||
|
||||
findAll() {
|
||||
return this.repository.find({
|
||||
relations: ["workspace", "taskPhases", "users"],
|
||||
});
|
||||
}
|
||||
|
||||
findByWorkspace(workspaceId: string) {
|
||||
return this.repository.find({
|
||||
where: { workspaceId },
|
||||
relations: ["taskPhases", "users"],
|
||||
});
|
||||
}
|
||||
|
||||
findOneById(id: string) {
|
||||
return this.repository.findOne({
|
||||
where: { id },
|
||||
relations: ["workspace", "taskPhases", "users"],
|
||||
});
|
||||
}
|
||||
|
||||
create(data: Partial<TMProject>) {
|
||||
return this.repository.create(data);
|
||||
}
|
||||
|
||||
save(project: TMProject) {
|
||||
return this.repository.save(project);
|
||||
}
|
||||
|
||||
update(id: string, data: Partial<TMProject>) {
|
||||
return this.repository.update(id, data);
|
||||
}
|
||||
|
||||
delete(id: string) {
|
||||
return this.repository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||
|
||||
@Injectable()
|
||||
export class TaskPhaseRepository {
|
||||
constructor(
|
||||
@InjectRepository(TMTaskPhase)
|
||||
private readonly repository: Repository<TMTaskPhase>,
|
||||
) {}
|
||||
|
||||
findAll() {
|
||||
return this.repository.find({
|
||||
relations: ["project", "tasks"],
|
||||
order: { order: "ASC" },
|
||||
});
|
||||
}
|
||||
|
||||
findByProject(projectId: string) {
|
||||
return this.repository.find({
|
||||
where: { projectId },
|
||||
relations: ["tasks"],
|
||||
order: { order: "ASC" },
|
||||
});
|
||||
}
|
||||
|
||||
findOneById(id: string) {
|
||||
return this.repository.findOne({
|
||||
where: { id },
|
||||
relations: ["project", "tasks"],
|
||||
});
|
||||
}
|
||||
|
||||
create(data: Partial<TMTaskPhase>) {
|
||||
return this.repository.create(data);
|
||||
}
|
||||
|
||||
save(taskPhase: TMTaskPhase) {
|
||||
return this.repository.save(taskPhase);
|
||||
}
|
||||
|
||||
update(id: string, data: Partial<TMTaskPhase>) {
|
||||
return this.repository.update(id, data);
|
||||
}
|
||||
|
||||
delete(id: string) {
|
||||
return this.repository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { TMTask } from "../entities/task.entity";
|
||||
|
||||
@Injectable()
|
||||
export class TaskRepository {
|
||||
constructor(
|
||||
@InjectRepository(TMTask)
|
||||
private readonly repository: Repository<TMTask>,
|
||||
) {}
|
||||
|
||||
findAll() {
|
||||
return this.repository.find({
|
||||
relations: ["taskPhase", "remarks", "attachments", "checkListItems", "users"],
|
||||
});
|
||||
}
|
||||
|
||||
findByPhase(taskPhaseId: string) {
|
||||
return this.repository.find({
|
||||
where: { taskPhaseId },
|
||||
relations: ["remarks", "attachments", "checkListItems", "users"],
|
||||
});
|
||||
}
|
||||
|
||||
findOneById(id: string) {
|
||||
return this.repository.findOne({
|
||||
where: { id },
|
||||
relations: ["taskPhase", "remarks", "attachments", "checkListItems", "users"],
|
||||
});
|
||||
}
|
||||
|
||||
create(data: Partial<TMTask>) {
|
||||
return this.repository.create(data);
|
||||
}
|
||||
|
||||
save(task: TMTask) {
|
||||
return this.repository.save(task);
|
||||
}
|
||||
|
||||
update(id: string, data: Partial<TMTask>) {
|
||||
return this.repository.update(id, data);
|
||||
}
|
||||
|
||||
delete(id: string) {
|
||||
return this.repository.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -16,29 +16,58 @@ import { User } from "../users/entities/user.entity";
|
||||
import { WorkspaceTypeService } from "./providers/workspace-type.service";
|
||||
import { WorkspaceTypeRepository } from "./repositories/workspace-type.repository";
|
||||
import { WorkspaceTypeController } from "./controllers/workspace-type.controller";
|
||||
|
||||
// import { WorkspaceTypeService } from './providers/workspace-type.service';
|
||||
// import { WorkspaceService } from './providers/workspace.service';
|
||||
// import { ProjectService } from './providers/project.service';
|
||||
// import { TaskPhaseService } from './providers/task-phase.service';
|
||||
// import { TaskService } from './providers/task.service';
|
||||
|
||||
// import { TaskManagerController } from './task-manager.controller';
|
||||
import { ProjectController } from "./controllers/project.controller";
|
||||
import { ProjectRepository } from "./repositories/project.repository";
|
||||
import { ProjectService } from "./providers/project.service";
|
||||
import { TaskPhaseService } from "./providers/task-phase.service";
|
||||
import { TaskPhaseRepository } from "./repositories/task-phase.repository";
|
||||
import { TaskRepository } from "./repositories/task.repository";
|
||||
import { TaskService } from "./providers/task.service";
|
||||
import { CheckListItemRepository } from "./repositories/check-list-item.repository";
|
||||
import { CheckListItemService } from "./providers/check-list-item.service";
|
||||
import { TaskPhaseController } from "./controllers/task-phase.controller";
|
||||
import { TaskController } from "./controllers/task.controller";
|
||||
import { CheckListItemController } from "./controllers/check-list-item.controller";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([TMWorkspaceType, TMWorkspace, TMProject, TMTaskPhase, TMTask, TMRemark, TMAttachment, TMCheckListItem, User]),
|
||||
],
|
||||
controllers: [WorkspaceController, WorkspaceTypeController],
|
||||
controllers: [
|
||||
WorkspaceController,
|
||||
WorkspaceTypeController,
|
||||
ProjectController,
|
||||
TaskPhaseController,
|
||||
TaskController,
|
||||
CheckListItemController,
|
||||
],
|
||||
providers: [
|
||||
WorkspaceRepository,
|
||||
WorkspaceService,
|
||||
WorkspaceTypeRepository,
|
||||
WorkspaceTypeService,
|
||||
// ProjectService,
|
||||
// TaskPhaseService,
|
||||
// TaskService,
|
||||
ProjectRepository,
|
||||
ProjectService,
|
||||
TaskPhaseRepository,
|
||||
TaskPhaseService,
|
||||
TaskRepository,
|
||||
TaskService,
|
||||
CheckListItemRepository,
|
||||
CheckListItemService,
|
||||
],
|
||||
exports: [
|
||||
WorkspaceRepository,
|
||||
WorkspaceService,
|
||||
WorkspaceTypeRepository,
|
||||
WorkspaceTypeService,
|
||||
ProjectRepository,
|
||||
ProjectService,
|
||||
TaskPhaseRepository,
|
||||
TaskPhaseService,
|
||||
TaskRepository,
|
||||
TaskService,
|
||||
CheckListItemRepository,
|
||||
CheckListItemService,
|
||||
],
|
||||
exports: [WorkspaceService, WorkspaceRepository, WorkspaceTypeService, WorkspaceTypeRepository],
|
||||
})
|
||||
export class TaskManagerModule {}
|
||||
|
||||
@@ -34,6 +34,7 @@ import { Reseller } from "../../reseller/entities/reseller.entity";
|
||||
import { UserBankAccount } from "../../reseller/entities/user-bank-account.entity";
|
||||
import { TMWorkspace } from "../../task-manager/entities/workspace.entity";
|
||||
import { TMTask } from "../../task-manager/entities/task.entity";
|
||||
import { TMProject } from "../../task-manager/entities/project.entity";
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseEntity {
|
||||
@@ -185,4 +186,7 @@ export class User extends BaseEntity {
|
||||
|
||||
@ManyToMany(() => TMTask, (task) => task.users)
|
||||
tasks: TMTask[];
|
||||
|
||||
@ManyToMany(() => TMProject, (project) => project.users)
|
||||
projects: TMProject[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user