Skip to content

Commit 4eac092

Browse files
committed
CLAP-108 Add: 요청 목록 조회 시 특정 속성에 따른 정렬 조건 추가
1 parent c2300aa commit 4eac092

File tree

19 files changed

+166
-126
lines changed

19 files changed

+166
-126
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package clap.server.adapter.inbound.web.dto.task;
2+
3+
4+
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
5+
import jakarta.validation.constraints.NotNull;
6+
import org.springframework.beans.factory.annotation.Value;
7+
8+
import java.util.List;
9+
10+
11+
public record FilterTaskListRequest(
12+
13+
Integer term,
14+
@NotNull
15+
List<Long> categoryIds,
16+
@NotNull
17+
List<Long> mainCategoryIds,
18+
@NotNull
19+
String title,
20+
@NotNull
21+
String nickName,
22+
@NotNull
23+
List<TaskStatus> taskStatus,
24+
@NotNull
25+
OrderRequest orderRequest
26+
) {
27+
}

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

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package clap.server.adapter.inbound.web.dto.task;
2+
3+
import jakarta.validation.constraints.NotNull;
4+
5+
public record OrderRequest(
6+
@NotNull
7+
String target,
8+
@NotNull
9+
String type
10+
) {}
Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,66 @@
11
package clap.server.adapter.inbound.web.task;
22

3+
import clap.server.adapter.inbound.security.SecurityUserDetails;
34
import clap.server.adapter.inbound.web.dto.task.FindTaskDetailsResponse;
4-
import clap.server.adapter.inbound.web.dto.task.FindTaskListRequest;
5+
import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest;
56
import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse;
67
import clap.server.application.port.inbound.task.FindTaskDetailsUsecase;
78
import clap.server.application.port.inbound.task.FindTaskListUsecase;
89
import clap.server.common.annotation.architecture.WebAdapter;
10+
import io.swagger.v3.oas.annotations.Operation;
11+
import io.swagger.v3.oas.annotations.tags.Tag;
912
import lombok.RequiredArgsConstructor;
1013

14+
import lombok.extern.slf4j.Slf4j;
1115
import org.springframework.data.domain.Page;
1216
import org.springframework.data.domain.PageRequest;
1317
import org.springframework.data.domain.Pageable;
1418
import org.springframework.http.ResponseEntity;
19+
import org.springframework.security.access.annotation.Secured;
20+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1521
import org.springframework.web.bind.annotation.*;
1622

1723
import java.util.List;
1824

25+
@Tag(name = "작업 조회")
1926
@WebAdapter
2027
@RestController
2128
@RequiredArgsConstructor
2229
@RequestMapping("/api/tasks")
30+
@Slf4j
2331
public class FindTaskController {
2432
private final FindTaskDetailsUsecase taskDetailsUsecase;
2533
private final FindTaskListUsecase taskListUsecase;
26-
private static final Long taskId = 3L;
27-
private static final Long memberId = 4L;
34+
35+
@Operation(summary = "내가 요청한 작업 목록 조회 (filtering, paging, sorting")
36+
@Secured({"ROLE_USER"})
2837
@GetMapping("/requests")
2938
public ResponseEntity<Page<FindTaskListResponse>> getRequestedTaskList(
3039
@RequestParam(defaultValue = "0") int page,
31-
@RequestParam(defaultValue = "20") int size,
32-
@RequestBody FindTaskListRequest findTaskListRequest){
33-
Pageable pageable = PageRequest.of(page, size);
34-
return ResponseEntity.ok(taskListUsecase.findRequestedTaskList(memberId, pageable, findTaskListRequest));
35-
}
40+
@RequestParam(defaultValue = "20") int pageSize,
41+
@ModelAttribute FilterTaskListRequest filterTaskListRequest,
42+
@AuthenticationPrincipal SecurityUserDetails userInfo){
43+
Pageable pageable = PageRequest.of(page, pageSize);
3644

37-
@GetMapping("/requests/details")
38-
public ResponseEntity<List<FindTaskDetailsResponse>> getRequestedTaskDetails(){
39-
return ResponseEntity.ok(taskDetailsUsecase.findRequestedTaskDetails(memberId, taskId));
45+
log.info("요청된 파라미터 - page: {}, pageSize: {}, userId: {}", page, pageSize, userInfo.getUserId());
46+
log.info("FilterTaskListRequest - term: {}, categoryIds: {}, mainCategoryIds: {}, title: {}, nickName: {}, taskStatus: {}, orderRequest: {}",
47+
filterTaskListRequest.term(),
48+
filterTaskListRequest.categoryIds(),
49+
filterTaskListRequest.mainCategoryIds(),
50+
filterTaskListRequest.title(),
51+
filterTaskListRequest.nickName(),
52+
filterTaskListRequest.taskStatus(),
53+
filterTaskListRequest.orderRequest());
54+
log.info("isEmpty={}", filterTaskListRequest.nickName().isEmpty());
55+
56+
return ResponseEntity.ok(taskListUsecase.findRequestedTaskList(userInfo.getUserId(), pageable, filterTaskListRequest));
57+
}
58+
@Operation(summary = "요청한 작업 상세 조회")
59+
@Secured({"ROLE_USER", "ROLE_MANAGER"})
60+
@GetMapping("/requests/details/{taskId}")
61+
public ResponseEntity<List<FindTaskDetailsResponse>> getRequestedTaskDetails(
62+
@PathVariable Long taskId,
63+
@AuthenticationPrincipal SecurityUserDetails userInfo){
64+
return ResponseEntity.ok(taskDetailsUsecase.findRequestedTaskDetails(userInfo.getUserId(), taskId));
4065
}
4166
}
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
package clap.server.adapter.inbound.web.task;
22

