From e44d6feefba6d38efd69825e5d596c156e103fbb Mon Sep 17 00:00:00 2001 From: jeongwpa <55525927+yhames@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:14:31 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20[Feature]=20#886=20Admin=20?= =?UTF-8?q?=EB=8C=80=ED=9A=8C=20=EC=A0=84=EC=B2=B4=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20(#890)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repo/agenda/AgendaAdminRepository.java | 10 ++ .../controller/AgendaAdminController.java | 45 ++++++ .../response/AgendaAdminResDto.java | 84 +++++++++++ .../agenda/service/AgendaAdminService.java | 22 +++ .../controller/AgendaAdminControllerTest.java | 132 ++++++++++++++++++ .../service/AgendaAdminServiceTest.java | 71 ++++++++++ 6 files changed, 364 insertions(+) create mode 100644 gg-admin-repo/src/main/java/gg/admin/repo/agenda/AgendaAdminRepository.java create mode 100644 gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/AgendaAdminController.java create mode 100644 gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/response/AgendaAdminResDto.java create mode 100644 gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/service/AgendaAdminService.java create mode 100644 gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/controller/AgendaAdminControllerTest.java create mode 100644 gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/service/AgendaAdminServiceTest.java diff --git a/gg-admin-repo/src/main/java/gg/admin/repo/agenda/AgendaAdminRepository.java b/gg-admin-repo/src/main/java/gg/admin/repo/agenda/AgendaAdminRepository.java new file mode 100644 index 000000000..58a4a9ace --- /dev/null +++ b/gg-admin-repo/src/main/java/gg/admin/repo/agenda/AgendaAdminRepository.java @@ -0,0 +1,10 @@ +package gg.admin.repo.agenda; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import gg.data.agenda.Agenda; + +@Repository +public interface AgendaAdminRepository extends JpaRepository { +} diff --git a/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/AgendaAdminController.java b/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/AgendaAdminController.java new file mode 100644 index 000000000..58dc62d75 --- /dev/null +++ b/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/AgendaAdminController.java @@ -0,0 +1,45 @@ +package gg.agenda.api.admin.agenda.controller; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.validation.Valid; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.agenda.api.admin.agenda.controller.response.AgendaAdminResDto; +import gg.agenda.api.admin.agenda.service.AgendaAdminService; +import gg.utils.dto.PageRequestDto; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/admin/agenda") +@RequiredArgsConstructor +public class AgendaAdminController { + + private final AgendaAdminService agendaAdminService; + + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Agenda 요청 리스트 조회 성공") + }) + @GetMapping("/request/list") + public ResponseEntity> getAgendaRequestList( + @RequestBody @Valid PageRequestDto pageDto) { + int page = pageDto.getPage(); + int size = pageDto.getSize(); + Pageable pageable = PageRequest.of(page - 1, size, Sort.by("id").descending()); + List agendaDtos = agendaAdminService.getAgendaRequestList(pageable).stream() + .map(AgendaAdminResDto.MapStruct.INSTANCE::toAgendaAdminResDto) + .collect(Collectors.toList()); + return ResponseEntity.ok(agendaDtos); + } +} diff --git a/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/response/AgendaAdminResDto.java b/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/response/AgendaAdminResDto.java new file mode 100644 index 000000000..f0b2fdb3b --- /dev/null +++ b/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/controller/response/AgendaAdminResDto.java @@ -0,0 +1,84 @@ +package gg.agenda.api.admin.agenda.controller.response; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import gg.data.agenda.Agenda; +import gg.data.agenda.type.AgendaStatus; +import gg.data.agenda.type.Location; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AgendaAdminResDto { + + private Long agendaId; + + private String agendaTitle; + + private String agendaDeadLine; + + private String agendaStartTime; + + private String agendaEndTime; + + private int agendaCurrentTeam; + + private int agendaMaxTeam; + + private int agendaMinPeople; + + private int agendaMaxPeople; + + private Location agendaLocation; + + private Boolean isRanking; + + private Boolean isOfficial; + + private AgendaStatus agendaStatus; + + @Builder + public AgendaAdminResDto(Long agendaId, String agendaTitle, String agendaDeadLine, String agendaStartTime, + String agendaEndTime, int agendaCurrentTeam, int agendaMaxTeam, int agendaMinPeople, int agendaMaxPeople, + Location agendaLocation, Boolean isRanking, Boolean isOfficial, AgendaStatus agendaStatus) { + this.agendaId = agendaId; + this.agendaTitle = agendaTitle; + this.agendaDeadLine = agendaDeadLine; + this.agendaStartTime = agendaStartTime; + this.agendaEndTime = agendaEndTime; + this.agendaCurrentTeam = agendaCurrentTeam; + this.agendaMaxTeam = agendaMaxTeam; + this.agendaMinPeople = agendaMinPeople; + this.agendaMaxPeople = agendaMaxPeople; + this.agendaLocation = agendaLocation; + this.isRanking = isRanking; + this.isOfficial = isOfficial; + this.agendaStatus = agendaStatus; + } + + @Mapper + public interface MapStruct { + + AgendaAdminResDto.MapStruct INSTANCE = Mappers.getMapper(AgendaAdminResDto.MapStruct.class); + + @Mapping(target = "agendaId", source = "id") + @Mapping(target = "agendaTitle", source = "title") + @Mapping(target = "agendaDeadLine", source = "deadline") + @Mapping(target = "agendaStartTime", source = "startTime") + @Mapping(target = "agendaEndTime", source = "endTime") + @Mapping(target = "agendaCurrentTeam", source = "currentTeam") + @Mapping(target = "agendaMaxTeam", source = "maxTeam") + @Mapping(target = "agendaMinPeople", source = "minPeople") + @Mapping(target = "agendaMaxPeople", source = "maxPeople") + @Mapping(target = "agendaLocation", source = "location") + @Mapping(target = "isRanking", source = "isRanking") + @Mapping(target = "isOfficial", source = "isOfficial") + @Mapping(target = "agendaStatus", source = "status") + AgendaAdminResDto toAgendaAdminResDto(Agenda agenda); + } +} diff --git a/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/service/AgendaAdminService.java b/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/service/AgendaAdminService.java new file mode 100644 index 000000000..d6aecd645 --- /dev/null +++ b/gg-agenda-api/src/main/java/gg/agenda/api/admin/agenda/service/AgendaAdminService.java @@ -0,0 +1,22 @@ +package gg.agenda.api.admin.agenda.service; + +import java.util.List; + +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import gg.admin.repo.agenda.AgendaAdminRepository; +import gg.data.agenda.Agenda; +import gg.repo.agenda.AgendaRepository; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AgendaAdminService { + + private final AgendaAdminRepository agendaAdminRepository; + + public List getAgendaRequestList(Pageable pageable) { + return agendaAdminRepository.findAll(pageable).getContent(); + } +} diff --git a/gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/controller/AgendaAdminControllerTest.java b/gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/controller/AgendaAdminControllerTest.java new file mode 100644 index 000000000..d0b768dd8 --- /dev/null +++ b/gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/controller/AgendaAdminControllerTest.java @@ -0,0 +1,132 @@ +package gg.agenda.api.admin.agenda.controller; + +import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.springframework.test.web.servlet.MockMvcBuilder.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.transaction.Transactional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MockMvcBuilder; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import gg.agenda.api.AgendaMockData; +import gg.agenda.api.admin.agenda.controller.response.AgendaAdminResDto; +import gg.data.agenda.Agenda; +import gg.data.agenda.type.AgendaStatus; +import gg.data.user.User; +import gg.repo.agenda.AgendaRepository; +import gg.utils.TestDataUtils; +import gg.utils.annotation.IntegrationTest; +import gg.utils.dto.PageRequestDto; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@IntegrationTest +@Transactional +@AutoConfigureMockMvc +public class AgendaAdminControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private TestDataUtils testDataUtils; + + @Autowired + private AgendaMockData agendaMockData; + + @Autowired + EntityManager em; + + @Autowired + AgendaRepository agendaRepository; + + private User user; + + private String accessToken; + + @BeforeEach + void setUp() { + user = testDataUtils.createNewUser(); + accessToken = testDataUtils.getLoginAccessTokenFromUser(user); + } + + @Nested + @DisplayName("Admin Agenda 상세 조회") + class GetAgendaAdmin { + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3, 4, 5}) + @DisplayName("Admin Agenda 상세 조회 성공") + void findAgendaByAgendaKeySuccessAdmin(int page) throws Exception { + // given + int size = 10; + List agendas = new ArrayList<>(); + agendas.addAll(agendaMockData.createOfficialAgendaList(5, AgendaStatus.ON_GOING)); + agendas.addAll(agendaMockData.createOfficialAgendaList(5, AgendaStatus.CONFIRM)); + agendas.addAll(agendaMockData.createOfficialAgendaList(5, AgendaStatus.CANCEL)); + agendas.addAll(agendaMockData.createNonOfficialAgendaList(5, AgendaStatus.ON_GOING)); + agendas.addAll(agendaMockData.createNonOfficialAgendaList(5, AgendaStatus.CONFIRM)); + agendas.addAll(agendaMockData.createNonOfficialAgendaList(5, AgendaStatus.CANCEL)); + PageRequestDto pageRequestDto = new PageRequestDto(page, size); + String request = objectMapper.writeValueAsString(pageRequestDto); + + // when + String response = mockMvc.perform(get("/admin/agenda/request/list") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(request)) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + AgendaAdminResDto[] result = objectMapper.readValue(response, AgendaAdminResDto[].class); + + // then + assertThat(result).hasSize(((page - 1) * size) < agendas.size() + ? Math.min(size, agendas.size() - (page - 1) * size) : 0); + agendas.sort((a, b) -> b.getId().compareTo(a.getId())); + for (int i = 0; i < result.length; i++) { + assertThat(result[i].getAgendaId()).isEqualTo(agendas.get(i + (page - 1) * size).getId()); + } + } + + @Test + @DisplayName("Admin Agenda 상세 조회 성공 - 대회가 존재하지 않는 경우") + void findAgendaByAgendaKeySuccessAdminWithNoContent() throws Exception { + // given + int page = 1; + int size = 10; + PageRequestDto pageRequestDto = new PageRequestDto(page, size); + String request = objectMapper.writeValueAsString(pageRequestDto); + + // when + String response = mockMvc.perform(get("/admin/agenda/request/list") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(request)) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + AgendaAdminResDto[] result = objectMapper.readValue(response, AgendaAdminResDto[].class); + + // then + assertThat(result).isEmpty(); + } + } +} diff --git a/gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/service/AgendaAdminServiceTest.java b/gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/service/AgendaAdminServiceTest.java new file mode 100644 index 000000000..928f02355 --- /dev/null +++ b/gg-agenda-api/src/test/java/gg/agenda/api/admin/agenda/service/AgendaAdminServiceTest.java @@ -0,0 +1,71 @@ +package gg.agenda.api.admin.agenda.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import gg.admin.repo.agenda.AgendaAdminRepository; +import gg.data.agenda.Agenda; +import gg.utils.annotation.UnitTest; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@UnitTest +public class AgendaAdminServiceTest { + + @Mock + AgendaAdminRepository agendaAdminRepository; + + @InjectMocks + AgendaAdminService agendaAdminService; + + @Nested + @DisplayName("Admin Agenda 상세 조회") + class GetAgendaAdmin { + + @Test + @DisplayName("Admin Agenda 상세 조회 성공") + void findAgendaByAgendaKeySuccessAdmin() { + // given + Pageable pageable = mock(Pageable.class); + List agendas = new ArrayList<>(); + agendas.add(Agenda.builder().build()); + Page page = new PageImpl<>(agendas); + when(agendaAdminRepository.findAll(pageable)).thenReturn(page); + + // when + List result = agendaAdminService.getAgendaRequestList(pageable); + + // then + verify(agendaAdminRepository, times(1)).findAll(pageable); + assertThat(result).isNotEmpty(); + } + + @Test + @DisplayName("Admin Agenda 상세 조회 성공 - 빈 리스트인 경우") + void findAgendaByAgendaKeySuccessAdminWithNoContent() { + // given + Pageable pageable = mock(Pageable.class); + Page page = new PageImpl<>(List.of()); + when(agendaAdminRepository.findAll(pageable)).thenReturn(page); + + // when + List result = agendaAdminService.getAgendaRequestList(pageable); + + // then + verify(agendaAdminRepository, times(1)).findAll(pageable); + assertThat(result).isEmpty(); + } + } +}