Skip to content

Commit

Permalink
feat: 프로젝트 별 태스크 목록 조회 API 구현
Browse files Browse the repository at this point in the history
* feat: 프로젝트 내 Task 목록 조회 API 구현

* refactor: Task 생성 로직 Project 도메인으로 이동

* refactor: long polling 구현을 위해 Task 생성 로직 Task 디렉토리로 이동

* refactor: 프로젝트 내 태스크 목록 조회 API 응답 포멧 변경

* fix: 병합 시 생긴 오류 해결

* fix: 구체적인 예외 처리 방식 적용
  • Loading branch information
yangchef1 authored Nov 13, 2024
1 parent bf741a5 commit a7a8678
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 6 deletions.
5 changes: 5 additions & 0 deletions apps/server/src/project/controller/project.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export class ProjectController {
return this.projectService.getInvitations(user.id);
}

@Get(':id/tasks')
getTasks(@Param('id') projectId: number) {
return this.projectService.getTasks(projectId);
}

@Post()
create(@AuthUser() user: Account, @Body() body: CreateProjectRequest) {
return this.projectService.create(user.id, body.title);
Expand Down
33 changes: 32 additions & 1 deletion apps/server/src/project/service/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ import { UserProjectsResponse } from '../dto/user-projects-response.dto';
import { Account } from '@/account/entity/account.entity';
import { ProjectContributorsResponse } from '../dto/project-contributors-response-dto';
import { UserInvitationResponse } from '../dto/user-invitation-response.dto';
import { Task } from '@/task/domain/task.entity';
import { TaskResponse } from '@/task/dto/task-response.dto';

@Injectable()
export class ProjectService {
constructor(
private dataSource: DataSource,
@InjectRepository(Project) private projectRepository: Repository<Project>,
@InjectRepository(Contributor) private contributorRepository: Repository<Contributor>,
@InjectRepository(Account) private accountRepository: Repository<Account>
@InjectRepository(Account) private accountRepository: Repository<Account>,
@InjectRepository(Task) private taskRepository: Repository<Task>
) {}

async getUserProjects(userId: number) {
Expand Down Expand Up @@ -89,6 +92,34 @@ export class ProjectService {
);
}

async getTasks(projectId: number) {
const tasks = await this.taskRepository.find({
where: { section: { project: { id: projectId } } },
relations: ['section'],
select: ['id', 'title', 'description', 'position', 'section'],
});

const taskBySection = tasks.reduce((acc, task) => {
const sectionId = task.section.id;
const sectionName = task.section.name;
const sectionData = acc.find((data) => data.id === sectionId);

if (!sectionData) {
acc.push({
id: sectionId,
name: sectionName,
tasks: [],
});
}

sectionData.tasks.push(new TaskResponse(task));

return acc;
}, []);

return taskBySection;
}

async create(userId: number, title: string) {
const queryRunner = this.dataSource.createQueryRunner();

Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/task/controller/task.controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
import { TaskService } from '../service/task.service';
import { CreateTaskRequest } from '../dto/create-task-request.dto';
import { UpdateTaskRequest } from '../dto/update-task-request.dto';
import { MoveTaskRequest } from '../dto/move-task-request.dto';
import { CreateTaskRequest } from '@/task/dto/create-task-request.dto';

@Controller('task')
export class TaskController {
Expand Down
7 changes: 6 additions & 1 deletion apps/server/src/task/domain/section.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from 'typeorm';
import { Project } from '@/project/entity/project.entity';

@Entity()
export class Section {
Expand All @@ -7,4 +8,8 @@ export class Section {

@Column()
name: string;

@ManyToOne(() => Project)
@JoinColumn({ name: 'project_id' })
project: Project;
}
2 changes: 2 additions & 0 deletions apps/server/src/task/dto/create-task-request.dto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export class CreateTaskRequest {
projectId: number;

lastTaskPosition: string;
}
16 changes: 13 additions & 3 deletions apps/server/src/task/service/task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,42 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { LexoRank } from 'lexorank';
import { Task } from '../domain/task.entity';
import { CreateTaskRequest } from '../dto/create-task-request.dto';
import { CreateTaskResponse } from '../dto/create-task-response.dto';
import { Section } from '../domain/section.entity';
import { UpdateTaskRequest } from '../dto/update-task-request.dto';
import { UpdateTaskResponse } from '../dto/update-task-response.dto';
import { MoveTaskRequest } from '../dto/move-task-request.dto';
import { MoveTaskResponse } from '../dto/move-task-response.dto';
import { TaskResponse } from '../dto/task-response.dto';
import { DeleteTaskResponse } from '../dto/delete-task-response.dto';
import { CreateTaskResponse } from '@/task/dto/create-task-response.dto';
import { Project } from '@/project/entity/project.entity';
import { CreateTaskRequest } from '@/task/dto/create-task-request.dto';

@Injectable()
export class TaskService {
constructor(
@InjectRepository(Task)
private taskRepository: Repository<Task>,
@InjectRepository(Section)
private sectionRepository: Repository<Section>
private sectionRepository: Repository<Section>,
@InjectRepository(Project)
private projectRepository: Repository<Project>
) {}

async create(createTaskRequest: CreateTaskRequest) {
const project = await this.projectRepository.findOneBy({ id: createTaskRequest.projectId });
if (!project) {
throw new NotFoundException('Project not found');
}

const sections = await this.sectionRepository.find({ where: { project } });
const position: string = createTaskRequest.lastTaskPosition
? LexoRank.parse(createTaskRequest.lastTaskPosition).genNext().toString()
: LexoRank.min().toString();

const task = await this.taskRepository.save({
position,
section: sections[0],
});
return new CreateTaskResponse(task);
}
Expand Down

0 comments on commit a7a8678

Please sign in to comment.