Skip to content

Commit d408c65

Browse files
CLAP-299 사용자 작업 취소
* CLAP-110 Feature : 담당자별 작업 처리량 조회 API 구현 <footer> - 관련: #73 * CLAP-111 Refactor : 통계 조회 API 리팩토링 및 기능 수정 <footer> - 관련: #74 * 내 작업한 내용에 대한 설명 * 담당자 조회 API 구현 * CLAP-111 Refactor : 통계 조회 API 주소 통합, 리팩토링, 예외처리 <footer> - 관련: #74 * Bug : 프로퍼티파일 수정 * CLAP-104 CI/CD : CI에서 s3.yml 파일 생성하도록 수정 * CLAP-146 Feature : 카테고리 목록 조회 API 구현 <footer> - 관련: #118 * CLAP-147 Feature : 카테고리 수정 API 구현 <footer> - 관련: #119 * CLAP-147 Feature : 카테고리 추가, 수정 API 리뷰반영 수정 <footer> - 관련: #119 * CLAP-148 Feature : 카테고리 삭제 API 구현 <footer> - 관련: #120 * CLAP-148 Feature : 카테고리 삭제 API 수정 <footer> - 관련: #120 * CLAP-148 Docs : 카테고리 API 스웨거 수정 <footer> - 관련: #120 * CLAP-107 Bug : CI test yml파일 key 중복 수정 <footer> - 관련: #60 * CLAP-148 Feature : 카테고리 CUD 리뷰 반영 수정, 조회 반환 양식 수정 <footer> - 관련: #120 * CLAP-214 Cleanup : 통계, 카테고리 미흡한부분 리팩토링 <footer> - 관련: #216 * CLAP-214 Fix : 통계조회 API 파라미터 바인딩 오류 수정 <footer> - 관련: #216 * CLAP-214 Fix : addConverter 수정 <footer> - 관련: #216 * CLAP-214 Hotfix : 추가한 파일들 제거 <footer> - 관련: #216 * CLAP-214 Hotfix : FindStatisticsController 스위치문 수정 <footer> - 관련: #216 * CLAP-214 Hotfix : AddCategoryService 지연로딩 오류 수정 <footer> - 관련: #216 * CLAP-214 Hotfix : DeleteCategoryService 카테고리 삭제 로직 수정 <footer> - 관련: #216 * CLAP-249 Refactor : 통계 조회 서비스 리팩토링 <footer> - 관련: #265 * CLAP-250 Test : 통계 조회 테스트코드 작성 <footer> - 관련: #266 * CLAP-214 Hotifx : 카테고리 수정 로직 수정 <footer> - 관련: #216 * CLAP-214 Hotifx : 카테고리 수정 로직 수정 <footer> - 관련: #216 * CLAP-256 fix: 스웨거 명세 추가 * CLAP-214 Hotifx : 카테고리 저장 트랜잭션 추가 <footer> - 관련: #216 * CLAP-214 Hotifx : 카테고리 저장 시간 수정 <footer> - 관련: #216 * CLAP-285 Hotifx : 모든 카테고리 조회 <footer> - 관련: #331 * CLAP-214 Hotifx : 카테고리 조회 Secured 설정 <footer> - 관련: #216 * CLAP-256 fix: convert 동작 mapper 추가 * CLAP-256 fix: 충돌해결 * CLAP-256 fix: 불필요한 테스트 파일 제거 * CLAP-256 fix: mapper statuslabel 수정 * CLAP-256 Fix : 팀 작업 현황 필터링 조회 수정 <footer> - 관련: #281 * CLAP-299 Feature : 사용자 작업 취소 <footer> - 관련: #352
1 parent d442aae commit d408c65

File tree

13 files changed

+148
-14
lines changed

13 files changed

+148
-14
lines changed

src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTeamStatusRequest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package clap.server.adapter.inbound.web.dto.task.request;
22

33
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.NotNull;
45

56
import java.util.List;
67

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package clap.server.adapter.inbound.web.task;
2+
3+
import clap.server.application.port.inbound.task.CancelTaskUsecase;
4+
import clap.server.common.annotation.architecture.WebAdapter;
5+
import io.swagger.v3.oas.annotations.Operation;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.security.access.annotation.Secured;
9+
import org.springframework.web.bind.annotation.PatchMapping;
10+
import org.springframework.web.bind.annotation.PathVariable;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
13+
@Tag(name = "02. Task [거부 & 종료]")
14+
@RequestMapping("/api/tasks")
15+
@RequiredArgsConstructor
16+
@WebAdapter
17+
public class CancelTaskController {
18+
private final CancelTaskUsecase cancelTaskUsecase;
19+
20+
@Operation(summary = "작업 취소")
21+
@Secured("ROLE_USER")
22+
@PatchMapping("/{taskId}/cancle")
23+
public void cancelTask(@PathVariable Long taskId) {
24+
cancelTaskUsecase.cancleTask(taskId);
25+
}
26+
}