3+
import clap.server.adapter.inbound.security.SecurityUserDetails;
34
import clap.server.adapter.inbound.web.dto.task.CreateTaskRequest;
45
import clap.server.adapter.inbound.web.dto.task.CreateTaskResponse;
56
import clap.server.adapter.inbound.web.dto.task.UpdateTaskRequest;
67
import clap.server.adapter.inbound.web.dto.task.UpdateTaskResponse;
78
import clap.server.application.port.inbound.task.CreateTaskUsecase;
89
import clap.server.application.port.inbound.task.UpdateTaskUsecase;
910
import clap.server.common.annotation.architecture.WebAdapter;
11+
import io.swagger.v3.oas.annotations.Operation;
12+
import io.swagger.v3.oas.annotations.tags.Tag;
1013
import jakarta.validation.Valid;
1114
import lombok.RequiredArgsConstructor;
1215
import org.springframework.http.ResponseEntity;
16+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1317
import org.springframework.web.bind.annotation.*;
1418

1519

20+
@Tag(name = "작업 생성 및 수정")
1621
@WebAdapter
1722
@RestController
1823
@RequiredArgsConstructor
@@ -21,17 +26,20 @@ public class ManagementTaskController {
2126

2227
private final CreateTaskUsecase createTaskUsecase;
2328
private final UpdateTaskUsecase updateTaskUsecase;
24-
private static final Long memberId = 4L;
2529

30+
@Operation(summary = "작업 요청 생성")
2631
@PostMapping
2732
public ResponseEntity<CreateTaskResponse> createTask(
28-
@RequestBody @Valid CreateTaskRequest createTaskRequest){
29-
return ResponseEntity.ok(createTaskUsecase.createTask(memberId, createTaskRequest));
33+
@RequestBody @Valid CreateTaskRequest createTaskRequest,
34+
@AuthenticationPrincipal SecurityUserDetails userInfo){
35+
return ResponseEntity.ok(createTaskUsecase.createTask(userInfo.getUserId(), createTaskRequest));
3036
}
3137

38+
@Operation(summary = "요청한 작업 수정")
3239
@PatchMapping
3340
public ResponseEntity<UpdateTaskResponse> updateTask(
34-
@RequestBody @Valid UpdateTaskRequest updateTaskRequest){
35-
return ResponseEntity.ok(updateTaskUsecase.updateTask(memberId, updateTaskRequest));
41+
@RequestBody @Valid UpdateTaskRequest updateTaskRequest,
42+
@AuthenticationPrincipal SecurityUserDetails userInfo){
43+
return ResponseEntity.ok(updateTaskUsecase.updateTask(userInfo.getUserId(), updateTaskRequest));
3644
}
3745
}

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

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

