diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index e992f6f..8bf57e4 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -933,5 +933,11 @@ export const enum ProjectMessage { } export const enum TaskPhaseMessage { - TASK_PHASE_NOT_FOUND = "فاز تسک مورد نظر پیدا نشد!" + TASK_PHASE_NOT_FOUND = "فاز تسک مورد نظر پیدا نشد!", + TASK_PHASE_NOT_SAME_PROJECT = "فاز تسک جدید با فاز تسک قبلی در یک پروژه نیستند!" +} + +export const enum TaskMessage { + TASK_NOT_FOUND = "تسک مورد نظر پیدا نشد!", + USERS_ASSIGNED_TO_TASK_NOT_PROJECT_MEMBER = "حداقل یکی از کاربران تعیین شده عضو پروژه نیستند!" } \ No newline at end of file diff --git a/src/modules/task-manager/controllers/task-phase.controller.ts b/src/modules/task-manager/controllers/task-phase.controller.ts index 32f83c9..5e3fd3d 100644 --- a/src/modules/task-manager/controllers/task-phase.controller.ts +++ b/src/modules/task-manager/controllers/task-phase.controller.ts @@ -32,7 +32,7 @@ export class TaskPhaseController { @ApiResponse({ status: 200, description: "TaskPhase found", type: TMTaskPhase }) @ApiResponse({ status: 404, description: "TaskPhase not found" }) findOne(@Param("id") id: string): Promise { - return this.taskPhaseService.findOne(id); + return this.taskPhaseService.findOneOrFail(id); } @Post() diff --git a/src/modules/task-manager/controllers/task.controller.ts b/src/modules/task-manager/controllers/task.controller.ts index 9e356b3..c0fa93d 100644 --- a/src/modules/task-manager/controllers/task.controller.ts +++ b/src/modules/task-manager/controllers/task.controller.ts @@ -26,7 +26,7 @@ export class TaskController { @ApiResponse({ status: 200, description: 'Task found', type: TMTask }) @ApiResponse({ status: 404, description: 'Task not found' }) findOne(@Param('id') id: string): Promise { - return this.taskService.findOne(id); + return this.taskService.findOneOrFail(id); } @Post() diff --git a/src/modules/task-manager/providers/task-phase.service.ts b/src/modules/task-manager/providers/task-phase.service.ts index 00bcf63..11233ee 100644 --- a/src/modules/task-manager/providers/task-phase.service.ts +++ b/src/modules/task-manager/providers/task-phase.service.ts @@ -23,7 +23,7 @@ export class TaskPhaseService { }); } - async findOne(id: string): Promise { + async findOneOrFail(id: string): Promise { const taskPhase = await this.taskPhaseRepository.findOne({where: {id}}); if (!taskPhase) throw new NotFoundException(TaskPhaseMessage.TASK_PHASE_NOT_FOUND); return taskPhase; @@ -36,7 +36,7 @@ export class TaskPhaseService { } async update(id: string, dto: UpdateTaskPhaseDto): Promise { - const taskPhase = await this.findOne(id); + const taskPhase = await this.findOneOrFail(id); if (dto.projectId) { await this.projectService.findOneOrFail(dto.projectId); @@ -47,7 +47,7 @@ export class TaskPhaseService { } async remove(id: string): Promise { - await this.findOne(id); + await this.findOneOrFail(id); await this.taskPhaseRepository.delete(id); } } diff --git a/src/modules/task-manager/providers/task.service.ts b/src/modules/task-manager/providers/task.service.ts index 9e635e3..2be9e15 100644 --- a/src/modules/task-manager/providers/task.service.ts +++ b/src/modules/task-manager/providers/task.service.ts @@ -1,13 +1,15 @@ -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'; +import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { In, Repository } from "typeorm"; +import { TaskRepository } from "../repositories/task.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"; +import { TaskMessage, TaskPhaseMessage } from "../../../common/enums/message.enum"; +import { TaskPhaseRepository } from "../repositories/task-phase.repository"; +import { TMTaskPhase } from "../entities/task-phase.entity"; @Injectable() export class TaskService { @@ -18,25 +20,50 @@ export class TaskService { private readonly userRepository: Repository, ) {} - findAll(): Promise { - return this.taskRepository.findAll(); + async findAll(): Promise { + return this.taskRepository.find({ + relations: ["taskPhase", "remarks", "attachments", "checkListItems", "users"], + }); } - findByPhase(taskPhaseId: string): Promise { - return this.taskRepository.findByPhase(taskPhaseId); + async findByPhase(taskPhaseId: string): Promise { + return this.taskRepository.find({ where: { taskPhaseId } }); } - async findOne(id: string): Promise { - const task = await this.taskRepository.findOneById(id); - if (!task) throw new NotFoundException(`Task #${id} not found`); + async findOneOrFail(id: string): Promise { + const task = await this.taskRepository.findOne({ + where: { id }, + relations: { + taskPhase: true, + }, + }); + if (!task) throw new NotFoundException(TaskMessage.TASK_NOT_FOUND); return task; } + async findTaskPhaseOrFail(taskPhaseId: string): Promise { + const taskPhase = await this.taskPhaseRepository.findOne({ + where: { id: taskPhaseId }, + relations: { + project: { + users: true, + }, + }, + }); + if (!taskPhase) throw new NotFoundException(TaskPhaseMessage.TASK_PHASE_NOT_FOUND); + + return taskPhase; + } + async create(dto: CreateTaskDto): Promise { 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 taskPhase = await this.findTaskPhaseOrFail(dto.taskPhaseId); + + if (userIds?.length) { + const isUsersValid = userIds.every((userId) => taskPhase.project.users.some((user) => user.id === userId)); + if (!isUsersValid) throw new BadRequestException(TaskMessage.USERS_ASSIGNED_TO_TASK_NOT_PROJECT_MEMBER); + } const task = this.taskRepository.create({ ...rest, @@ -52,12 +79,16 @@ export class TaskService { } async update(id: string, dto: UpdateTaskDto): Promise { - const task = await this.findOne(id); + const task = await this.findOneOrFail(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`); + const taskPhase = await this.findTaskPhaseOrFail(dto.taskPhaseId); + + if (userIds?.length) { + const isUsersValid = userIds.every((userId) => taskPhase.project.users.some((user) => user.id === userId)); + if (!isUsersValid) throw new BadRequestException(TaskMessage.USERS_ASSIGNED_TO_TASK_NOT_PROJECT_MEMBER); + } } Object.assign(task, { @@ -67,24 +98,19 @@ export class TaskService { }); if (userIds) { - task.users = userIds.length - ? await this.userRepository.findBy({ id: In(userIds) }) - : []; + task.users = userIds.length ? await this.userRepository.findBy({ id: In(userIds) }) : []; } return this.taskRepository.save(task); } async changePhase(id: string, dto: ChangeTaskPhaseDto): Promise { - const task = await this.findOne(id); + const task = await this.findOneOrFail(id); - const newPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId); - if (!newPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`); + const newPhase = await this.findTaskPhaseOrFail(dto.taskPhaseId); if (task.taskPhase.projectId !== newPhase.projectId) { - throw new BadRequestException( - `TaskPhase #${dto.taskPhaseId} does not belong to the same project as the current phase`, - ); + throw new BadRequestException(TaskPhaseMessage.TASK_PHASE_NOT_SAME_PROJECT); } task.taskPhaseId = dto.taskPhaseId; @@ -94,7 +120,7 @@ export class TaskService { } async remove(id: string): Promise { - await this.findOne(id); + await this.findOneOrFail(id); await this.taskRepository.delete(id); } -} \ No newline at end of file +} diff --git a/src/modules/task-manager/repositories/task.repository.ts b/src/modules/task-manager/repositories/task.repository.ts index f419845..5f07518 100644 --- a/src/modules/task-manager/repositories/task.repository.ts +++ b/src/modules/task-manager/repositories/task.repository.ts @@ -4,45 +4,10 @@ import { Repository } from "typeorm"; import { TMTask } from "../entities/task.entity"; @Injectable() -export class TaskRepository { +export class TaskRepository extends Repository { constructor( - @InjectRepository(TMTask) - private readonly repository: Repository, - ) {} - - 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) { - return this.repository.create(data); - } - - save(task: TMTask) { - return this.repository.save(task); - } - - update(id: string, data: Partial) { - return this.repository.update(id, data); - } - - delete(id: string) { - return this.repository.delete(id); + @InjectRepository(TMTask) taskRepository: Repository, + ) { + super(taskRepository.target, taskRepository.manager, taskRepository.queryRunner) } }