From f29dff614fc271fb94dfcb286fd2b45fba6f0893 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 14:26:24 +0900 Subject: [PATCH 01/11] =?UTF-8?q?Fix:=20=ED=8C=80=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=ED=98=84=ED=99=A9=20API=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/response/TeamTaskItemResponse.java | 28 +++ .../task/TeamStatusControllerTest.java | 216 ++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java create mode 100644 src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java new file mode 100644 index 00000000..1b52b0d4 --- /dev/null +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskItemResponse.java @@ -0,0 +1,28 @@ +package clap.server.adapter.inbound.web.dto.task.response; + +import clap.server.adapter.outbound.persistense.entity.task.constant.LabelColor; +import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; + +import java.time.LocalDateTime; + +public record TeamTaskItemResponse( + Long taskId, + String taskCode, + String title, + String mainCategoryName, + String categoryName, + LabelInfo labelInfo, + String requesterNickname, + String requesterImageUrl, + String requesterDepartment, + long processorOrder, + TaskStatus taskStatus, + LocalDateTime createdAt +) { + public static record LabelInfo( + String labelName, + LabelColor labelColor + ) { + } + +} \ No newline at end of file diff --git a/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java b/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java new file mode 100644 index 00000000..f2bae84d --- /dev/null +++ b/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java @@ -0,0 +1,216 @@ +package clap.server.application.service.task; + +import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; +import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse; +import clap.server.adapter.inbound.web.task.TeamStatusController; +import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; +import clap.server.application.service.task.TeamStatusService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.TestPropertySource; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; +import org.springframework.test.web.servlet.MockMvc; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.web.servlet.function.RequestPredicates.param; + +@SpringBootTest +@Testcontainers +@TestPropertySource(properties = "spring.flyway.enabled=false") +@AutoConfigureMockMvc +class TeamStatusControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private TeamStatusController teamStatusController; + + @MockBean + private TeamStatusService teamStatusService; + + @Container + public static ElasticsearchContainer ES_CONTAINER = new ElasticsearchContainer(DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.17.5")) + .withReuse(true); + + @DynamicPropertySource + static void elasticProperties(DynamicPropertyRegistry registry) { + registry.add("spring.elasticsearch.uris", ES_CONTAINER::getHttpHostAddress); + } + + @Test + void filterTeamStatus_validRequest_shouldReturnValidResponse() { + // 필터 객체 생성 + FilterTeamStatusRequest filter = new FilterTeamStatusRequest( + "기여도순", // 정렬 기준 + List.of(1L, 2L), // 1차 카테고리 ID 목록 + List.of(1L, 2L), // 2차 카테고리 ID 목록 + "타이틀1" // 작업 타이틀 + ); + + // 컨트롤러 메서드 호출 + ResponseEntity responseEntity = teamStatusController.filterTeamStatus(filter); + + // 응답 값 검증 + assertThat(responseEntity.getStatusCodeValue()).isEqualTo(200); + assertThat(responseEntity.getBody()).isNotNull(); + assertThat(responseEntity.getBody().members()).isNotEmpty(); + } + + @Test + void filterTeamStatus_invalidRequest_shouldReturnValidResponse() { + // 잘못된 필터 객체 생성 (빈 리스트 혹은 null 값) + FilterTeamStatusRequest filter = new FilterTeamStatusRequest( + "", // 잘못된 정렬 기준 + null, // 잘못된 1차 카테고리 ID 목록 + null, // 잘못된 2차 카테고리 ID 목록 + "" // 잘못된 작업 타이틀 + ); + + // 컨트롤러 메서드 호출 + ResponseEntity responseEntity = teamStatusController.filterTeamStatus(filter); + + // 200 OK를 확인 + assertThat(responseEntity.getStatusCodeValue()).isEqualTo(200); + } + + @Test + public void testFilterTeamStatus() throws Exception { + // mock 응답 설정 + TeamStatusResponse response = new TeamStatusResponse(List.of()); + + // mock 동작 설정 + when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))).thenReturn(response); + + // mockMvc 요청 수행 + mockMvc.perform(get("/api/team-status/filter") + .param("sortBy", "기여도순") // 정렬 기준 + .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 + .param("categoryIds", "3") // 2차 카테고리 ID 목록 + .param("taskTitle", "")) // 작업 타이틀 + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").exists()); + } + @Test + public void testFilterTeamStatus_validRequest_shouldReturnFilteredResults() throws Exception { + // mock 응답 설정: 예상되는 데이터 + List mockResponseData = List.of( + new TeamMemberTaskResponse( + 1L, + "사용자1", + "imageUrl1", + "부서1", + 2, + 1, + 3, + List.of(new TaskItemResponse(1L, "code1", "타이틀1", "1", "2", "요청자1", "imageUrl", "부서", 1, TaskStatus.COMPLETED, LocalDateTime.now()))) + ); + + // mock 동작 설정: filterTeamStatus 메소드를 호출 + when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) + .thenReturn(new TeamStatusResponse(mockResponseData)); + + // mockMvc 요청 수행: 필터링된 결과 확인 + mockMvc.perform(get("/api/team-status/filter") + .param("sortBy", "기여도순") // 정렬 기준 + .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 + .param("categoryIds", "2") // 2차 카테고리 ID 목록 + .param("taskTitle", "타이틀1")) // 작업 타이틀 + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").exists()) // members가 존재하는지 확인 + .andExpect(jsonPath("$.members[0].tasks[0].title").value("타이틀1")) // 첫 번째 작업의 타이틀 확인 + .andExpect(jsonPath("$.members[0].tasks[0].taskStatus").value("IN_PROGRESS")) // 작업 상태 확인 + .andDo(print()); + } + + + @Test + public void testFilterTeamStatus_emptyResponse_shouldReturnEmpty() throws Exception { + // mock 응답 설정: 빈 리스트 반환 (조건에 맞는 작업이 없는 경우) + List mockResponseData = List.of(); + + /// mock 동작 설정: filterTeamStatus 메소드를 호출 + when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) + .thenReturn(new TeamStatusResponse(mockResponseData)); + + // mockMvc 요청 수행: 필터링된 결과가 없을 경우 + mockMvc.perform(get("/api/team-status/filter") + .param("sortBy", "기여도순") // 정렬 기준 + .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 + .param("categoryIds", "2") // 2차 카테고리 ID 목록 + .param("taskTitle", "타이틀1")) // 작업 타이틀 + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isEmpty()); // members가 비어 있는지 확인 + } + + @Test + public void testFilterTeamStatus_invalidRequest_shouldReturnBadRequest() throws Exception { + // 잘못된 요청: 필터 값이 비어있거나 잘못됨 + mockMvc.perform(get("/api/team-status/filter") + .param("sortBy", "") // 잘못된 정렬 기준 + .param("mainCategoryIds", "") // 잘못된 1차 카테고리 ID 목록 + .param("categoryIds", "") // 잘못된 2차 카테고리 ID 목록 + .param("taskTitle", "")) // 잘못된 작업 타이틀 + .andExpect(status().isBadRequest()); // 400 Bad Request 응답을 예상 + } + @Test + public void testFilterTeamStatus_completedTaskShouldNotBeReturned() throws Exception { + // mock 응답 설정: 'COMPLETED' 상태인 작업이 제외되어야 함 + List mockResponseData = List.of( + new TeamMemberTaskResponse( + 1L, + "사용자1", + "imageUrl1", + "부서1", + 2, + 1, + 3, + List.of( + new TaskItemResponse(1L, "code1", "타이틀1", "1", "2", "요청자1", "imageUrl", "부서", 1, TaskStatus.IN_PROGRESS, LocalDateTime.now()), + new TaskItemResponse(2L, "code2", "타이틀2", "1", "2", "요청자2", "imageUrl", "부서", 2, TaskStatus.COMPLETED, LocalDateTime.now()) + ) + ) + ); + + // mock 동작 설정: filterTeamStatus 메소드 호출 + when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) + .thenReturn(new TeamStatusResponse(mockResponseData)); + + // mockMvc 요청 수행: 필터링된 결과 확인 + mockMvc.perform(get("/api/team-status/filter") + .param("sortBy", "기여도순") // 정렬 기준 + .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 + .param("categoryIds", "2") // 2차 카테고리 ID 목록 + .param("taskTitle", "타이틀")) // 작업 타이틀 + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members[0].tasks").isArray()) // tasks가 배열 형태인지 확인 + .andExpect(jsonPath("$.members[0].tasks.length()").value(1)) // 완료된 작업은 제외되어야 하므로 tasks 배열 길이가 1이어야 함 + .andExpect(jsonPath("$.members[0].tasks[0].taskStatus").value("IN_PROGRESS")); // 첫 번째 작업의 상태는 IN_PROGRESS이어야 함 + } + + + + +} From f60755ff5837a91e8868c074a3380fe59a8aa5e8 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 14:32:16 +0900 Subject: [PATCH 02/11] =?UTF-8?q?CLPA-256=20Fix:=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=EC=A7=80=ED=86=A0=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/request/FilterTeamStatusRequest.java | 5 -- .../dto/task/response/TaskItemResponse.java | 1 + .../task/response/TeamMemberTaskResponse.java | 2 +- .../web/task/TeamStatusController.java | 5 +- .../task/TaskCustomRepositoryImpl.java | 51 ++++++++++++------- .../repository/task/TaskRepository.java | 3 +- .../inbound/task/LoadTeamStatusUsecase.java | 2 +- .../service/task/TeamStatusService.java | 4 +- src/test/resources/application.yml | 28 +++++++++- 9 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTeamStatusRequest.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTeamStatusRequest.java index 9fa71e91..ba517760 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTeamStatusRequest.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/request/FilterTeamStatusRequest.java @@ -24,9 +24,4 @@ public record FilterTeamStatusRequest( taskTitle = taskTitle == null ? "" : taskTitle; } - // 카테고리 유효성 검사 - public boolean isValid() { - // 1차 카테고리가 없으면 2차 카테고리는 선택할 수 없으므로 - return mainCategoryIds.isEmpty() || !categoryIds.isEmpty(); - } } diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java index a67406d6..a7ec6d4b 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TaskItemResponse.java @@ -1,6 +1,7 @@ package clap.server.adapter.inbound.web.dto.task.response; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; +import clap.server.domain.model.task.Label; import java.time.LocalDateTime; diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java index 157993a4..874ace60 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java @@ -12,7 +12,7 @@ public record TeamMemberTaskResponse( int inProgressTaskCount, int pendingTaskCount, int totalTaskCount, - List tasks + List tasks ) { @QueryProjection public TeamMemberTaskResponse { diff --git a/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java b/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java index 69a559bf..71477182 100644 --- a/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java +++ b/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java @@ -6,10 +6,9 @@ import clap.server.application.service.task.TeamStatusService; import clap.server.common.annotation.architecture.WebAdapter; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @RestController @@ -22,7 +21,7 @@ public class TeamStatusController { private final TeamStatusService teamStatusService; @GetMapping("/filter") - public ResponseEntity filterTeamStatus(@Valid@ModelAttribute FilterTeamStatusRequest filter) { + public ResponseEntity filterTeamStatus(@Validated @ModelAttribute FilterTeamStatusRequest filter) { TeamStatusResponse response = teamStatusService.filterTeamStatus(filter); return ResponseEntity.ok(response); } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java index b6fa1e00..f405dd6c 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java @@ -5,6 +5,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskItemResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import com.querydsl.core.BooleanBuilder; @@ -58,30 +59,37 @@ public Page findTasksAssignedByManager(Long processorId, Pageable pa @Override public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { + // filter가 null인 경우에도 기본적으로 모든 데이터를 조회하도록 처리 BooleanBuilder builder = new BooleanBuilder(); - // 담당자 ID 필터링 - if (memberId != null) { - builder.and(taskEntity.processor.memberId.eq(memberId)); - } + // 필터가 null인 경우, 기본적으로 모든 데이터 조회 + if (filter != null) { + // 진행 중 또는 완료 대기 상태 필터링 + builder.and(taskEntity.taskStatus.in(TaskStatus.IN_PROGRESS, TaskStatus.PENDING_COMPLETED)); - // 작업 타이틀 필터링 - if (filter.taskTitle() != null && !filter.taskTitle().isEmpty()) { - builder.and(taskEntity.title.containsIgnoreCase(filter.taskTitle())); - } + // 담당자 ID 필터링 + if (memberId != null) { + builder.and(taskEntity.processor.memberId.eq(memberId)); + } - // 1차 카테고리 필터링 - if (!filter.mainCategoryIds().isEmpty()) { - builder.and(taskEntity.category.mainCategory.categoryId.in(filter.mainCategoryIds())); - } + // 작업 타이틀 필터링 + if (filter.taskTitle() != null && !filter.taskTitle().isEmpty()) { + builder.and(taskEntity.title.containsIgnoreCase(filter.taskTitle())); + } - // 2차 카테고리 필터링 - if (!filter.categoryIds().isEmpty()) { - builder.and(taskEntity.category.categoryId.in(filter.categoryIds())); + // 1차 카테고리 필터링 (빈 배열인 경우, 필터링하지 않음) + if (filter.mainCategoryIds() != null && !filter.mainCategoryIds().isEmpty()) { + builder.and(taskEntity.category.mainCategory.categoryId.in(filter.mainCategoryIds())); + } + + // 2차 카테고리 필터링 (빈 배열인 경우, 필터링하지 않음) + if (filter.categoryIds() != null && !filter.categoryIds().isEmpty()) { + builder.and(taskEntity.category.categoryId.in(filter.categoryIds())); + } } // 정렬 조건 적용 - OrderSpecifier orderBy = "기여도순".equals(filter.sortBy()) + OrderSpecifier orderBy = "기여도순".equals(filter != null ? filter.sortBy() : "") ? new CaseBuilder() .when(taskEntity.taskStatus.eq(TaskStatus.IN_PROGRESS) .or(taskEntity.taskStatus.eq(TaskStatus.PENDING_COMPLETED))) @@ -101,13 +109,18 @@ public List findTeamStatus(Long memberId, FilterTeamStat .collect(Collectors.groupingBy(t -> t.getProcessor().getMemberId())) .entrySet().stream() .map(entry -> { - List taskResponses = entry.getValue().stream() - .map(taskEntity -> new TaskItemResponse( + List taskResponses = entry.getValue().stream() + .map(taskEntity -> new TeamTaskItemResponse( taskEntity.getTaskId(), taskEntity.getTaskCode(), taskEntity.getTitle(), taskEntity.getCategory().getMainCategory().getName(), taskEntity.getCategory().getName(), + taskEntity.getLabel() != null ? + new TeamTaskItemResponse.LabelInfo( + taskEntity.getLabel().getLabelName(), + taskEntity.getLabel().getLabelColor() + ) : null, taskEntity.getRequester().getNickname(), taskEntity.getRequester().getImageUrl(), taskEntity.getRequester().getDepartment().getName(), @@ -129,6 +142,8 @@ public List findTeamStatus(Long memberId, FilterTeamStat }).collect(Collectors.toList()); } + + private boolean isValidTitle(FilterTeamStatusRequest filter) { return filter.taskTitle() != null && !filter.taskTitle().isEmpty(); } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java index adf87e22..6ff86056 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java @@ -6,7 +6,6 @@ import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import io.lettuce.core.dynamic.annotation.Param; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; @@ -55,7 +54,7 @@ Optional findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAf Long processorId, TaskStatus taskStatus, Long processorOrder); @Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ") - Page findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter, Pageable pageable); + List findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter); diff --git a/src/main/java/clap/server/application/port/inbound/task/LoadTeamStatusUsecase.java b/src/main/java/clap/server/application/port/inbound/task/LoadTeamStatusUsecase.java index 68b204f4..e7e67f45 100644 --- a/src/main/java/clap/server/application/port/inbound/task/LoadTeamStatusUsecase.java +++ b/src/main/java/clap/server/application/port/inbound/task/LoadTeamStatusUsecase.java @@ -5,6 +5,6 @@ import org.springframework.data.domain.Pageable; public interface LoadTeamStatusUsecase { - TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter, Pageable pageable); + TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter); } diff --git a/src/main/java/clap/server/application/service/task/TeamStatusService.java b/src/main/java/clap/server/application/service/task/TeamStatusService.java index e24d09a6..a6a72ba8 100644 --- a/src/main/java/clap/server/application/service/task/TeamStatusService.java +++ b/src/main/java/clap/server/application/service/task/TeamStatusService.java @@ -21,8 +21,8 @@ public TeamStatusService(LoadTaskPort loadTaskPort) { } @Override - public TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter, Pageable pageable) { - List members = loadTaskPort.findTeamStatus(memberId, filter); // 페이징 처리 + public TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter) { + List members = loadTaskPort.findTeamStatus(memberId, filter); return new TeamStatusResponse(members); } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index a6acd661..e7959745 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -1,4 +1,6 @@ spring: + elasticsearch: + uris: http://127.0.0.1:9200 # H2 설정 정보 (H2 Console에 접속하기 위한 설정) h2: console: @@ -35,6 +37,8 @@ server: domain: local: 127.0.0.1:8080 service: 127.0.0.1:8080 + elasticsearch: + uri: 127.0.0.1:9200 web: domain: @@ -58,4 +62,26 @@ jwt: password: policy: length: 12 - characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+ \ No newline at end of file + characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+ + +cloud: + kakao: + project-id: 34481374c1ee4bbb8745df43e4c13fff + region: kr-central-2 + object-storage: + endpoint: https://objectstorage.kr-central-2.kakaocloud.com + access-key: 253474a41cb447f4ad3c38e0ed9963c4 + secret-key: 74861656e46845488ec4357f155fa3ed + bucketName: taskflow + +webhook: + kakaowork: + url: https://api.kakaowork.com/v1/messages.send_by_email + auth: Bearer 1b01becc.a7f10da76d2e4038948771107cfe5c1d + agit: + url: https://agit.io/webhook/a342181d-fb18-4eb0-a99a-30f4fb5b14b1 + +mail: + username: leegd120@gmail.com + password: znlictzarqurxlla + From b5b6ee672a2d6df36070e1049ab48587c5737e1e Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 15:46:39 +0900 Subject: [PATCH 03/11] =?UTF-8?q?CLAP-256=20fix:=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/resources/application.yml | 87 ------------------------------ 1 file changed, 87 deletions(-) delete mode 100644 src/test/resources/application.yml diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml deleted file mode 100644 index e7959745..00000000 --- a/src/test/resources/application.yml +++ /dev/null @@ -1,87 +0,0 @@ -spring: - elasticsearch: - uris: http://127.0.0.1:9200 - # H2 설정 정보 (H2 Console에 접속하기 위한 설정) - h2: - console: - enabled: false # H2 Console을 사용할지 여부 (H2 Console은 H2 Database를 UI로 제공해주는 기능) - path: /h2 # H2 Console의 Path - # Database 설정 정보 (H2 연동 정보) - datasource: - driver-class-name: org.h2.Driver # H2 Database 사용 - url: jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false # H2 접속 정보 - username: taskflow # H2 접속 시 입력할 username 정보 - password: # H2 접속 시 입력할 password 정보 - jpa: - hibernate: - ddl-auto: create - flyway: - enabled: false - - mail: - host: smtp.gmail.com - port: 587 - username: leegd120@gmail.com - password: znlictzarqurxlla - properties: - mail: - smtp: - auth: true - starttls: - enable: true - - testcontainers: - beans: - startup: parallel -server: - domain: - local: 127.0.0.1:8080 - service: 127.0.0.1:8080 - elasticsearch: - uri: 127.0.0.1:9200 - -web: - domain: - local: 127.0.0.1:3O00 - service: 127.0.0.1:3000 - -swagger: - server: - url: http://localhost:8080 - -jwt: - secret-key: - access-token: exampleSecretKeyForTFSystemAccessSecretKeyTestForPadding - temporary-token: exampleSecretKeyForTFSystemTemporarySecretKeyTestForPadding - refresh-token: exampleSecretKeyTFSystemRefreshSecretKeyTestForPadding - expiration-time: - access-token: 43200000 # 1000 * 60 * 60 * 12 = 43200000 (12 hours) - temporary-token: 300000 - refresh-token: 1209600000 # 1000 * 60 * 60 * 24 * 14 = 1209600000 (14 days) - -password: - policy: - length: 12 - characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+ - -cloud: - kakao: - project-id: 34481374c1ee4bbb8745df43e4c13fff - region: kr-central-2 - object-storage: - endpoint: https://objectstorage.kr-central-2.kakaocloud.com - access-key: 253474a41cb447f4ad3c38e0ed9963c4 - secret-key: 74861656e46845488ec4357f155fa3ed - bucketName: taskflow - -webhook: - kakaowork: - url: https://api.kakaowork.com/v1/messages.send_by_email - auth: Bearer 1b01becc.a7f10da76d2e4038948771107cfe5c1d - agit: - url: https://agit.io/webhook/a342181d-fb18-4eb0-a99a-30f4fb5b14b1 - -mail: - username: leegd120@gmail.com - password: znlictzarqurxlla - From e6f4195788c346ad5c05ee3f6c92c7367d0bd82f Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 15:49:30 +0900 Subject: [PATCH 04/11] =?UTF-8?q?CLAP-256=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0(=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=9B=84=20=EC=BB=A4=EB=B0=8B=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/TeamStatusControllerTest.java | 216 ------------------ 1 file changed, 216 deletions(-) delete mode 100644 src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java diff --git a/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java b/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java deleted file mode 100644 index f2bae84d..00000000 --- a/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package clap.server.application.service.task; - -import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; -import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse; -import clap.server.adapter.inbound.web.task.TeamStatusController; -import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; -import clap.server.application.service.task.TeamStatusService; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.TestPropertySource; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.DynamicPropertySource; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.testcontainers.elasticsearch.ElasticsearchContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; -import org.springframework.test.web.servlet.MockMvc; - -import java.time.LocalDateTime; -import java.util.List; - -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.web.servlet.function.RequestPredicates.param; - -@SpringBootTest -@Testcontainers -@TestPropertySource(properties = "spring.flyway.enabled=false") -@AutoConfigureMockMvc -class TeamStatusControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private TeamStatusController teamStatusController; - - @MockBean - private TeamStatusService teamStatusService; - - @Container - public static ElasticsearchContainer ES_CONTAINER = new ElasticsearchContainer(DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.17.5")) - .withReuse(true); - - @DynamicPropertySource - static void elasticProperties(DynamicPropertyRegistry registry) { - registry.add("spring.elasticsearch.uris", ES_CONTAINER::getHttpHostAddress); - } - - @Test - void filterTeamStatus_validRequest_shouldReturnValidResponse() { - // 필터 객체 생성 - FilterTeamStatusRequest filter = new FilterTeamStatusRequest( - "기여도순", // 정렬 기준 - List.of(1L, 2L), // 1차 카테고리 ID 목록 - List.of(1L, 2L), // 2차 카테고리 ID 목록 - "타이틀1" // 작업 타이틀 - ); - - // 컨트롤러 메서드 호출 - ResponseEntity responseEntity = teamStatusController.filterTeamStatus(filter); - - // 응답 값 검증 - assertThat(responseEntity.getStatusCodeValue()).isEqualTo(200); - assertThat(responseEntity.getBody()).isNotNull(); - assertThat(responseEntity.getBody().members()).isNotEmpty(); - } - - @Test - void filterTeamStatus_invalidRequest_shouldReturnValidResponse() { - // 잘못된 필터 객체 생성 (빈 리스트 혹은 null 값) - FilterTeamStatusRequest filter = new FilterTeamStatusRequest( - "", // 잘못된 정렬 기준 - null, // 잘못된 1차 카테고리 ID 목록 - null, // 잘못된 2차 카테고리 ID 목록 - "" // 잘못된 작업 타이틀 - ); - - // 컨트롤러 메서드 호출 - ResponseEntity responseEntity = teamStatusController.filterTeamStatus(filter); - - // 200 OK를 확인 - assertThat(responseEntity.getStatusCodeValue()).isEqualTo(200); - } - - @Test - public void testFilterTeamStatus() throws Exception { - // mock 응답 설정 - TeamStatusResponse response = new TeamStatusResponse(List.of()); - - // mock 동작 설정 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))).thenReturn(response); - - // mockMvc 요청 수행 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "3") // 2차 카테고리 ID 목록 - .param("taskTitle", "")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").exists()); - } - @Test - public void testFilterTeamStatus_validRequest_shouldReturnFilteredResults() throws Exception { - // mock 응답 설정: 예상되는 데이터 - List mockResponseData = List.of( - new TeamMemberTaskResponse( - 1L, - "사용자1", - "imageUrl1", - "부서1", - 2, - 1, - 3, - List.of(new TaskItemResponse(1L, "code1", "타이틀1", "1", "2", "요청자1", "imageUrl", "부서", 1, TaskStatus.COMPLETED, LocalDateTime.now()))) - ); - - // mock 동작 설정: filterTeamStatus 메소드를 호출 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) - .thenReturn(new TeamStatusResponse(mockResponseData)); - - // mockMvc 요청 수행: 필터링된 결과 확인 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "2") // 2차 카테고리 ID 목록 - .param("taskTitle", "타이틀1")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").exists()) // members가 존재하는지 확인 - .andExpect(jsonPath("$.members[0].tasks[0].title").value("타이틀1")) // 첫 번째 작업의 타이틀 확인 - .andExpect(jsonPath("$.members[0].tasks[0].taskStatus").value("IN_PROGRESS")) // 작업 상태 확인 - .andDo(print()); - } - - - @Test - public void testFilterTeamStatus_emptyResponse_shouldReturnEmpty() throws Exception { - // mock 응답 설정: 빈 리스트 반환 (조건에 맞는 작업이 없는 경우) - List mockResponseData = List.of(); - - /// mock 동작 설정: filterTeamStatus 메소드를 호출 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) - .thenReturn(new TeamStatusResponse(mockResponseData)); - - // mockMvc 요청 수행: 필터링된 결과가 없을 경우 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "2") // 2차 카테고리 ID 목록 - .param("taskTitle", "타이틀1")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isEmpty()); // members가 비어 있는지 확인 - } - - @Test - public void testFilterTeamStatus_invalidRequest_shouldReturnBadRequest() throws Exception { - // 잘못된 요청: 필터 값이 비어있거나 잘못됨 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "") // 잘못된 정렬 기준 - .param("mainCategoryIds", "") // 잘못된 1차 카테고리 ID 목록 - .param("categoryIds", "") // 잘못된 2차 카테고리 ID 목록 - .param("taskTitle", "")) // 잘못된 작업 타이틀 - .andExpect(status().isBadRequest()); // 400 Bad Request 응답을 예상 - } - @Test - public void testFilterTeamStatus_completedTaskShouldNotBeReturned() throws Exception { - // mock 응답 설정: 'COMPLETED' 상태인 작업이 제외되어야 함 - List mockResponseData = List.of( - new TeamMemberTaskResponse( - 1L, - "사용자1", - "imageUrl1", - "부서1", - 2, - 1, - 3, - List.of( - new TaskItemResponse(1L, "code1", "타이틀1", "1", "2", "요청자1", "imageUrl", "부서", 1, TaskStatus.IN_PROGRESS, LocalDateTime.now()), - new TaskItemResponse(2L, "code2", "타이틀2", "1", "2", "요청자2", "imageUrl", "부서", 2, TaskStatus.COMPLETED, LocalDateTime.now()) - ) - ) - ); - - // mock 동작 설정: filterTeamStatus 메소드 호출 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) - .thenReturn(new TeamStatusResponse(mockResponseData)); - - // mockMvc 요청 수행: 필터링된 결과 확인 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "2") // 2차 카테고리 ID 목록 - .param("taskTitle", "타이틀")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members[0].tasks").isArray()) // tasks가 배열 형태인지 확인 - .andExpect(jsonPath("$.members[0].tasks.length()").value(1)) // 완료된 작업은 제외되어야 하므로 tasks 배열 길이가 1이어야 함 - .andExpect(jsonPath("$.members[0].tasks[0].taskStatus").value("IN_PROGRESS")); // 첫 번째 작업의 상태는 IN_PROGRESS이어야 함 - } - - - - -} From 2866789bda772722d3a549b31035de0f658dae91 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 15:53:59 +0900 Subject: [PATCH 05/11] =?UTF-8?q?CLAP-256=20fix:=20=ED=86=B5=EA=B3=84=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0,=20=EB=9D=BC=EB=B2=A8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/response/TeamMemberTaskResponse.java | 1 + .../dto/task/response/TeamStatusResponse.java | 18 +- .../task/TaskCustomRepositoryImpl.java | 6 +- .../task/TeamStatusControllerTest.java | 216 ------------------ 4 files changed, 22 insertions(+), 219 deletions(-) delete mode 100644 src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java index 874ace60..5bdf1579 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java @@ -1,5 +1,6 @@ package clap.server.adapter.inbound.web.dto.task.response; +import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import com.querydsl.core.annotations.QueryProjection; import java.util.List; diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java index 61cd5dfc..e5c44252 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java @@ -3,9 +3,23 @@ import java.util.List; public record TeamStatusResponse( - List members + List members, + int totalInProgressTaskCount, + int totalPendingTaskCount, + int totalTaskCount ) { + // 기존 생성자 (3개 파라미터) + public TeamStatusResponse(List members, int totalInProgressTaskCount, int totalPendingTaskCount) { + this( + (members == null) ? List.of() : members, + totalInProgressTaskCount, + totalPendingTaskCount, + totalInProgressTaskCount + totalPendingTaskCount + ); + } + + // 추가된 생성자 (List만 받음) public TeamStatusResponse(List members) { - this.members = (members == null) ? List.of() : members; + this(members, 0, 0); // 기본값을 사용하여 생성 } } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java index f405dd6c..37059889 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java @@ -3,7 +3,6 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; import clap.server.adapter.inbound.web.dto.task.response.TeamTaskItemResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; @@ -129,6 +128,10 @@ public List findTeamStatus(Long memberId, FilterTeamStat taskEntity.getCreatedAt() )).collect(Collectors.toList()); + int inProgressTaskCount = (int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.IN_PROGRESS).count(); + int pendingTaskCount = (int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.PENDING_COMPLETED).count(); + int totalTaskCount = inProgressTaskCount + pendingTaskCount; + return new TeamMemberTaskResponse( entry.getKey(), entry.getValue().get(0).getProcessor().getNickname(), @@ -140,6 +143,7 @@ public List findTeamStatus(Long memberId, FilterTeamStat taskResponses ); }).collect(Collectors.toList()); + } diff --git a/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java b/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java deleted file mode 100644 index f2bae84d..00000000 --- a/src/test/java/clap/server/application/service/task/TeamStatusControllerTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package clap.server.application.service.task; - -import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TaskItemResponse; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; -import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse; -import clap.server.adapter.inbound.web.task.TeamStatusController; -import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; -import clap.server.application.service.task.TeamStatusService; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.TestPropertySource; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.DynamicPropertySource; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.testcontainers.elasticsearch.ElasticsearchContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; -import org.springframework.test.web.servlet.MockMvc; - -import java.time.LocalDateTime; -import java.util.List; - -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.web.servlet.function.RequestPredicates.param; - -@SpringBootTest -@Testcontainers -@TestPropertySource(properties = "spring.flyway.enabled=false") -@AutoConfigureMockMvc -class TeamStatusControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private TeamStatusController teamStatusController; - - @MockBean - private TeamStatusService teamStatusService; - - @Container - public static ElasticsearchContainer ES_CONTAINER = new ElasticsearchContainer(DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.17.5")) - .withReuse(true); - - @DynamicPropertySource - static void elasticProperties(DynamicPropertyRegistry registry) { - registry.add("spring.elasticsearch.uris", ES_CONTAINER::getHttpHostAddress); - } - - @Test - void filterTeamStatus_validRequest_shouldReturnValidResponse() { - // 필터 객체 생성 - FilterTeamStatusRequest filter = new FilterTeamStatusRequest( - "기여도순", // 정렬 기준 - List.of(1L, 2L), // 1차 카테고리 ID 목록 - List.of(1L, 2L), // 2차 카테고리 ID 목록 - "타이틀1" // 작업 타이틀 - ); - - // 컨트롤러 메서드 호출 - ResponseEntity responseEntity = teamStatusController.filterTeamStatus(filter); - - // 응답 값 검증 - assertThat(responseEntity.getStatusCodeValue()).isEqualTo(200); - assertThat(responseEntity.getBody()).isNotNull(); - assertThat(responseEntity.getBody().members()).isNotEmpty(); - } - - @Test - void filterTeamStatus_invalidRequest_shouldReturnValidResponse() { - // 잘못된 필터 객체 생성 (빈 리스트 혹은 null 값) - FilterTeamStatusRequest filter = new FilterTeamStatusRequest( - "", // 잘못된 정렬 기준 - null, // 잘못된 1차 카테고리 ID 목록 - null, // 잘못된 2차 카테고리 ID 목록 - "" // 잘못된 작업 타이틀 - ); - - // 컨트롤러 메서드 호출 - ResponseEntity responseEntity = teamStatusController.filterTeamStatus(filter); - - // 200 OK를 확인 - assertThat(responseEntity.getStatusCodeValue()).isEqualTo(200); - } - - @Test - public void testFilterTeamStatus() throws Exception { - // mock 응답 설정 - TeamStatusResponse response = new TeamStatusResponse(List.of()); - - // mock 동작 설정 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))).thenReturn(response); - - // mockMvc 요청 수행 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "3") // 2차 카테고리 ID 목록 - .param("taskTitle", "")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").exists()); - } - @Test - public void testFilterTeamStatus_validRequest_shouldReturnFilteredResults() throws Exception { - // mock 응답 설정: 예상되는 데이터 - List mockResponseData = List.of( - new TeamMemberTaskResponse( - 1L, - "사용자1", - "imageUrl1", - "부서1", - 2, - 1, - 3, - List.of(new TaskItemResponse(1L, "code1", "타이틀1", "1", "2", "요청자1", "imageUrl", "부서", 1, TaskStatus.COMPLETED, LocalDateTime.now()))) - ); - - // mock 동작 설정: filterTeamStatus 메소드를 호출 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) - .thenReturn(new TeamStatusResponse(mockResponseData)); - - // mockMvc 요청 수행: 필터링된 결과 확인 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "2") // 2차 카테고리 ID 목록 - .param("taskTitle", "타이틀1")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").exists()) // members가 존재하는지 확인 - .andExpect(jsonPath("$.members[0].tasks[0].title").value("타이틀1")) // 첫 번째 작업의 타이틀 확인 - .andExpect(jsonPath("$.members[0].tasks[0].taskStatus").value("IN_PROGRESS")) // 작업 상태 확인 - .andDo(print()); - } - - - @Test - public void testFilterTeamStatus_emptyResponse_shouldReturnEmpty() throws Exception { - // mock 응답 설정: 빈 리스트 반환 (조건에 맞는 작업이 없는 경우) - List mockResponseData = List.of(); - - /// mock 동작 설정: filterTeamStatus 메소드를 호출 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) - .thenReturn(new TeamStatusResponse(mockResponseData)); - - // mockMvc 요청 수행: 필터링된 결과가 없을 경우 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "2") // 2차 카테고리 ID 목록 - .param("taskTitle", "타이틀1")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isEmpty()); // members가 비어 있는지 확인 - } - - @Test - public void testFilterTeamStatus_invalidRequest_shouldReturnBadRequest() throws Exception { - // 잘못된 요청: 필터 값이 비어있거나 잘못됨 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "") // 잘못된 정렬 기준 - .param("mainCategoryIds", "") // 잘못된 1차 카테고리 ID 목록 - .param("categoryIds", "") // 잘못된 2차 카테고리 ID 목록 - .param("taskTitle", "")) // 잘못된 작업 타이틀 - .andExpect(status().isBadRequest()); // 400 Bad Request 응답을 예상 - } - @Test - public void testFilterTeamStatus_completedTaskShouldNotBeReturned() throws Exception { - // mock 응답 설정: 'COMPLETED' 상태인 작업이 제외되어야 함 - List mockResponseData = List.of( - new TeamMemberTaskResponse( - 1L, - "사용자1", - "imageUrl1", - "부서1", - 2, - 1, - 3, - List.of( - new TaskItemResponse(1L, "code1", "타이틀1", "1", "2", "요청자1", "imageUrl", "부서", 1, TaskStatus.IN_PROGRESS, LocalDateTime.now()), - new TaskItemResponse(2L, "code2", "타이틀2", "1", "2", "요청자2", "imageUrl", "부서", 2, TaskStatus.COMPLETED, LocalDateTime.now()) - ) - ) - ); - - // mock 동작 설정: filterTeamStatus 메소드 호출 - when(teamStatusService.filterTeamStatus(any(FilterTeamStatusRequest.class))) - .thenReturn(new TeamStatusResponse(mockResponseData)); - - // mockMvc 요청 수행: 필터링된 결과 확인 - mockMvc.perform(get("/api/team-status/filter") - .param("sortBy", "기여도순") // 정렬 기준 - .param("mainCategoryIds", "1") // 1차 카테고리 ID 목록 - .param("categoryIds", "2") // 2차 카테고리 ID 목록 - .param("taskTitle", "타이틀")) // 작업 타이틀 - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members[0].tasks").isArray()) // tasks가 배열 형태인지 확인 - .andExpect(jsonPath("$.members[0].tasks.length()").value(1)) // 완료된 작업은 제외되어야 하므로 tasks 배열 길이가 1이어야 함 - .andExpect(jsonPath("$.members[0].tasks[0].taskStatus").value("IN_PROGRESS")); // 첫 번째 작업의 상태는 IN_PROGRESS이어야 함 - } - - - - -} From ddd2d94a87bd2bcdd6bb52705be7e4c661cc1f37 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 16:38:24 +0900 Subject: [PATCH 06/11] =?UTF-8?q?CLAP-256=20fix:=20teamtaskresponse?= =?UTF-8?q?=EB=A1=9C=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/task/response/TeamStatusResponse.java | 6 ++-- ...askResponse.java => TeamTaskResponse.java} | 4 +-- .../persistense/TaskPersistenceAdapter.java | 4 +-- .../repository/task/TaskCustomRepository.java | 4 +-- .../task/TaskCustomRepositoryImpl.java | 6 ++-- .../repository/task/TaskRepository.java | 4 +-- .../port/outbound/task/LoadTaskPort.java | 4 +-- .../service/task/TeamStatusService.java | 7 ++--- src/main/resources/env.properties | 31 +++++++++++++++++++ 9 files changed, 50 insertions(+), 20 deletions(-) rename src/main/java/clap/server/adapter/inbound/web/dto/task/response/{TeamMemberTaskResponse.java => TeamTaskResponse.java} (87%) create mode 100644 src/main/resources/env.properties diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java index e5c44252..95e9be15 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamStatusResponse.java @@ -3,13 +3,13 @@ import java.util.List; public record TeamStatusResponse( - List members, + List members, int totalInProgressTaskCount, int totalPendingTaskCount, int totalTaskCount ) { // 기존 생성자 (3개 파라미터) - public TeamStatusResponse(List members, int totalInProgressTaskCount, int totalPendingTaskCount) { + public TeamStatusResponse(List members, int totalInProgressTaskCount, int totalPendingTaskCount) { this( (members == null) ? List.of() : members, totalInProgressTaskCount, @@ -19,7 +19,7 @@ public TeamStatusResponse(List members, int totalInProgr } // 추가된 생성자 (List만 받음) - public TeamStatusResponse(List members) { + public TeamStatusResponse(List members) { this(members, 0, 0); // 기본값을 사용하여 생성 } } diff --git a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskResponse.java similarity index 87% rename from src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java rename to src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskResponse.java index 5bdf1579..b8a9019c 100644 --- a/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamMemberTaskResponse.java +++ b/src/main/java/clap/server/adapter/inbound/web/dto/task/response/TeamTaskResponse.java @@ -5,7 +5,7 @@ import java.util.List; -public record TeamMemberTaskResponse( +public record TeamTaskResponse( Long processorId, String nickname, String imageUrl, @@ -16,7 +16,7 @@ public record TeamMemberTaskResponse( List tasks ) { @QueryProjection - public TeamMemberTaskResponse { + public TeamTaskResponse { tasks = (tasks == null) ? List.of() : tasks; } } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java b/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java index 7171871b..36f0e9db 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/TaskPersistenceAdapter.java @@ -3,7 +3,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import clap.server.adapter.outbound.persistense.mapper.TaskPersistenceMapper; @@ -112,7 +112,7 @@ public Slice findTaskBoardByFilter(Long processorId, List stat } @Override - public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { + public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { return taskRepository.findTeamStatus(memberId, filter); } diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java index b016c5cb..a6b0625f 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepository.java @@ -3,7 +3,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import org.springframework.data.domain.Page; @@ -15,7 +15,7 @@ public interface TaskCustomRepository { Page findTasksRequestedByUser(Long requesterId, Pageable pageable, FilterTaskListRequest findTaskListRequest); - List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); + List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); Page findPendingApprovalTasks(Pageable pageable, FilterTaskListRequest findTaskListRequest); Page findAllTasks(Pageable pageable, FilterTaskListRequest findTaskListRequest); List findTasksByFilter(Long processorId, List statuses, LocalDateTime localDateTime, FilterTaskBoardRequest request, Pageable pageable); diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java index 37059889..ecfa13f5 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java @@ -3,7 +3,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.inbound.web.dto.task.response.TeamTaskItemResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; @@ -57,7 +57,7 @@ public Page findTasksAssignedByManager(Long processorId, Pageable pa } @Override - public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { + public List findTeamStatus(Long memberId, FilterTeamStatusRequest filter) { // filter가 null인 경우에도 기본적으로 모든 데이터를 조회하도록 처리 BooleanBuilder builder = new BooleanBuilder(); @@ -132,7 +132,7 @@ public List findTeamStatus(Long memberId, FilterTeamStat int pendingTaskCount = (int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.PENDING_COMPLETED).count(); int totalTaskCount = inProgressTaskCount + pendingTaskCount; - return new TeamMemberTaskResponse( + return new TeamTaskResponse( entry.getKey(), entry.getValue().get(0).getProcessor().getNickname(), entry.getValue().get(0).getProcessor().getImageUrl(), diff --git a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java index 6ff86056..13e22752 100644 --- a/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java +++ b/src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskRepository.java @@ -2,7 +2,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.TaskEntity; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import io.lettuce.core.dynamic.annotation.Param; @@ -54,7 +54,7 @@ Optional findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAf Long processorId, TaskStatus taskStatus, Long processorOrder); @Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ") - List findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter); + List findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter); diff --git a/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java b/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java index 054d0343..5c38cd38 100644 --- a/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java +++ b/src/main/java/clap/server/application/port/outbound/task/LoadTaskPort.java @@ -3,7 +3,7 @@ import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus; import clap.server.domain.model.task.Task; import org.springframework.data.domain.Page; @@ -37,5 +37,5 @@ public interface LoadTaskPort { Slice findTaskBoardByFilter(Long processorId, List statuses, LocalDateTime untilDateTime, FilterTaskBoardRequest request, Pageable pageable); - List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); + List findTeamStatus(Long memberId, FilterTeamStatusRequest filter); } diff --git a/src/main/java/clap/server/application/service/task/TeamStatusService.java b/src/main/java/clap/server/application/service/task/TeamStatusService.java index a6a72ba8..5b6e5ac8 100644 --- a/src/main/java/clap/server/application/service/task/TeamStatusService.java +++ b/src/main/java/clap/server/application/service/task/TeamStatusService.java @@ -1,12 +1,11 @@ package clap.server.application.service.task; import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest; -import clap.server.adapter.inbound.web.dto.task.response.TeamMemberTaskResponse; +import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse; import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse; import clap.server.application.port.inbound.task.FilterTeamStatusUsecase; import clap.server.application.port.inbound.task.LoadTeamStatusUsecase; import clap.server.application.port.outbound.task.LoadTaskPort; -import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; @@ -22,13 +21,13 @@ public TeamStatusService(LoadTaskPort loadTaskPort) { @Override public TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter) { - List members = loadTaskPort.findTeamStatus(memberId, filter); + List members = loadTaskPort.findTeamStatus(memberId, filter); return new TeamStatusResponse(members); } @Override public TeamStatusResponse filterTeamStatus(FilterTeamStatusRequest filter) { - List members = loadTaskPort.findTeamStatus(null, filter); + List members = loadTaskPort.findTeamStatus(null, filter); return new TeamStatusResponse(members); } diff --git a/src/main/resources/env.properties b/src/main/resources/env.properties new file mode 100644 index 00000000..3b653581 --- /dev/null +++ b/src/main/resources/env.properties @@ -0,0 +1,31 @@ + +DATABASE_HOST=localhost +DATABASE_PORT=3306 +DATABASE_NAME=taskflow +DATABASE_USERNAME=root +DATABASE_PASSWORD=km7971na + +KAKAO_REGION=kr-central-2 +KAKAO_OBJECT_STORAGE_ENDPOINT=https://objectstorage.kr-central-2.kakaocloud.com +KAKAO_OBJECT_STORAGE_ACCESS_KEY=253474a41cb447f4ad3c38e0ed9963c4 +KAKAO_OBJECT_STORAGE_SECRET_KEY=74861656e46845488ec4357f155fa3ed +KAKAO_OBJECT_STORAGE_BUCKET_NAME=taskflow +KAKAO_PROJECT_ID=34481374c1ee4bbb8745df43e4c13fff + + +TASKFLOW_SERVICE_SERVER=210.109.59.9:9090 + +SWAGGER_SERVER_URL=http://210.109.59.9:9090 + + +KAKAOWORK_WEBHOOK_URL=https://api.kakaowork.com/v1/messages.send_by_email +KAKAOWORK_WEBHOOK_AUTH=Bearer 1b01becc.a7f10da76d2e4038948771107cfe5c1d +AGIT_WEBHOOK_URL=https://agit.io/webhook/a342181d-fb18-4eb0-a99a-30f4fb5b14b1 +MAIL_USERNAME=leegd120@gmail.com +MAIL_PASSWORD=znlictzarqurxlla + +JIRA_BASE_URL=https://gachon-clap.atlassian.net/ +JIRA_API_KEY=ATATT3xFfGF0Y1TU8ydsORKL7aKLur-FQ4xppSEWLlhMyZE4Jx1zGA-2kvcxDj-A1ahlFVrZ6fVTsqesUT7QZhEoaiyFiq48oQ-hGVoXe-oZxg3civZcxJ4JNDDOgv26IjBAP39VsX3CjF7gfptNGX-iHz5f5_AXs4vlLT4SaQY5XB-Yk66DH0A=11BEF509 +JIRA_USER_EMAIL=joowojr@gmail.com +PAT_TOKEN=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 + From c218a6696ed47050568e257faf6b7d8ec5dd2241 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 22:50:26 +0900 Subject: [PATCH 07/11] =?UTF-8?q?CLAP-256=20fix:=20develop=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=EC=9D=98=20src/test/java/resources=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/resources/application.yml | 61 +++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/test/java/resources/application.yml diff --git a/src/test/java/resources/application.yml b/src/test/java/resources/application.yml new file mode 100644 index 00000000..a6acd661 --- /dev/null +++ b/src/test/java/resources/application.yml @@ -0,0 +1,61 @@ +spring: + # H2 설정 정보 (H2 Console에 접속하기 위한 설정) + h2: + console: + enabled: false # H2 Console을 사용할지 여부 (H2 Console은 H2 Database를 UI로 제공해주는 기능) + path: /h2 # H2 Console의 Path + # Database 설정 정보 (H2 연동 정보) + datasource: + driver-class-name: org.h2.Driver # H2 Database 사용 + url: jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false # H2 접속 정보 + username: taskflow # H2 접속 시 입력할 username 정보 + password: # H2 접속 시 입력할 password 정보 + jpa: + hibernate: + ddl-auto: create + flyway: + enabled: false + + mail: + host: smtp.gmail.com + port: 587 + username: leegd120@gmail.com + password: znlictzarqurxlla + properties: + mail: + smtp: + auth: true + starttls: + enable: true + + testcontainers: + beans: + startup: parallel +server: + domain: + local: 127.0.0.1:8080 + service: 127.0.0.1:8080 + +web: + domain: + local: 127.0.0.1:3O00 + service: 127.0.0.1:3000 + +swagger: + server: + url: http://localhost:8080 + +jwt: + secret-key: + access-token: exampleSecretKeyForTFSystemAccessSecretKeyTestForPadding + temporary-token: exampleSecretKeyForTFSystemTemporarySecretKeyTestForPadding + refresh-token: exampleSecretKeyTFSystemRefreshSecretKeyTestForPadding + expiration-time: + access-token: 43200000 # 1000 * 60 * 60 * 12 = 43200000 (12 hours) + temporary-token: 300000 + refresh-token: 1209600000 # 1000 * 60 * 60 * 24 * 14 = 1209600000 (14 days) + +password: + policy: + length: 12 + characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+ \ No newline at end of file From 5bfb1cb2a97a8c0596b2b37f891cdb17ecfb9b06 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 23:11:06 +0900 Subject: [PATCH 08/11] =?UTF-8?q?CLAP-256=20fix:=20application.yml=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/{java => }/resources/application.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/{java => }/resources/application.yml (100%) diff --git a/src/test/java/resources/application.yml b/src/test/resources/application.yml similarity index 100% rename from src/test/java/resources/application.yml rename to src/test/resources/application.yml From 3de893d6e81d95aed6d5ec6b124807ec4b024d20 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 23:12:24 +0900 Subject: [PATCH 09/11] =?UTF-8?q?CLAP-256=20fix:=20env.properties=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/env.properties | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 src/main/resources/env.properties diff --git a/src/main/resources/env.properties b/src/main/resources/env.properties deleted file mode 100644 index 3b653581..00000000 --- a/src/main/resources/env.properties +++ /dev/null @@ -1,31 +0,0 @@ - -DATABASE_HOST=localhost -DATABASE_PORT=3306 -DATABASE_NAME=taskflow -DATABASE_USERNAME=root -DATABASE_PASSWORD=km7971na - -KAKAO_REGION=kr-central-2 -KAKAO_OBJECT_STORAGE_ENDPOINT=https://objectstorage.kr-central-2.kakaocloud.com -KAKAO_OBJECT_STORAGE_ACCESS_KEY=253474a41cb447f4ad3c38e0ed9963c4 -KAKAO_OBJECT_STORAGE_SECRET_KEY=74861656e46845488ec4357f155fa3ed -KAKAO_OBJECT_STORAGE_BUCKET_NAME=taskflow -KAKAO_PROJECT_ID=34481374c1ee4bbb8745df43e4c13fff - - -TASKFLOW_SERVICE_SERVER=210.109.59.9:9090 - -SWAGGER_SERVER_URL=http://210.109.59.9:9090 - - -KAKAOWORK_WEBHOOK_URL=https://api.kakaowork.com/v1/messages.send_by_email -KAKAOWORK_WEBHOOK_AUTH=Bearer 1b01becc.a7f10da76d2e4038948771107cfe5c1d -AGIT_WEBHOOK_URL=https://agit.io/webhook/a342181d-fb18-4eb0-a99a-30f4fb5b14b1 -MAIL_USERNAME=leegd120@gmail.com -MAIL_PASSWORD=znlictzarqurxlla - -JIRA_BASE_URL=https://gachon-clap.atlassian.net/ -JIRA_API_KEY=ATATT3xFfGF0Y1TU8ydsORKL7aKLur-FQ4xppSEWLlhMyZE4Jx1zGA-2kvcxDj-A1ahlFVrZ6fVTsqesUT7QZhEoaiyFiq48oQ-hGVoXe-oZxg3civZcxJ4JNDDOgv26IjBAP39VsX3CjF7gfptNGX-iHz5f5_AXs4vlLT4SaQY5XB-Yk66DH0A=11BEF509 -JIRA_USER_EMAIL=joowojr@gmail.com -PAT_TOKEN=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 - From 372a65ef0c09f1f4630486d2e0e370f26746b7f4 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Tue, 4 Feb 2025 23:38:47 +0900 Subject: [PATCH 10/11] =?UTF-8?q?CLAP-256=20Docs:=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EB=AA=85=EC=84=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/inbound/web/task/TeamStatusController.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java b/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java index 71477182..cd3ac6b7 100644 --- a/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java +++ b/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java @@ -5,7 +5,7 @@ import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse; import clap.server.application.service.task.TeamStatusService; import clap.server.common.annotation.architecture.WebAdapter; -import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; @@ -14,15 +14,14 @@ @RestController @RequestMapping("/api/team-status") @RequiredArgsConstructor -@Tag(name = "팀 현황 조회 API") @WebAdapter public class TeamStatusController { - + private final TeamStatusService teamStatusService; - + @Operation(summary = "팀 현황 필터링 조회 API") @GetMapping("/filter") public ResponseEntity filterTeamStatus(@Validated @ModelAttribute FilterTeamStatusRequest filter) { TeamStatusResponse response = teamStatusService.filterTeamStatus(filter); return ResponseEntity.ok(response); } -} \ No newline at end of file +} From 39d2bdadd70f0ba800a5261bf72085ee822e8503 Mon Sep 17 00:00:00 2001 From: nano-mm Date: Wed, 5 Feb 2025 00:06:35 +0900 Subject: [PATCH 11/11] =?UTF-8?q?CLAP-256=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20?= =?UTF-8?q?=EB=AA=85=EC=84=B8=20=ED=83=9C=EA=B7=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/inbound/web/task/TeamStatusController.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java b/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java index cd3ac6b7..41997c09 100644 --- a/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java +++ b/src/main/java/clap/server/adapter/inbound/web/task/TeamStatusController.java @@ -6,16 +6,18 @@ import clap.server.application.service.task.TeamStatusService; import clap.server.common.annotation.architecture.WebAdapter; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +@Tag(name = "02. Task [담당자]") +@WebAdapter @RestController -@RequestMapping("/api/team-status") @RequiredArgsConstructor -@WebAdapter -public class TeamStatusController { +@RequestMapping("/api/team-status") + public class TeamStatusController { private final TeamStatusService teamStatusService; @Operation(summary = "팀 현황 필터링 조회 API")