3-
import clap.server.adapter.inbound.web.dto.task.FindTaskListRequest;
3+
import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest;
44
import clap.server.adapter.inbound.web.dto.task.FindTaskListResponse;
55
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
66
import clap.server.adapter.outbound.persistense.mapper.TaskPersistenceMapper;
@@ -38,7 +38,7 @@ public Optional<Task> findById(Long id) {
3838
}
3939

4040
@Override
41-
public Page<FindTaskListResponse> findAllByRequesterId(Long requesterId, Pageable pageable, FindTaskListRequest findTaskListRequest) {
41+
public Page<FindTaskListResponse> findAllByRequesterId(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest) {
4242
Page<Task> taskList = taskRepository.findRequestedTaskList(requesterId, pageable, findTaskListRequest)
4343
.map(taskPersistenceMapper::toDomain);
4444
return taskList.map(TaskMapper::toFindTaskListResponse);

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
@@ -10,7 +10,7 @@
1010
public enum TaskStatus {
1111
REQUESTED("요청"),
1212
IN_PROGRESS("진행 중"),
13-
PENDING_COMPLETED("검토중"),
13+
PENDING_COMPLETED("검토 중"),
1414
COMPLETED("완료"),
1515
TERMINATED("종료");
1616

src/main/java/clap/server/adapter/outbound/persistense/mapper/TaskPersistenceMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import clap.server.adapter.outbound.persistense.mapper.common.PersistenceMapper;
55
import clap.server.domain.model.task.Task;
66
import org.mapstruct.Mapper;
7+
import org.mapstruct.Mapping;
78

89
@Mapper(componentModel = "spring", uses = {MemberPersistenceMapper.class, LabelPersistenceMapper.class, CategoryPersistenceMapper.class})
910
public interface TaskPersistenceMapper extends PersistenceMapper<TaskEntity, Task> {
10-
1111
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package clap.server.adapter.outbound.persistense.repository.task;
22

3-
import clap.server.adapter.inbound.web.dto.task.FindTaskListRequest;
3+
import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest;
44
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
55
import org.springframework.data.domain.Page;
66
import org.springframework.data.domain.Pageable;
77

88
public interface TaskCustomRepository {
99

10-
Page<TaskEntity> findRequestedTaskList(Long requesterId, Pageable pageable, FindTaskListRequest findTaskListRequest);
10+
Page<TaskEntity> findRequestedTaskList(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest);
1111
}
Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package clap.server.adapter.outbound.persistense.repository.task;
22

3-
import clap.server.adapter.inbound.web.dto.task.FindTaskListRequest;
4-
import clap.server.adapter.outbound.persistense.entity.task.QTaskEntity;
3+
import clap.server.adapter.inbound.web.dto.task.FilterTaskListRequest;
54
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
65
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
7-
import clap.server.domain.model.task.Term;
86
import com.querydsl.core.BooleanBuilder;
7+
import com.querydsl.core.types.OrderSpecifier;
8+
import com.querydsl.core.types.dsl.DateTimePath;
99
import com.querydsl.jpa.impl.JPAQueryFactory;
1010
import lombok.RequiredArgsConstructor;
1111
import org.springframework.data.domain.Page;
@@ -16,57 +16,73 @@
1616
import java.time.LocalDateTime;
1717
import java.util.List;
1818

19+
import static clap.server.adapter.outbound.persistense.entity.task.QTaskEntity.taskEntity;
20+
import static com.querydsl.core.types.Order.*;
21+
1922
@Repository
2023
@RequiredArgsConstructor
2124
public class TaskCustomRepositoryImpl implements TaskCustomRepository {
2225

2326
private final JPAQueryFactory queryFactory;
2427

2528
@Override
26-
public Page<TaskEntity> findRequestedTaskList(Long requesterId, Pageable pageable, FindTaskListRequest findTaskListRequest) {
27-
QTaskEntity task = QTaskEntity.taskEntity;
29+
public Page<TaskEntity> findRequestedTaskList(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest) {
2830
BooleanBuilder whereClause = new BooleanBuilder();
29-
whereClause.and(task.requester.memberId.eq(requesterId));
31+
whereClause.and(taskEntity.requester.memberId.eq(requesterId));
3032

3133
List<Long> categoryIds = findTaskListRequest.categoryIds();
3234
List<Long> mainCategoryIds = findTaskListRequest.mainCategoryIds();
3335
String title = findTaskListRequest.title();
3436
String nickName = findTaskListRequest.nickName();
35-
TaskStatus taskStatus = findTaskListRequest.taskStatus();
36-
Term term = findTaskListRequest.term();
37+
List<TaskStatus> taskStatuses = findTaskListRequest.taskStatus();
38+
Integer termHours = findTaskListRequest.term();
39+
String sortTarget = findTaskListRequest.orderRequest().target();
40+
String sortType = findTaskListRequest.orderRequest().type();
3741

38-
if (term != null) {
39-
LocalDateTime fromDate = LocalDateTime.now().minusMonths(term.getHours());
40-
whereClause.and(task.createdAt.after(fromDate));
42+
if (termHours != null) {
43+
LocalDateTime fromDate = LocalDateTime.now().minusHours(termHours);
44+
whereClause.and(taskEntity.createdAt.after(fromDate));
4145
}
42-
if (categoryIds != null && !categoryIds.isEmpty()) {
43-
whereClause.and(task.category.categoryId.in(categoryIds)); // 리스트를 처리하는 in 조건
46+
if (!categoryIds.isEmpty()) {
47+
whereClause.and(taskEntity.category.categoryId.in(categoryIds));
4448
}
45-
if (mainCategoryIds != null && !mainCategoryIds.isEmpty()) {
46-
whereClause.and(task.category.mainCategory.categoryId.in(mainCategoryIds)); // 리스트를 처리하는 in 조건
49+
if (!mainCategoryIds.isEmpty()) {
50+
whereClause.and(taskEntity.category.mainCategory.categoryId.in(mainCategoryIds));
4751
}
48-
if (title != null && !title.isEmpty()) {
49-
whereClause.and(task.title.containsIgnoreCase(title));
52+
if (!title.isEmpty()) {
53+
whereClause.and(taskEntity.title.containsIgnoreCase(title));
5054
}
51-
if (nickName != null) {
52-
whereClause.and(task.processor.nickname.eq(nickName));
55+
if (!nickName.isEmpty()) {
56+
whereClause.and(taskEntity.processor.nickname.eq(nickName));
5357
}
54-
if (taskStatus != null) {
55-
whereClause.and(task.taskStatus.eq(taskStatus));
58+
if (!taskStatuses.isEmpty()) {
59+
whereClause.and(taskEntity.taskStatus.in(taskStatuses));
5660
}
5761

62+
OrderSpecifier<?> orderSpecifier = getOrderSpecifier(sortTarget, sortType);
63+
5864
List<TaskEntity> result = queryFactory
59-
.selectFrom(task)
65+
.selectFrom(taskEntity)
6066
.where(whereClause)
67+
.orderBy(orderSpecifier)
6168
.offset(pageable.getOffset())
6269
.limit(pageable.getPageSize())
6370
.fetch();
64-
6571
int total = queryFactory
66-
.selectFrom(task)
72+
.selectFrom(taskEntity)
6773
.where(whereClause)
6874
.fetch().size();
69-
7075
return new PageImpl<>(result, pageable, total);
7176
}
77+
78+
private OrderSpecifier<?> getOrderSpecifier(String sortTarget, String sortType) {
79+
DateTimePath<LocalDateTime> sortColumn = switch (sortTarget) {
80+
case "REQUESTED_AT" -> taskEntity.updatedAt;
81+
case "FINISHED_AT" -> taskEntity.completedAt;
82+
default -> taskEntity.updatedAt;
83+
};
84+
return "ASC".equalsIgnoreCase(sortType)
85+
? new OrderSpecifier<>(ASC, sortColumn)
86+
: new OrderSpecifier<>(DESC, sortColumn);
87+
}
7288
}

0 commit comments

Comments
 (0)