152 lines
5.3 KiB
TypeScript
152 lines
5.3 KiB
TypeScript
import { BadRequestException, ForbiddenException, 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 { PaginationDto } from "../../../common/DTO/pagination.dto";
|
|
import { User } from "../../users/entities/user.entity";
|
|
import { ProjectMessage, WorkSpaceMessage } from "../../../common/enums/message.enum";
|
|
import { WorkspaceService } from "./workspace.service";
|
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
|
|
|
@Injectable()
|
|
export class ProjectService {
|
|
constructor(
|
|
private readonly projectRepository: ProjectRepository,
|
|
private readonly workspaceService: WorkspaceService,
|
|
@InjectRepository(User)
|
|
private readonly userRepository: Repository<User>,
|
|
) {}
|
|
|
|
async findOneOrFail(id: string): Promise<TMProject> {
|
|
const project = await this.projectRepository.findOne({ where: { id } });
|
|
if (!project) throw new NotFoundException(ProjectMessage.PROJECT_NOT_FOUND);
|
|
return project;
|
|
}
|
|
|
|
async create(dto: CreateProjectDto): Promise<TMProject> {
|
|
const { userIds, startDate, ...rest } = dto;
|
|
|
|
const workspace = await this.workspaceService.findOneOrFail(dto.workspaceId);
|
|
|
|
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(WorkSpaceMessage.USERS_DONT_BELONG_TO_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.findOneOrFail(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.workspaceService.findOneOrFail(workspaceId);
|
|
|
|
const workspaceUserIds = workspace.users.map((u) => u.id);
|
|
const invalidUsers = userIds.filter((uid) => !workspaceUserIds.includes(uid));
|
|
if (invalidUsers.length) {
|
|
throw new BadRequestException(WorkSpaceMessage.USERS_DONT_BELONG_TO_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.projectRepository.findOne({
|
|
where: {
|
|
id,
|
|
},
|
|
relations: {
|
|
taskPhases: true,
|
|
},
|
|
select: {
|
|
taskPhases: {
|
|
id: true,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!project) throw new NotFoundException(ProjectMessage.PROJECT_NOT_FOUND);
|
|
|
|
const taskPhases = project.taskPhases;
|
|
if (taskPhases !== undefined && taskPhases.length) {
|
|
throw new BadRequestException(ProjectMessage.PROJECT_CONTAINS_TASK_PHASES);
|
|
}
|
|
await this.projectRepository.delete(id);
|
|
return project;
|
|
}
|
|
|
|
async findUserProjectsByWorkspace(
|
|
userId: string,
|
|
permissions: PermissionEnum[],
|
|
wsId: string,
|
|
pagination: PaginationDto,
|
|
): Promise<{ projects: TMProject[]; count: number; paginate: true }> {
|
|
const workspace = await this.workspaceService.findOneOrFail(wsId);
|
|
|
|
const page = pagination.page ?? 1;
|
|
const limit = pagination.limit ?? 10;
|
|
const skip = (page - 1) * limit;
|
|
|
|
const isPermissionIncluded = permissions.includes(PermissionEnum.VIEW_ALL_PROJECTS);
|
|
const isUserMemeberOfWorkspace = workspace.users.some((user) => user.id === userId);
|
|
|
|
var res: [TMProject[], number];
|
|
if (isUserMemeberOfWorkspace) {
|
|
res = await this.projectRepository.findUserProjects(userId, wsId, skip, limit);
|
|
} else if (isPermissionIncluded) {
|
|
res = await this.projectRepository.findAndCount({ where: { workspaceId: wsId } });
|
|
} else {
|
|
throw new ForbiddenException(WorkSpaceMessage.FORBIDDEN);
|
|
}
|
|
|
|
const [projects, count] = res;
|
|
|
|
return { projects, count, paginate: true };
|
|
}
|
|
|
|
async getProjectDetail(projectId: string, userId: string, permissions: PermissionEnum[]): Promise<TMProject | null> {
|
|
const project = await this.projectRepository.findOne({
|
|
where: { id: projectId },
|
|
relations: {
|
|
users: true,
|
|
},
|
|
});
|
|
if (!project) throw new NotFoundException(ProjectMessage.PROJECT_NOT_FOUND);
|
|
|
|
const isUserMember = project.users.some((user) => user.id === userId);
|
|
if (!isUserMember && !permissions.includes(PermissionEnum.VIEW_ALL_PROJECTS))
|
|
throw new ForbiddenException(ProjectMessage.NOT_MEMBER_OF_PROJECT);
|
|
|
|
const projectDetail = await this.projectRepository.getProjectDetail(projectId);
|
|
|
|
return projectDetail;
|
|
}
|
|
}
|