src/main/java/clap/server/adapter/inbound/web/task/ManagerController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@
33
import clap.server.application.port.inbound.task.FindManagersUsecase;
44
import clap.server.adapter.inbound.web.dto.task.response.FindManagersResponse;
55
import clap.server.common.annotation.architecture.WebAdapter;
6+
import io.swagger.v3.oas.annotations.Operation;
7+
8+
import io.swagger.v3.oas.annotations.tags.Tag;
69
import lombok.RequiredArgsConstructor;
710
import org.springframework.http.ResponseEntity;
811
import org.springframework.web.bind.annotation.GetMapping;
912
import org.springframework.web.bind.annotation.RequestMapping;
1013

1114
import java.util.List;
15+
16+
@Tag(name = "02. Task [조회]")
1217
@WebAdapter
1318
@RequestMapping("/api/managers")
1419
@RequiredArgsConstructor
1520
public class ManagerController {
1621
private final FindManagersUsecase findManagersUsecase;
1722

23+
@Operation(summary = "담당자 조회 API")
1824
@GetMapping
1925
public ResponseEntity<List<FindManagersResponse>> findManagers() {
2026
return ResponseEntity.ok(findManagersUsecase.findManagers());

src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,24 @@
99
import io.swagger.v3.oas.annotations.tags.Tag;
1010
import lombok.RequiredArgsConstructor;
1111
import org.springframework.http.ResponseEntity;
12+
import org.springframework.validation.annotation.Validated;
1213
import org.springframework.web.bind.annotation.*;
1314

1415
import java.util.List;
1516

16-
1717
@Tag(name = "02. Task [담당자]")
18-
@WebAdapter
1918
@RestController
20-
@RequiredArgsConstructor
2119
@RequestMapping("/api/team-status")
22-
public class TeamStatusController {
23-
20+
@RequiredArgsConstructor
21+
@WebAdapter
22+
public class TeamStatusController {
23+
2424
private final TeamStatusService teamStatusService;
2525
@Operation(summary = "팀 현황 필터링 조회 API")
2626
@GetMapping("/filter")
2727
public ResponseEntity<TeamStatusResponse> filterTeamStatus(@ModelAttribute FilterTeamStatusRequest filter) {
2828
TeamStatusResponse response = teamStatusService.filterTeamStatus(filter);
2929
return ResponseEntity.ok(response != null ? response : new TeamStatusResponse(List.of(), 0, 0, 0));
3030
}
31-
}
31+
32+
}

src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package clap.server.adapter.outbound.persistense;
22

3-
import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest;
43
import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest;
4+
import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest;
55
import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest;
66
import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse;
77
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
@@ -23,7 +23,6 @@
2323
import org.springframework.data.domain.Pageable;
2424
import org.springframework.data.domain.Slice;
2525
import org.springframework.data.domain.SliceImpl;
26-
import org.springframework.http.ResponseEntity;
2726

2827
import java.time.LocalDateTime;
2928
import java.util.List;

src/main/java/clap/server/adapter/outbound/persistense/entity/task/constant/TaskStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
public enum TaskStatus {
99
REQUESTED("요청"),
1010
IN_PROGRESS("진행 중"),
11-
IN_REVIEWING("완료 대기"),
11+
IN_REVIEWING("검토중"),
1212
COMPLETED("완료"),
1313
TERMINATED("종료");
1414

src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.time.LocalDateTime;
2222
import java.util.List;
2323
import java.util.stream.Collectors;
24+
import java.util.Optional;
2425

2526
import static clap.server.adapter.outbound.persistense.entity.task.QTaskEntity.taskEntity;
2627
import static com.querydsl.core.types.Order.ASC;
@@ -102,6 +103,11 @@ public List<TeamTaskResponse> findTeamStatus(Long memberId, FilterTeamStatusRequ
102103
.orderBy(orderBy)
103104
.fetch();
104105

106+
// null 또는 빈 리스트 처리
107+
if (taskEntities == null || taskEntities.isEmpty()) {
108+
return List.of(); // 빈 리스트 반환
109+
}
110+
105111
return taskEntities.stream()
106112
.collect(Collectors.groupingBy(t -> t.getProcessor().getMemberId()))
107113
.entrySet().stream()

src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
77
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
88
import io.lettuce.core.dynamic.annotation.Param;
9-
import org.springframework.data.domain.Pageable;
109
import org.springframework.data.jpa.repository.JpaRepository;
1110
import org.springframework.data.jpa.repository.Query;
12-
1311
import org.springframework.stereotype.Repository;
1412

1513
import java.time.LocalDateTime;
1614
import java.util.Collection;
17-
1815
import java.util.List;
1916
import java.util.Optional;
2017

@@ -52,7 +49,7 @@ List<TaskEntity> findTasksWithTaskStatusAndCompletedAt(
5249
Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAfterOrderByProcessorOrderAsc(
5350
Long processorId, TaskStatus taskStatus, Long processorOrder);
5451

55-
@Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ")
52+
// @Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ")
5653
List<TeamTaskResponse> findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter);
5754

5855
Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndTaskIdLessThanOrderByTaskIdDesc(Long processorId, TaskStatus taskStatus, Long taskId);

src/main/java/clap/server/application/mapper/TaskResponseMapper.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33

44
import clap.server.adapter.inbound.web.dto.task.response.*;
5+
import clap.server.adapter.outbound.persistense.entity.task.LabelEntity;
6+
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
57
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
68
import clap.server.domain.model.member.Member;
79
import clap.server.domain.model.task.Attachment;
@@ -193,4 +195,61 @@ public static FindManagersResponse toFindManagersResponse(Member manager, int re
193195
remainingTasks
194196
);
195197
}
198+
199+
public static TeamStatusResponse toTeamStatusResponse(List<TaskEntity> taskEntities) {
200+
// 담당자별로 그룹화
201+
Map<Long, List<TaskEntity>> tasksByProcessor = taskEntities.stream()
202+
.collect(Collectors.groupingBy(taskEntity -> taskEntity.getProcessor().getMemberId()));
203+
204+
List<TeamTaskResponse> memberResponses = tasksByProcessor.entrySet().stream()
205+
.map(entry -> {
206+
List<TeamTaskItemResponse> teamtaskItemResponses = entry.getValue().stream()
207+
.map(TaskResponseMapper::toTeamTaskItemResponse)
208+
.collect(Collectors.toList());
209+
210+
return new TeamTaskResponse(
211+
entry.getKey(),
212+
entry.getValue().get(0).getProcessor().getNickname(),
213+
entry.getValue().get(0).getProcessor().getImageUrl(),
214+
entry.getValue().get(0).getProcessor().getDepartment().getName(),
215+
(int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.IN_PROGRESS).count(),
216+
(int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.IN_REVIEWING).count(),
217+
entry.getValue().size(),
218+
teamtaskItemResponses
219+
);
220+
})
221+
.collect(Collectors.toList());
222+
223+
return new TeamStatusResponse(memberResponses);
224+
}
225+
226+
public static TeamTaskItemResponse toTeamTaskItemResponse(TaskEntity taskEntity) {
227+
return new TeamTaskItemResponse(
228+
taskEntity.getTaskId(),
229+
taskEntity.getTaskCode(),
230+
taskEntity.getTitle(),
231+
taskEntity.getCategory().getMainCategory().getName(),
232+
taskEntity.getCategory().getName(),
233+
taskEntity.getLabel() != null ? toLabelInfo(taskEntity.getLabel()) : null,
234+
taskEntity.getRequester().getNickname(),
235+
taskEntity.getRequester().getImageUrl(),
236+
taskEntity.getRequester().getDepartment().getName(),
237+
taskEntity.getProcessorOrder(),
238+
taskEntity.getTaskStatus(),
239+
taskEntity.getCreatedAt()
240+
);
241+
}
242+
243+
public static TeamTaskItemResponse.LabelInfo toLabelInfo(LabelEntity label) { // Label → LabelEntity로 변경
244+
return new TeamTaskItemResponse.LabelInfo(
245+
label.getLabelName(),
246+
label.getLabelColor()
247+
);
248+
}
249+
250+
251+
252+
253+
254+
196255
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package clap.server.application.port.inbound.task;
2+
3+
public interface CancelTaskUsecase {
4+
void cancleTask(Long taskId);
5+
}

0 commit comments

Comments
 (0)