From c84ca7ff2d803f1dfce799e1e7acedebf6456554 Mon Sep 17 00:00:00 2001 From: wonie <119565449+wonies@users.noreply.github.com> Date: Fri, 27 Dec 2024 17:25:27 +0900 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=EC=9D=BC=EC=A0=95=20=EC=B6=94=EA=B0=80=20api=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20#1052=20(#1083)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: wonie --- .../controller/PublicScheduleController.java | 1 + .../service/PublicScheduleService.java | 3 ++ .../PublicScheduleMockData.java | 24 ++-------------- .../PublicScheduleControllerTest.java | 28 +++++++++++++++++++ .../response/PublicScheduleResDtoTest.java | 4 --- .../java/gg/utils/exception/ErrorCode.java | 1 - 6 files changed, 34 insertions(+), 27 deletions(-) delete mode 100644 gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDtoTest.java diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java index 78d979485..53f0d56db 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java @@ -1,5 +1,6 @@ package gg.calendar.api.user.schedule.publicschedule.controller; + import javax.validation.Valid; import org.springframework.http.HttpStatus; diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java index 0e5960eb4..8727777a7 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java @@ -25,6 +25,9 @@ public void createPublicSchedule(PublicScheduleCreateReqDto req, Long userId) { if (!user.getIntraId().equals(req.getAuthor())) { throw new CustomRuntimeException(ErrorCode.CALENDAR_AUTHOR_NOT_MATCH); } + if (req.getStartTime().isAfter(req.getEndTime())) { + throw new CustomRuntimeException(ErrorCode.CALENDAR_BEFORE_DATE); + } PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), req); publicScheduleRepository.save(publicSchedule); } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/PublicScheduleMockData.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/PublicScheduleMockData.java index 5977d9f6f..98bc906bb 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/PublicScheduleMockData.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/PublicScheduleMockData.java @@ -1,17 +1,10 @@ package gg.calendar.api.user.schedule.publicschedule; -import java.time.LocalDateTime; - import javax.persistence.EntityManager; import org.springframework.stereotype.Component; -import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleCreateReqDto; -import gg.data.BaseTimeEntity; -import gg.data.calendar.PublicSchedule; -import gg.data.calendar.type.DetailClassification; -import gg.data.calendar.type.EventTag; -import gg.data.calendar.type.ScheduleStatus; + import gg.repo.calendar.PublicScheduleRepository; import gg.utils.TestDataUtils; import lombok.RequiredArgsConstructor; @@ -23,18 +16,5 @@ public class PublicScheduleMockData { private final PublicScheduleRepository publicScheduleRepository; private final TestDataUtils testDataUtils; - public PublicSchedule createPublicSchedule(String author) { - return PublicSchedule.builder() - .classification(DetailClassification.EVENT) - .jobTag(null) - .techTag(null) - .title("Test Schedule") - .status(ScheduleStatus.ACTIVATE) - .author(author) - .content("Test Content") - .link("http://test.com") - .startTime(LocalDateTime.now()) - .endTime(LocalDateTime.now().plusDays(1)) - .build(); - } + } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java index cc31352ea..2b895096b 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java @@ -122,5 +122,33 @@ void createPublicScheduleFail() throws Exception { List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); assertThat(schedules).isEmpty(); } + + @Test + @DisplayName("공개일정- 기간이 잘못되었을 때/ 종료닐짜가 시작날짜보다 빠를때") + void createPublicScheduleFail2() throws Exception { + // given : reqDto를 생성 + PublicScheduleCreateReqDto publicScheduleDto = PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .eventTag(EventTag.ETC) + .author(user.getIntraId()) + .title("Test Schedule") + .content("Test Content") + .link("http://test.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().minusDays(1)) + .build(); + // when : reqDto로 요청 + mockMvc.perform(post("/calendar/public").header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleDto))) + .andExpect(status().isBadRequest()) + .andExpect(result -> { + status().isBadRequest(); // 처음에 errorcode로 잡았는데, status로 잡음 + }) + .andDo(print()); + // then : 예외가 발생 + List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); + assertThat(schedules).isEmpty(); + } } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDtoTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDtoTest.java deleted file mode 100644 index fe5c7035b..000000000 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDtoTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package gg.calendar.api.user.schedule.publicschedule.controller.response; - -public class PublicScheduleResDtoTest { -} diff --git a/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java index a0b1e9414..8fa62caca 100644 --- a/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java +++ b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java @@ -245,7 +245,6 @@ public enum ErrorCode { PUBLIC_SCHEDULE_NOT_FOUND(404, "CA102", "공유 일정을 찾을 수 없습니다."), SCHEDULE_GROUP_NOT_FOUND(404, "CA103", "스캐줄 그룹을 찾을 수 없습니다."); - private final int status; private final String errCode; private String message; From 608f83a3eb31849e857dadc58a43bb1874f0174e Mon Sep 17 00:00:00 2001 From: seyeon22222 <92151066+seyeon22222@users.noreply.github.com> Date: Mon, 30 Dec 2024 13:45:21 +0900 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20Admin=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=EC=9D=BC=EC=A0=95=20=EC=A1=B0=ED=9A=8C=20API=20#1063?= =?UTF-8?q?=20(#1084)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PublicScheduleAdminRepository.java | 5 ++ .../PublicScheduleAdminController.java | 18 ++++++ .../response/PublicScheduleAdminResDto.java | 62 +++++++++++++++++++ .../service/PublicScheduleAdminService.java | 24 +++++++ .../admin/PublicScheduleAdminMockData.java | 52 +++++++++++++++- .../PublicScheduleAdminControllerTest.java | 61 ++++++++++++++++++ 6 files changed, 221 insertions(+), 1 deletion(-) diff --git a/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java b/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java index ff1d9715a..fa7932dc1 100644 --- a/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java +++ b/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java @@ -2,13 +2,18 @@ import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; @Repository public interface PublicScheduleAdminRepository extends JpaRepository { List findByAuthor(String author); + + Page findAllByClassification(DetailClassification detailClassification, Pageable pageable); } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java index 7c5486c19..1c48773e0 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java @@ -4,13 +4,20 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; import gg.calendar.api.admin.schedule.publicschedule.service.PublicScheduleAdminService; +import gg.data.calendar.type.DetailClassification; +import gg.utils.dto.PageRequestDto; +import gg.utils.dto.PageResponseDto; import lombok.RequiredArgsConstructor; @RestController @@ -27,4 +34,15 @@ public ResponseEntity publicScheduleCreate( return ResponseEntity.status(HttpStatus.CREATED).build(); } + @GetMapping("/list/{detailClassification}") + public ResponseEntity> publicScheduleAdminClassificationList( + @PathVariable DetailClassification detailClassification, @ModelAttribute PageRequestDto pageRequestDto) { + int page = pageRequestDto.getPage(); + int size = pageRequestDto.getSize(); + + PageResponseDto pageResponseDto = publicScheduleAdminService.findAllByClassification( + detailClassification, page, size); + + return ResponseEntity.ok(pageResponseDto); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java index b1556443c..b26e996d8 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java @@ -1,4 +1,66 @@ package gg.calendar.api.admin.schedule.publicschedule.controller.response; +import java.time.LocalDateTime; + +import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class PublicScheduleAdminResDto { + private Long id; + + private DetailClassification classification; + + private EventTag eventTag; + + private JobTag jobTag; + + private TechTag techTag; + + private String author; + + private String title; + + private LocalDateTime startTime; + + private LocalDateTime endTime; + + private String link; + + private Integer sharedCount; + + private ScheduleStatus status; + + @Builder + public PublicScheduleAdminResDto(PublicSchedule publicSchedule) { + this.id = publicSchedule.getId(); + this.classification = publicSchedule.getClassification(); + this.eventTag = publicSchedule.getEventTag(); + this.jobTag = publicSchedule.getJobTag(); + this.techTag = publicSchedule.getTechTag(); + this.author = publicSchedule.getAuthor(); + this.title = publicSchedule.getTitle(); + this.startTime = publicSchedule.getStartTime(); + this.endTime = publicSchedule.getEndTime(); + this.link = publicSchedule.getLink(); + this.sharedCount = publicSchedule.getSharedCount(); + this.status = publicSchedule.getStatus(); + } + + @Override + public String toString() { + return "PublicScheduleAdminResDto{" + "id=" + id + ", classification=" + classification + ", eventTag=" + + eventTag + ", jobTag=" + jobTag + ", techTag=" + techTag + ", author='" + author + '\'' + ", title='" + + title + '\'' + ", startTime=" + startTime + ", endTime=" + endTime + ", link='" + link + '\'' + + ", sharedCount=" + sharedCount + ", status=" + status + '}'; + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java index f4b1d06b5..12a29d2bc 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java @@ -1,13 +1,22 @@ package gg.calendar.api.admin.schedule.publicschedule.service; import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import gg.admin.repo.calendar.PublicScheduleAdminRepository; import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.utils.dto.PageResponseDto; import gg.utils.exception.ErrorCode; import gg.utils.exception.custom.CustomRuntimeException; import lombok.RequiredArgsConstructor; @@ -29,6 +38,21 @@ public void createPublicSchedule(PublicScheduleAdminCreateReqDto publicScheduleA publicScheduleAdminRepository.save(publicSchedule); } + public PageResponseDto findAllByClassification( + DetailClassification detailClassification, int page, int size) { + + Pageable pageable = PageRequest.of(page - 1, size, + Sort.by(Sort.Order.asc("status"), Sort.Order.asc("startTime"))); + + Page publicSchedules = publicScheduleAdminRepository.findAllByClassification( + detailClassification, pageable); + + List publicScheduleList = publicSchedules.stream() + .map(PublicScheduleAdminResDto::new) + .collect(Collectors.toList()); + return PageResponseDto.of(publicSchedules.getTotalElements(), publicScheduleList); + } + private void dateTimeErrorCheck(LocalDateTime startTime, LocalDateTime endTime) { if (startTime.isAfter(endTime)) { throw new CustomRuntimeException(ErrorCode.CALENDAR_BEFORE_DATE); diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java index 6367d8da1..ba252e6a1 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java @@ -7,10 +7,11 @@ import org.springframework.stereotype.Component; import gg.admin.repo.calendar.PublicScheduleAdminRepository; -import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; import lombok.RequiredArgsConstructor; @Component @@ -35,4 +36,53 @@ public PublicSchedule createPublicSchedule() { return publicScheduleAdminRepository.save(publicSchedule); } + public void createPublicScheduleEvent(int size) { + for (int i = 0; i < size; i++) { + PublicSchedule publicSchedule = PublicSchedule.builder() + .classification(DetailClassification.EVENT) + .eventTag(EventTag.JOB_FORUM) + .author("42GG") + .title("Job " + i) + .content("TEST JOB") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(i)) + .endTime(LocalDateTime.now().plusDays(i + 10)) + .build(); + publicScheduleAdminRepository.save(publicSchedule); + } + } + + public void createPublicScheduleJob(int size) { + for (int i = 0; i < size; i++) { + PublicSchedule publicSchedule = PublicSchedule.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.EXPERIENCED) + .author("42GG") + .title("Job " + i) + .content("TEST JOB") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(i)) + .endTime(LocalDateTime.now().plusDays(i + 10)) + .build(); + publicScheduleAdminRepository.save(publicSchedule); + } + } + + public void createPublicSchedulePrivate(int size) { + for (int i = 0; i < size; i++) { + PublicSchedule publicSchedule = PublicSchedule.builder() + .classification(DetailClassification.PRIVATE_SCHEDULE) + .author("42GG") + .title("Private " + i) + .content("TEST Private") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(i)) + .endTime(LocalDateTime.now().plusDays(i + 10)) + .build(); + publicScheduleAdminRepository.save(publicSchedule); + } + } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java index 7278421ec..0bda1dbd5 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java @@ -7,6 +7,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.stream.Stream; import javax.persistence.EntityManager; import javax.transaction.Transactional; @@ -15,16 +16,24 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import gg.admin.repo.calendar.PublicScheduleAdminRepository; import gg.calendar.api.admin.PublicScheduleAdminMockData; import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; import gg.calendar.api.admin.schedule.publicschedule.service.PublicScheduleAdminService; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; @@ -34,6 +43,7 @@ import gg.data.user.User; import gg.utils.TestDataUtils; import gg.utils.annotation.IntegrationTest; +import gg.utils.dto.PageResponseDto; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -170,4 +180,55 @@ public void createPublicScheduleContentMax() throws Exception { .andExpect(status().isBadRequest()); } } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Nested + @DisplayName("Admin PublicSchedule 태그 조회 테스트") + class GetPublicScheduleAdminClassificationListTest { + + private Stream inputParams() { + return Stream.of(Arguments.of("EVENT", 2, 10), Arguments.of("JOB_NOTICE", 1, 10), + Arguments.of("PRIVATE_SCHEDULE", 1, 2)); + } + + @ParameterizedTest + @MethodSource("inputParams") + @DisplayName("Admin PublicSchedule 태그 조회 테스트 - 성공") + void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, int size) throws + Exception { + // given + publicScheduleAdminMockData.createPublicScheduleEvent(20); + publicScheduleAdminMockData.createPublicScheduleJob(10); + publicScheduleAdminMockData.createPublicSchedulePrivate(5); + + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("page", String.valueOf(page)); + params.add("size", String.valueOf(size)); + + // when + // multivalue map 을 통해서 값이 넘어옴 + String response = mockMvc.perform( + get("/admin/calendar/public/list/{detailClassification}", tags).header("Authorization", + "Bearer " + accessToken) + .params(params)) + .andDo(print()) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + + // then + PageResponseDto pageResponseDto = objectMapper.readValue( + response, new TypeReference<>() { + }); + List result = pageResponseDto.getContent(); + + if (DetailClassification.valueOf(tags) == DetailClassification.PRIVATE_SCHEDULE) { + assertThat(result.size()).isEqualTo(2); + } else { + assertThat(result.size()).isEqualTo(10); + } + + for (PublicScheduleAdminResDto dto : result) { + System.out.println(dto.toString()); + } + } + } } From b85ba439d0a95e34c6288b17a211627edbc41a30 Mon Sep 17 00:00:00 2001 From: wonie <119565449+wonies@users.noreply.github.com> Date: Mon, 30 Dec 2024 18:08:14 +0900 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=EC=9D=BC=EC=A0=95=20=EC=88=98=EC=A0=95=20API=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20#1053=20(#1085)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: wonie --- .../controller/PublicScheduleController.java | 14 +- .../request/PublicScheduleCreateReqDto.java | 12 +- .../request/PublicScheduleReqDto.java | 11 - .../request/PublicScheduleUpdateReqDto.java | 40 +++ .../response/PublicScheduleResDto.java | 4 - .../response/PublicScheduleUpdateResDto.java | 52 +++ .../service/PublicScheduleService.java | 38 ++- .../PublicScheduleControllerTest.java | 308 ++++++++++++++++-- .../PublicScheduleCreateReqDtoTest.java | 14 +- .../request/PublicScheduleReqDtoTest.java | 6 - .../PublicScheduleUpdateReqDtoTest.java | 41 +++ .../PublicScheduleUpdateResDtoTest.java | 56 ++++ .../java/gg/data/calendar/PublicSchedule.java | 17 + .../java/gg/utils/exception/ErrorCode.java | 2 +- 14 files changed, 553 insertions(+), 62 deletions(-) delete mode 100644 gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDto.java delete mode 100644 gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDto.java delete mode 100644 gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDtoTest.java create mode 100644 gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDtoTest.java create mode 100644 gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDtoTest.java diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java index 53f0d56db..76e50cc14 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleController.java @@ -1,11 +1,12 @@ package gg.calendar.api.user.schedule.publicschedule.controller; - import javax.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -13,7 +14,10 @@ import gg.auth.UserDto; import gg.auth.argumentresolver.Login; import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleCreateReqDto; +import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleUpdateReqDto; +import gg.calendar.api.user.schedule.publicschedule.controller.response.PublicScheduleUpdateResDto; import gg.calendar.api.user.schedule.publicschedule.service.PublicScheduleService; +import gg.data.calendar.PublicSchedule; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; @@ -29,5 +33,13 @@ public ResponseEntity publicScheduleCreate(@RequestBody @Valid PublicSched publicScheduleService.createPublicSchedule(req, userDto.getId()); return ResponseEntity.status(HttpStatus.CREATED).build(); } + + @PutMapping("/{id}") + public ResponseEntity publicScheduleUpdate(@PathVariable Long id, + @RequestBody @Valid PublicScheduleUpdateReqDto req, + @Login @Parameter(hidden = true) UserDto userDto) { + PublicSchedule updateSchedule = publicScheduleService.updatePublicSchedule(id, req, userDto.getId()); + return ResponseEntity.ok(PublicScheduleUpdateResDto.toDto(updateSchedule)); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDto.java index 8bfc29712..c1e36d133 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDto.java @@ -2,7 +2,9 @@ import java.time.LocalDateTime; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; @@ -26,12 +28,18 @@ public class PublicScheduleCreateReqDto { private EventTag eventTag; private JobTag jobTag; private TechTag techTag; - @NotNull + @NotBlank private String author; - @NotNull + + @NotBlank + @Size(max = 50, message = "제목은 50자이하로 입력해주세요.") private String title; + + @Size(max = 2000, message = "내용은 2000자이하로 입력해주세요.") private String content; + private String link; + @NotNull private LocalDateTime startTime; @NotNull diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDto.java deleted file mode 100644 index 71ace1a3a..000000000 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package gg.calendar.api.user.schedule.publicschedule.controller.request; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class PublicScheduleReqDto { - -} diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDto.java index 3feaf7364..be2919f98 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDto.java @@ -1,11 +1,51 @@ package gg.calendar.api.user.schedule.publicschedule.controller.request; +import java.time.LocalDateTime; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.springframework.format.annotation.DateTimeFormat; + +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter +@Builder +@AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PublicScheduleUpdateReqDto { + @NotNull + private DetailClassification classification; + private EventTag eventTag; + private JobTag jobTag; + private TechTag techTag; + @NotBlank + private String author; + + @NotBlank + @Size(max = 50, message = "제목은 50자이하로 입력해주세요.") + private String title; + + @Size(max = 2000, message = "내용은 2000자이하로 입력해주세요.") + private String content; + private String link; + + @NotNull + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private LocalDateTime startTime; + @NotNull + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private LocalDateTime endTime; + private ScheduleStatus status; } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDto.java deleted file mode 100644 index d8d501aa7..000000000 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleResDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package gg.calendar.api.user.schedule.publicschedule.controller.response; - -public class PublicScheduleResDto { -} diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDto.java index 2abb6d988..6c285fcea 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDto.java @@ -1,11 +1,63 @@ package gg.calendar.api.user.schedule.publicschedule.controller.response; +import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.TechTag; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PublicScheduleUpdateResDto { + private Long id; + private DetailClassification classification; + private EventTag eventTag; + private JobTag jobTag; + private TechTag techTag; + private String author; + private String title; + private String content; + private String link; + private String startTime; + private String endTime; + private String status; + @Builder + private PublicScheduleUpdateResDto(Long id, DetailClassification classification, EventTag eventTag, JobTag jobTag, + TechTag techTag, String author, String title, String content, String link, String startTime, String endTime, + String status) { + this.id = id; + this.classification = classification; + this.eventTag = eventTag; + this.jobTag = jobTag; + this.techTag = techTag; + this.author = author; + this.title = title; + this.content = content; + this.link = link; + this.startTime = startTime; + this.endTime = endTime; + this.status = status; + } + + public static PublicScheduleUpdateResDto toDto(PublicSchedule publicSchedule) { + return PublicScheduleUpdateResDto.builder() + .id(publicSchedule.getId()) + .classification(publicSchedule.getClassification()) + .eventTag(publicSchedule.getEventTag()) + .jobTag(publicSchedule.getJobTag()) + .techTag(publicSchedule.getTechTag()) + .author(publicSchedule.getAuthor()) + .title(publicSchedule.getTitle()) + .content(publicSchedule.getContent()) + .link(publicSchedule.getLink()) + .startTime(publicSchedule.getStartTime().toString()) + .endTime(publicSchedule.getEndTime().toString()) + .status(publicSchedule.getStatus().name()) + .build(); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java index 8727777a7..62554d935 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/publicschedule/service/PublicScheduleService.java @@ -1,15 +1,20 @@ package gg.calendar.api.user.schedule.publicschedule.service; +import java.time.LocalDateTime; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleCreateReqDto; +import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleUpdateReqDto; import gg.data.calendar.PublicSchedule; import gg.data.user.User; import gg.repo.calendar.PublicScheduleRepository; import gg.repo.user.UserRepository; import gg.utils.exception.ErrorCode; -import gg.utils.exception.custom.CustomRuntimeException; +import gg.utils.exception.custom.ForbiddenException; +import gg.utils.exception.custom.InvalidParameterException; +import gg.utils.exception.custom.NotExistException; import lombok.RequiredArgsConstructor; @Service @@ -23,12 +28,35 @@ public class PublicScheduleService { public void createPublicSchedule(PublicScheduleCreateReqDto req, Long userId) { User user = userRepository.getById(userId); if (!user.getIntraId().equals(req.getAuthor())) { - throw new CustomRuntimeException(ErrorCode.CALENDAR_AUTHOR_NOT_MATCH); - } - if (req.getStartTime().isAfter(req.getEndTime())) { - throw new CustomRuntimeException(ErrorCode.CALENDAR_BEFORE_DATE); + throw new ForbiddenException(ErrorCode.CALENDAR_AUTHOR_NOT_MATCH); } + validateTimeRange(req.getStartTime(), req.getEndTime()); PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), req); publicScheduleRepository.save(publicSchedule); } + + @Transactional + public PublicSchedule updatePublicSchedule(Long scheduleId, PublicScheduleUpdateReqDto req, Long userId) { + User user = userRepository.getById(userId); + PublicSchedule existingSchedule = publicScheduleRepository.findById(scheduleId) + .orElseThrow(() -> new NotExistException(ErrorCode.PUBLIC_SCHEDULE_NOT_FOUND)); + checkAuthor(existingSchedule.getAuthor(), user); + checkAuthor(req.getAuthor(), user); + validateTimeRange(req.getStartTime(), req.getEndTime()); + existingSchedule.update(req.getClassification(), req.getEventTag(), req.getJobTag(), req.getTechTag(), + req.getTitle(), req.getContent(), req.getLink(), req.getStartTime(), req.getEndTime(), req.getStatus()); + return existingSchedule; + } + + private static void checkAuthor(String author, User user) { + if (!user.getIntraId().equals(author)) { + throw new ForbiddenException(ErrorCode.CALENDAR_AUTHOR_NOT_MATCH); + } + } + + public void validateTimeRange(LocalDateTime startTime, LocalDateTime endTime) { + if (endTime.isBefore(startTime)) { + throw new InvalidParameterException(ErrorCode.CALENDAR_BEFORE_DATE); + } + } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java index 2b895096b..fdc292262 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/PublicScheduleControllerTest.java @@ -24,9 +24,11 @@ import gg.calendar.api.user.schedule.publicschedule.PublicScheduleMockData; import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleCreateReqDto; +import gg.calendar.api.user.schedule.publicschedule.controller.request.PublicScheduleUpdateReqDto; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.ScheduleStatus; import gg.data.user.User; import gg.repo.calendar.PublicScheduleRepository; import gg.repo.user.UserRepository; @@ -69,12 +71,12 @@ void setUp() { } @Nested - @DisplayName("공개일정생성") + @DisplayName("공개일정:생성") class CreatePublicSchedule { @Test - @DisplayName("공개일정 생성 성공") + @DisplayName("공개일정생성성공") void createPublicScheduleSuccess() throws Exception { - // given : reqDto를 생성 + // given PublicScheduleCreateReqDto publicScheduleDto = PublicScheduleCreateReqDto.builder() .classification(DetailClassification.EVENT) .author(user.getIntraId()) @@ -85,21 +87,21 @@ void createPublicScheduleSuccess() throws Exception { .endTime(LocalDateTime.now().plusDays(1)) .build(); - // when : reqDto로 요청 + // when log.info("After mock data creation: {}", publicScheduleRepository.findByAuthor(user.getIntraId()).size()); mockMvc.perform(post("/calendar/public").header("Authorization", "Bearer " + accssToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleDto))).andExpect(status().isCreated()); - // then : 생성된 일정이 반환 + // then List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); assertThat(schedules).hasSize(1); assertThat(schedules.get(0).getTitle()).isEqualTo(publicScheduleDto.getTitle()); } @Test - @DisplayName("공개일정-작성자가 다를 때") - void createPublicScheduleFail() throws Exception { - // given : reqDto를 생성 + @DisplayName("공개일정생성실패-작성자가 다를 때") + void createPublicScheduleFailNotMatchAuthor() throws Exception { + // given PublicScheduleCreateReqDto publicScheduleDto = PublicScheduleCreateReqDto.builder() .classification(DetailClassification.EVENT) .author("another") @@ -109,24 +111,21 @@ void createPublicScheduleFail() throws Exception { .startTime(LocalDateTime.now()) .endTime(LocalDateTime.now().plusDays(1)) .build(); - // when : reqDto로 요청 + // when mockMvc.perform(post("/calendar/public").header("Authorization", "Bearer " + accssToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleDto))) - .andExpect(status().isBadRequest()) - .andExpect(result -> { - status().isBadRequest(); // 처음에 errorcode로 잡았는데, status로 잡음 - }) + .andExpect(status().isForbidden()) .andDo(print()); - // then : 예외가 발생 + // then List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); assertThat(schedules).isEmpty(); } @Test - @DisplayName("공개일정- 기간이 잘못되었을 때/ 종료닐짜가 시작날짜보다 빠를때") - void createPublicScheduleFail2() throws Exception { - // given : reqDto를 생성 + @DisplayName("공개일정생성실패- 기간이 잘못되었을 때(종료닐짜가 시작날짜보다 빠를때)") + void createPublicScheduleFailFalutPeriod() throws Exception { + // given PublicScheduleCreateReqDto publicScheduleDto = PublicScheduleCreateReqDto.builder() .classification(DetailClassification.EVENT) .eventTag(EventTag.ETC) @@ -137,18 +136,287 @@ void createPublicScheduleFail2() throws Exception { .startTime(LocalDateTime.now()) .endTime(LocalDateTime.now().minusDays(1)) .build(); - // when : reqDto로 요청 + // when mockMvc.perform(post("/calendar/public").header("Authorization", "Bearer " + accssToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleDto))) .andExpect(status().isBadRequest()) .andExpect(result -> { - status().isBadRequest(); // 처음에 errorcode로 잡았는데, status로 잡음 + status().isBadRequest(); }) .andDo(print()); - // then : 예외가 발생 + // then List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); assertThat(schedules).isEmpty(); } } + + @Nested + @DisplayName("공개일정:업데이트") + class UpdatePublicSchedule { + + @Test + @DisplayName("공개일정업데이트성공시") + void updatePublicScheduleSuccess() throws Exception { + // given + PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), + PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Original Title") + .content("Original Content") + .link("http://original.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .build()); + publicScheduleRepository.save(publicSchedule); + + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Updated Title") + .content("Updated Content") + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(2)) + .status(ScheduleStatus.ACTIVATE) + .build(); + + // when + mockMvc.perform( + put("/calendar/public/" + publicSchedule.getId()).header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))).andExpect(status().isOk()); + + // then + List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); + assertThat(schedules).hasSize(1); + assertThat(schedules.get(0).getTitle()).isEqualTo("Updated Title"); + assertThat(schedules.get(0).getContent()).isEqualTo("Updated Content"); + } + + @Test + @DisplayName("공개일정업데이트실패-작성자가 다를 때") + void updatePublicScheduleFailNotMatchAuthor() throws Exception { + // given + PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), + PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Original Title") + .content("Original Content") + .link("http://original.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .build()); + publicScheduleRepository.save(publicSchedule); + + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author("another") + .title("Updated Title") + .content("Updated Content") + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(2)) + .build(); + + // when + mockMvc.perform( + put("/calendar/public/" + publicSchedule.getId()).header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))) + .andExpect(status().isForbidden()) + .andDo(print()); + + // then + List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); + assertThat(schedules).hasSize(1); + assertThat(schedules.get(0).getTitle()).isEqualTo("Original Title"); + assertThat(schedules.get(0).getContent()).isEqualTo("Original Content"); + } + + @Test + @DisplayName("공개일정업데이트실패-기존일정작성자가다를때") + void updatePublicScheduleFailExistingAuthorNotMatch() throws Exception { + PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity("another", + PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .author("another") + .title("Original Title") + .content("Original Content") + .link("http://original.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .build()); + + publicScheduleRepository.save(publicSchedule); + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Updated Title") + .content("Updated Content") + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(2)) + .build(); + mockMvc.perform( + put("/calendar/public/" + publicSchedule.getId()).header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))) + .andExpect(status().isForbidden()) + .andDo(print()); + + List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); + assertThat(schedules).hasSize(0); + } + + @Test + @DisplayName("공개일정업데이트실패-기간이 잘못되었을 때(종료날짜가 시작날짜보다 빠를 때)") + void updatePublicScheduleFailFaultPeriod() throws Exception { + // given + PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), + PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Original Title") + .content("Original Content") + .link("http://original.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .build()); + publicScheduleRepository.save(publicSchedule); + + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Updated Title") + .content("Updated Content") + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().minusDays(1)) + .build(); + + // when + mockMvc.perform( + put("/calendar/public/" + publicSchedule.getId()).header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))) + .andExpect(status().isBadRequest()) + .andExpect(result -> { + status().isBadRequest(); + }) + .andDo(print()); + + // then + List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); + assertThat(schedules).hasSize(1); + assertThat(schedules.get(0).getTitle()).isEqualTo("Original Title"); + assertThat(schedules.get(0).getContent()).isEqualTo("Original Content"); + } + + @Test + @DisplayName("공개일정업데이트실패-없는 일정일 때") + void updatePublicScheduleFailNotExist() throws Exception { + // given + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Updated Title") + .content("Updated Content") + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(2)) + .build(); + + // when + mockMvc.perform(put("/calendar/public/9999").header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))).andExpect(status().isNotFound()).andDo(print()); + + // then + List schedules = publicScheduleRepository.findByAuthor(user.getIntraId()); + assertThat(schedules).hasSize(0); + } + + @Test + @DisplayName("공개일정업데이트실패-제목이 50글자 초과일 때") + void updatePublicScheduleFailTitleTooLong() throws Exception { + // given + PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), + PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Original Title") + .content("Original Content") + .link("http://original.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .build()); + publicScheduleRepository.save(publicSchedule); + + String longTitle = "publicScheduleTest".repeat(20); + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title(longTitle) + .content("Updated Content") + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(2)) + .build(); + + // when + mockMvc.perform( + put("/calendar/public/" + publicSchedule.getId()).header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))) + .andExpect(status().isBadRequest()) + .andDo(print()); + + //then + PublicSchedule updatedSchedule = publicScheduleRepository.findById(publicSchedule.getId()).get(); + assertThat(updatedSchedule.getTitle()).isEqualTo("Original Title"); + } + + @Test + @DisplayName("공개일정업데이트실패-내용이 2000글자 초과일 때") + void updatePublicScheduleFailContentTooLong() throws Exception { + // given + PublicSchedule publicSchedule = PublicScheduleCreateReqDto.toEntity(user.getIntraId(), + PublicScheduleCreateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Original Title") + .content("Original Content") + .link("http://original.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .build()); + publicScheduleRepository.save(publicSchedule); + + String longContent = "publicScheduleTest".repeat(200); + PublicScheduleUpdateReqDto updateDto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.EVENT) + .author(user.getIntraId()) + .title("Updated Title") + .content(longContent) + .link("http://updated.com") + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(2)) + .build(); + + // when + mockMvc.perform( + put("/calendar/public/" + publicSchedule.getId()).header("Authorization", "Bearer " + accssToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateDto))) + .andExpect(status().isBadRequest()) + .andDo(print()); + + //then + PublicSchedule updatedSchedule = publicScheduleRepository.findById(publicSchedule.getId()).get(); + assertThat(updatedSchedule.getContent()).isEqualTo("Original Content"); + } + } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDtoTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDtoTest.java index 6937a8ce5..f4fa96d2c 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDtoTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleCreateReqDtoTest.java @@ -13,8 +13,6 @@ import gg.data.calendar.type.EventTag; import gg.utils.annotation.UnitTest; - - /*이 테스트는 reqDto의 of()메서드가 정상적으로 엔티티로 변환되는 지 검증하는 테스트*/ @UnitTest @@ -22,7 +20,6 @@ public class PublicScheduleCreateReqDtoTest { @Test @DisplayName("PublicScheduleCreateReqDto 생성 성공") void createPublicScheduleSuccess() { - //given : userDto와 reqDto를 생성 UserDto user = UserDto.builder().intraId("intraId").build(); PublicScheduleCreateReqDto dto = PublicScheduleCreateReqDto.builder() @@ -32,28 +29,21 @@ void createPublicScheduleSuccess() { .author(user.getIntraId()) .content("Test Content") .link("http://test.com") - // .sharedCount(0) => sharedCount는 0으로 고정되기에 dto에서 제외 .startTime(LocalDateTime.now().plusDays(1)) .endTime(LocalDateTime.now().plusDays(2)) .build(); - - // when : dto를 엔티티로 변환 PublicSchedule schedule = dto.toEntity(user.getIntraId(), dto); - // then : dto와 엔티티가 같은지 검증 - assertAll( - () -> assertNotNull(schedule), + assertAll(() -> assertNotNull(schedule), () -> assertEquals(dto.getClassification(), schedule.getClassification()), () -> assertEquals(dto.getEventTag(), schedule.getEventTag()), () -> assertEquals(dto.getTitle(), schedule.getTitle()), () -> assertEquals(user.getIntraId(), schedule.getAuthor()), () -> assertEquals(dto.getContent(), schedule.getContent()), () -> assertEquals(dto.getLink(), schedule.getLink()), - // () -> assertEquals(dto.getSharedCount(), schedule.getSharedCount()), () -> assertEquals(dto.getStartTime(), schedule.getStartTime()), - () -> assertEquals(dto.getEndTime(), schedule.getEndTime()) - ); + () -> assertEquals(dto.getEndTime(), schedule.getEndTime())); } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDtoTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDtoTest.java deleted file mode 100644 index 4cd6b7542..000000000 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleReqDtoTest.java +++ /dev/null @@ -1,6 +0,0 @@ -package gg.calendar.api.user.schedule.publicschedule.controller.request; - -import org.junit.jupiter.api.Test; - -public class PublicScheduleReqDtoTest { -} diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDtoTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDtoTest.java new file mode 100644 index 000000000..de817702b --- /dev/null +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/request/PublicScheduleUpdateReqDtoTest.java @@ -0,0 +1,41 @@ +package gg.calendar.api.user.schedule.publicschedule.controller.request; + +import static org.junit.jupiter.api.Assertions.*; + +import java.time.LocalDateTime; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.utils.annotation.UnitTest; + +@UnitTest +public class PublicScheduleUpdateReqDtoTest { + + @Test + @DisplayName("PublicScheduleUpdateReqDto 생성 성공") + void createPublicScheduleSuccess() { + LocalDateTime startTime = LocalDateTime.now().plusDays(1); + LocalDateTime endTime = LocalDateTime.now().plusDays(2); + + PublicScheduleUpdateReqDto dto = PublicScheduleUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .eventTag(EventTag.INSTRUCTION) + .title("Test Schedule") + .author("intraId") + .content("Test Content") + .link("http://test.com") + .startTime(startTime) + .endTime(endTime) + .build(); + + assertAll(() -> assertEquals(DetailClassification.JOB_NOTICE, dto.getClassification()), + () -> assertEquals(EventTag.INSTRUCTION, dto.getEventTag()), + () -> assertEquals("Test Schedule", dto.getTitle()), () -> assertEquals("intraId", dto.getAuthor()), + () -> assertEquals("Test Content", dto.getContent()), () -> assertEquals("http://test.com", dto.getLink()), + () -> assertEquals(startTime, dto.getStartTime()), () -> assertEquals(endTime, dto.getEndTime())); + + } +} diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDtoTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDtoTest.java new file mode 100644 index 000000000..06dbc0ae6 --- /dev/null +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/publicschedule/controller/response/PublicScheduleUpdateResDtoTest.java @@ -0,0 +1,56 @@ +package gg.calendar.api.user.schedule.publicschedule.controller.response; + +import static org.junit.jupiter.api.Assertions.*; + +import java.time.LocalDateTime; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.utils.annotation.UnitTest; + +@UnitTest +public class PublicScheduleUpdateResDtoTest { + + @Test + @DisplayName("PublicSchedule Entity를 ResponseDto로 변환 성공") + void toDto_Success() { + // given + LocalDateTime startTime = LocalDateTime.now().plusDays(1); + LocalDateTime endTime = LocalDateTime.now().plusDays(2); + + PublicSchedule schedule = PublicSchedule.builder() + .classification(DetailClassification.JOB_NOTICE) + .eventTag(EventTag.INSTRUCTION) + .author("testUser") + .title("Test Title") + .content("Test Content") + .link("http://test.com") + .startTime(startTime) + .endTime(endTime) + .status(ScheduleStatus.ACTIVATE) + .build(); + ReflectionTestUtils.setField(schedule, "id", 1L); + // when + PublicScheduleUpdateResDto responseDto = PublicScheduleUpdateResDto.toDto(schedule); + + // then + assertAll( + () -> assertEquals(1L, responseDto.getId()), + () -> assertEquals(DetailClassification.JOB_NOTICE, responseDto.getClassification()), + () -> assertEquals(EventTag.INSTRUCTION, responseDto.getEventTag()), + () -> assertEquals("testUser", responseDto.getAuthor()), + () -> assertEquals("Test Title", responseDto.getTitle()), + () -> assertEquals("Test Content", responseDto.getContent()), + () -> assertEquals("http://test.com", responseDto.getLink()), + () -> assertEquals(startTime.toString(), responseDto.getStartTime()), + () -> assertEquals(endTime.toString(), responseDto.getEndTime()), + () -> assertEquals("ACTIVATE", responseDto.getStatus()) + ); + } +} diff --git a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java index 68e40c944..9f3481c1c 100644 --- a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java +++ b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java @@ -85,4 +85,21 @@ private PublicSchedule(DetailClassification classification, EventTag eventTag, J this.startTime = startTime; this.endTime = endTime; } + + public void update(DetailClassification classification, EventTag eventTag, JobTag jobTag, + TechTag techTag, + String title, String content, String link, LocalDateTime startTime, LocalDateTime endTime, + ScheduleStatus status) { + this.classification = classification; + this.eventTag = eventTag; + this.jobTag = jobTag; + this.techTag = techTag; + this.title = title; + this.content = content; + this.link = link; + this.startTime = startTime; + this.endTime = endTime; + this.status = status; + } } + diff --git a/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java index 8fa62caca..017c51a21 100644 --- a/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java +++ b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java @@ -240,7 +240,7 @@ public enum ErrorCode { CALENDAR_BEFORE_DATE(400, "CA201", "종료 시간이 시작 시간보다 빠를 수 없습니다."), CALENDAR_AFTER_DATE(400, "CA202", "시작 시간이 종료 시간보다 늦을 수 없습니다."), CALENDAR_EQUAL_DATE(400, "CA203", "시작 시간과 종료 시간이 같을 수 없습니다."), - CALENDAR_AUTHOR_NOT_MATCH(400, "CA205", "전제하지 않는 사용자입니다."), + CALENDAR_AUTHOR_NOT_MATCH(403, "CA205", "잘못된 사용자입니다."), PRIVATE_SCHEDULE_NOT_FOUND(404, "CA101", "개인 일정을 찾을 수 없습니다."), PUBLIC_SCHEDULE_NOT_FOUND(404, "CA102", "공유 일정을 찾을 수 없습니다."), SCHEDULE_GROUP_NOT_FOUND(404, "CA103", "스캐줄 그룹을 찾을 수 없습니다."); From 48ec5bb94074c70edb832ddf3ea307f29d6f7ace Mon Sep 17 00:00:00 2001 From: seyeon22222 <92151066+seyeon22222@users.noreply.github.com> Date: Mon, 30 Dec 2024 18:46:30 +0900 Subject: [PATCH 04/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20Admin=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=EC=9D=BC=EC=A0=95=20=EC=88=98=EC=A0=95=20API=20?= =?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20#1059=20(#1086)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PublicScheduleAdminRepository.java | 2 + .../PublicScheduleAdminController.java | 14 +- .../PublicScheduleAdminCreateReqDto.java | 1 + .../PublicScheduleAdminUpdateReqDto.java | 60 +++++ .../PublicScheduleAdminUpdateResDto.java | 72 +++++ .../service/PublicScheduleAdminService.java | 30 ++- .../admin/PublicScheduleAdminMockData.java | 1 + .../PublicScheduleAdminControllerTest.java | 248 ++++++++++++++++++ .../java/gg/data/calendar/PublicSchedule.java | 4 +- 9 files changed, 425 insertions(+), 7 deletions(-) diff --git a/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java b/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java index fa7932dc1..bc3d85838 100644 --- a/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java +++ b/gg-admin-repo/src/main/java/gg/admin/repo/calendar/PublicScheduleAdminRepository.java @@ -16,4 +16,6 @@ public interface PublicScheduleAdminRepository extends JpaRepository findByAuthor(String author); Page findAllByClassification(DetailClassification detailClassification, Pageable pageable); + + List findAll(); } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java index 1c48773e0..ecee0bed1 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java @@ -8,12 +8,15 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminUpdateReqDto; import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminUpdateResDto; import gg.calendar.api.admin.schedule.publicschedule.service.PublicScheduleAdminService; import gg.data.calendar.type.DetailClassification; import gg.utils.dto.PageRequestDto; @@ -36,7 +39,7 @@ public ResponseEntity publicScheduleCreate( @GetMapping("/list/{detailClassification}") public ResponseEntity> publicScheduleAdminClassificationList( - @PathVariable DetailClassification detailClassification, @ModelAttribute PageRequestDto pageRequestDto) { + @PathVariable DetailClassification detailClassification, @ModelAttribute @Valid PageRequestDto pageRequestDto) { int page = pageRequestDto.getPage(); int size = pageRequestDto.getSize(); @@ -45,4 +48,13 @@ public ResponseEntity> publicSchedule return ResponseEntity.ok(pageResponseDto); } + + @PutMapping("/{id}") + public ResponseEntity publicScheduleUpdate( + @RequestBody @Valid PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto, + @PathVariable Long id) { + PublicScheduleAdminUpdateResDto publicScheduleAdminUpdateRes = publicScheduleAdminService.updatePublicSchedule( + publicScheduleAdminUpdateReqDto, id); + return ResponseEntity.ok(publicScheduleAdminUpdateRes); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminCreateReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminCreateReqDto.java index 1ecdc063c..4a3575f82 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminCreateReqDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminCreateReqDto.java @@ -40,6 +40,7 @@ public class PublicScheduleAdminCreateReqDto { private String link; + @NotNull private ScheduleStatus status; @NotNull diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminUpdateReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminUpdateReqDto.java index 1e443dbb6..4ba2e29ae 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminUpdateReqDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/request/PublicScheduleAdminUpdateReqDto.java @@ -1,6 +1,20 @@ package gg.calendar.api.admin.schedule.publicschedule.controller.request; +import java.time.LocalDateTime; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.springframework.format.annotation.DateTimeFormat; + +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -8,4 +22,50 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PublicScheduleAdminUpdateReqDto { + @NotNull + private DetailClassification classification; + + private EventTag eventTag; + + private JobTag jobTag; + + private TechTag techTag; + + @NotBlank + @Size(max = 50, message = "제목은 50자이하로 입력해주세요.") + private String title; + + @Size(max = 2000, message = "내용은 2000자이하로 입력해주세요.") + private String content; + + private String link; + + @NotNull + private ScheduleStatus status; + + @NotNull + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private LocalDateTime startTime; + + @NotNull + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private LocalDateTime endTime; + + @Builder + private PublicScheduleAdminUpdateReqDto(DetailClassification classification, EventTag eventTag, JobTag jobTag, + TechTag techTag, String title, String content, String link, ScheduleStatus status, LocalDateTime startTime, + LocalDateTime endTime) { + + this.classification = classification; + this.eventTag = eventTag; + this.jobTag = jobTag; + this.techTag = techTag; + this.title = title; + this.content = content; + this.link = link; + this.status = status; + this.startTime = startTime; + this.endTime = endTime; + + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminUpdateResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminUpdateResDto.java index 19d69ee2c..0182c0f83 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminUpdateResDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminUpdateResDto.java @@ -1,6 +1,14 @@ package gg.calendar.api.admin.schedule.publicschedule.controller.response; +import java.time.LocalDateTime; + +import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -8,4 +16,68 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PublicScheduleAdminUpdateResDto { + private Long id; + + private String classification; + + private EventTag eventTag; + + private JobTag jobTag; + + private TechTag techTag; + + private String author; + + private String title; + + private String content; + + private String link; + + private Integer sharedCount; + + private ScheduleStatus status; + + private LocalDateTime startTime; + + private LocalDateTime endTime; + + @Builder + private PublicScheduleAdminUpdateResDto(Long id, String classification, EventTag eventTag, JobTag jobTag, + TechTag techTag, + String author, String title, String content, String link, Integer sharedCount, ScheduleStatus status, + LocalDateTime startTime, LocalDateTime endTime) { + this.id = id; + this.classification = classification; + this.eventTag = eventTag; + this.jobTag = jobTag; + this.techTag = techTag; + this.author = author; + this.title = title; + this.content = content; + this.link = link; + this.sharedCount = sharedCount; + this.status = status; + this.startTime = startTime; + this.endTime = endTime; + + } + + public static PublicScheduleAdminUpdateResDto toDto(PublicSchedule publicSchedule) { + return PublicScheduleAdminUpdateResDto.builder() + .id(publicSchedule.getId()) + .classification(publicSchedule.getClassification().name()) + .eventTag(publicSchedule.getEventTag()) + .jobTag(publicSchedule.getJobTag()) + .techTag(publicSchedule.getTechTag()) + .author(publicSchedule.getAuthor()) + .title(publicSchedule.getTitle()) + .content(publicSchedule.getContent()) + .link(publicSchedule.getLink()) + .sharedCount(publicSchedule.getSharedCount()) + .status(publicSchedule.getStatus()) + .startTime(publicSchedule.getStartTime()) + .endTime(publicSchedule.getEndTime()) + .build(); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java index 12a29d2bc..32ab751a0 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java @@ -13,12 +13,15 @@ import gg.admin.repo.calendar.PublicScheduleAdminRepository; import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminUpdateReqDto; import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminUpdateResDto; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; import gg.utils.dto.PageResponseDto; import gg.utils.exception.ErrorCode; -import gg.utils.exception.custom.CustomRuntimeException; +import gg.utils.exception.custom.InvalidParameterException; +import gg.utils.exception.custom.NotExistException; import lombok.RequiredArgsConstructor; @Service @@ -38,8 +41,8 @@ public void createPublicSchedule(PublicScheduleAdminCreateReqDto publicScheduleA publicScheduleAdminRepository.save(publicSchedule); } - public PageResponseDto findAllByClassification( - DetailClassification detailClassification, int page, int size) { + public PageResponseDto findAllByClassification(DetailClassification detailClassification, + int page, int size) { Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Order.asc("status"), Sort.Order.asc("startTime"))); @@ -53,9 +56,28 @@ public PageResponseDto findAllByClassification( return PageResponseDto.of(publicSchedules.getTotalElements(), publicScheduleList); } + @Transactional + public PublicScheduleAdminUpdateResDto updatePublicSchedule( + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto, Long id) { + dateTimeErrorCheck(publicScheduleAdminUpdateReqDto.getStartTime(), + publicScheduleAdminUpdateReqDto.getEndTime()); + + PublicSchedule publicSchedule = publicScheduleAdminRepository.findById(id) + .orElseThrow(() -> new NotExistException(ErrorCode.PUBLIC_SCHEDULE_NOT_FOUND)); + + publicSchedule.update(publicScheduleAdminUpdateReqDto.getClassification(), + publicScheduleAdminUpdateReqDto.getEventTag(), publicScheduleAdminUpdateReqDto.getJobTag(), + publicScheduleAdminUpdateReqDto.getTechTag(), publicScheduleAdminUpdateReqDto.getTitle(), + publicScheduleAdminUpdateReqDto.getContent(), publicScheduleAdminUpdateReqDto.getLink(), + publicScheduleAdminUpdateReqDto.getStartTime(), publicScheduleAdminUpdateReqDto.getEndTime(), + publicScheduleAdminUpdateReqDto.getStatus()); + + return PublicScheduleAdminUpdateResDto.toDto(publicSchedule); + } + private void dateTimeErrorCheck(LocalDateTime startTime, LocalDateTime endTime) { if (startTime.isAfter(endTime)) { - throw new CustomRuntimeException(ErrorCode.CALENDAR_BEFORE_DATE); + throw new InvalidParameterException(ErrorCode.CALENDAR_BEFORE_DATE); } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java index ba252e6a1..dd3128148 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java @@ -29,6 +29,7 @@ public PublicSchedule createPublicSchedule() { .title("취업설명회") .content("취업설명회입니다.") .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) .startTime(LocalDateTime.now()) .endTime(LocalDateTime.now().plusDays(10)) .build(); diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java index 0bda1dbd5..d2565029f 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java @@ -33,13 +33,16 @@ import gg.admin.repo.calendar.PublicScheduleAdminRepository; import gg.calendar.api.admin.PublicScheduleAdminMockData; import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminCreateReqDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.request.PublicScheduleAdminUpdateReqDto; import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; +import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminUpdateResDto; import gg.calendar.api.admin.schedule.publicschedule.service.PublicScheduleAdminService; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; import gg.data.calendar.type.EventTag; import gg.data.calendar.type.JobTag; import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; import gg.data.user.User; import gg.utils.TestDataUtils; import gg.utils.annotation.IntegrationTest; @@ -231,4 +234,249 @@ void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, } } } + + @Nested + @DisplayName("Admin PublicSchedule 수정 테스트") + class UpdatePublicScheduleAdminTest { + + @Test + @DisplayName("Admin PublicSchedule 수정 테스트 - 성공") + void updatePublicScheduleAdminTestSuccess() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto = PublicScheduleAdminUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.SHORTS_INTERN) + .techTag(TechTag.BACK_END) + .title("Job Notice") + .content("Job Notice") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(1)) + .endTime(LocalDateTime.now().plusDays(15)) + .build(); + + // when + String response = mockMvc.perform( + put("/admin/calendar/public/{id}", publicSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + PublicScheduleAdminUpdateResDto result = objectMapper.readValue(response, + PublicScheduleAdminUpdateResDto.class); + + List schedules = publicScheduleAdminRepository.findAll(); + + // then + assertThat(schedules.size()).isEqualTo(1); + assertThat(result.getClassification()).isEqualTo( + publicScheduleAdminUpdateReqDto.getClassification().name()); + assertThat(result.getJobTag()).isEqualTo(publicScheduleAdminUpdateReqDto.getJobTag()); + assertThat(result.getTechTag()).isEqualTo(publicScheduleAdminUpdateReqDto.getTechTag()); + assertThat(result.getTitle()).isEqualTo(publicScheduleAdminUpdateReqDto.getTitle()); + assertThat(result.getContent()).isEqualTo(publicScheduleAdminUpdateReqDto.getContent()); + assertThat(result.getLink()).isEqualTo(publicScheduleAdminUpdateReqDto.getLink()); + assertThat(result.getStartTime()).isEqualTo(publicScheduleAdminUpdateReqDto.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicScheduleAdminUpdateReqDto.getEndTime()); + } + + @Test + @DisplayName("Admin PublicSchedule 수정 테스트 - 실패 : 종료날짜가 시작날짜보다 빠른경우") + void updatePublicScheduleAdminTestFailEndBeforeStart() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto = PublicScheduleAdminUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.SHORTS_INTERN) + .techTag(TechTag.BACK_END) + .title("Job Notice") + .content("Job Notice") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(15)) + .endTime(LocalDateTime.now().plusDays(1)) + .build(); + + // when + String response = mockMvc.perform( + put("/admin/calendar/public/{id}", publicSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(); + + List schedules = publicScheduleAdminRepository.findAll(); + PublicSchedule result = schedules.get(0); + assertThat(schedules.size()).isEqualTo(1); + assertThat(result.getClassification()).isEqualTo(publicSchedule.getClassification()); + assertThat(result.getEventTag()).isEqualTo(publicSchedule.getEventTag()); + assertThat(result.getTitle()).isEqualTo(publicSchedule.getTitle()); + assertThat(result.getContent()).isEqualTo(publicSchedule.getContent()); + assertThat(result.getLink()).isEqualTo(publicSchedule.getLink()); + assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); + } + + @Test + @DisplayName("Admin PublicSchedule 수정 테스트 - 실패 : 제목이 50자가 넘는 경우") + void updatePublicScheduleAdminTestFailTitleMax() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto = PublicScheduleAdminUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.SHORTS_INTERN) + .techTag(TechTag.BACK_END) + .title("Job Notice".repeat(10)) + .content("Job Notice") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(1)) + .endTime(LocalDateTime.now().plusDays(15)) + .build(); + + // when + String response = mockMvc.perform( + put("/admin/calendar/public/{id}", publicSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(); + + List schedules = publicScheduleAdminRepository.findAll(); + PublicSchedule result = schedules.get(0); + assertThat(schedules.size()).isEqualTo(1); + assertThat(result.getClassification()).isEqualTo(publicSchedule.getClassification()); + assertThat(result.getEventTag()).isEqualTo(publicSchedule.getEventTag()); + assertThat(result.getTitle()).isEqualTo(publicSchedule.getTitle()); + assertThat(result.getContent()).isEqualTo(publicSchedule.getContent()); + assertThat(result.getLink()).isEqualTo(publicSchedule.getLink()); + assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); + } + + @Test + @DisplayName("Admin PublicSchedule 수정 테스트 - 실패 : 내용이 2000자가 넘는 경우") + void updatePublicScheduleAdminTestFailContentMax() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto = PublicScheduleAdminUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.SHORTS_INTERN) + .techTag(TechTag.BACK_END) + .title("Job Notice") + .content("Job Notice".repeat(500)) + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(1)) + .endTime(LocalDateTime.now().plusDays(15)) + .build(); + + // when + String response = mockMvc.perform( + put("/admin/calendar/public/{id}", publicSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(); + + List schedules = publicScheduleAdminRepository.findAll(); + PublicSchedule result = schedules.get(0); + assertThat(schedules.size()).isEqualTo(1); + assertThat(result.getClassification()).isEqualTo(publicSchedule.getClassification()); + assertThat(result.getEventTag()).isEqualTo(publicSchedule.getEventTag()); + assertThat(result.getTitle()).isEqualTo(publicSchedule.getTitle()); + assertThat(result.getContent()).isEqualTo(publicSchedule.getContent()); + assertThat(result.getLink()).isEqualTo(publicSchedule.getLink()); + assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); + } + + @Test + @DisplayName("Admin PublicSchedule 수정 테스트 - 실패 : 없는 일정을 수정하는 경우") + void updatePublicScheduleAdminTestFailNotExist() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto = PublicScheduleAdminUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.SHORTS_INTERN) + .techTag(TechTag.BACK_END) + .title("Job Notice") + .content("Job Notice") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(1)) + .endTime(LocalDateTime.now().plusDays(15)) + .build(); + + // when + String response = mockMvc.perform( + put("/admin/calendar/public/100") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) + .andDo(print()) + .andExpect(status().isNotFound()) + .andReturn().getResponse().getContentAsString(); + + List schedules = publicScheduleAdminRepository.findAll(); + PublicSchedule result = schedules.get(0); + assertThat(schedules.size()).isEqualTo(1); + assertThat(result.getClassification()).isEqualTo(publicSchedule.getClassification()); + assertThat(result.getEventTag()).isEqualTo(publicSchedule.getEventTag()); + assertThat(result.getTitle()).isEqualTo(publicSchedule.getTitle()); + assertThat(result.getContent()).isEqualTo(publicSchedule.getContent()); + assertThat(result.getLink()).isEqualTo(publicSchedule.getLink()); + assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); + } + + @Test + @DisplayName("Admin PublicSchedule 수정 테스트 - 실패 : 잘못된 id가 들어왔을 경우") + void updatePublicScheduleAdminTestFailBadArgument() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto = PublicScheduleAdminUpdateReqDto.builder() + .classification(DetailClassification.JOB_NOTICE) + .jobTag(JobTag.SHORTS_INTERN) + .techTag(TechTag.BACK_END) + .title("Job Notice") + .content("Job Notice") + .link("https://gg.42seoul.kr") + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(1)) + .endTime(LocalDateTime.now().plusDays(15)) + .build(); + + // when + String response = mockMvc.perform( + put("/admin/calendar/public/asdasdasd") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andReturn().getResponse().getContentAsString(); + + List schedules = publicScheduleAdminRepository.findAll(); + PublicSchedule result = schedules.get(0); + assertThat(schedules.size()).isEqualTo(1); + assertThat(result.getClassification()).isEqualTo(publicSchedule.getClassification()); + assertThat(result.getEventTag()).isEqualTo(publicSchedule.getEventTag()); + assertThat(result.getTitle()).isEqualTo(publicSchedule.getTitle()); + assertThat(result.getContent()).isEqualTo(publicSchedule.getContent()); + assertThat(result.getLink()).isEqualTo(publicSchedule.getLink()); + assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); + } + } } diff --git a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java index 9f3481c1c..ee8c8db59 100644 --- a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java +++ b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java @@ -86,9 +86,9 @@ private PublicSchedule(DetailClassification classification, EventTag eventTag, J this.endTime = endTime; } + public void update(DetailClassification classification, EventTag eventTag, JobTag jobTag, - TechTag techTag, - String title, String content, String link, LocalDateTime startTime, LocalDateTime endTime, + TechTag techTag, String title, String content, String link, LocalDateTime startTime, LocalDateTime endTime, ScheduleStatus status) { this.classification = classification; this.eventTag = eventTag; From c35888442b01e4f1c7c644f50f354ac3af1dc14e Mon Sep 17 00:00:00 2001 From: taehyeon3 <117972735+taehyeon3@users.noreply.github.com> Date: Mon, 30 Dec 2024 19:09:09 +0900 Subject: [PATCH 05/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20=EA=B0=9C?= =?UTF-8?q?=EC=9D=B8=EC=9D=BC=EC=A0=95=20=EC=88=98=EC=A0=95=20api=20#1057?= =?UTF-8?q?=20(#1087)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: taehyeon --- .../controller/PrivateScheduleController.java | 14 ++ .../request/PrivateScheduleCreateReqDto.java | 15 +- .../request/PrivateScheduleUpdateReqDto.java | 56 +++++++ .../response/PrivateScheduleUpdateResDto.java | 74 +++++++++ .../service/PrivateScheduleService.java | 28 ++++ .../PrivateScheduleMockData.java | 13 +- .../PrivateScheduleControllerTest.java | 151 +++++++++++++++++- .../gg/data/calendar/PrivateSchedule.java | 14 ++ .../java/gg/data/calendar/PublicSchedule.java | 1 - .../java/gg/utils/dto/PageResponseDto.java | 1 - 10 files changed, 347 insertions(+), 20 deletions(-) diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleController.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleController.java index 4da3bd1a8..d09da761b 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleController.java @@ -4,7 +4,9 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -12,6 +14,8 @@ import gg.auth.UserDto; import gg.auth.argumentresolver.Login; import gg.calendar.api.user.schedule.privateschedule.controller.request.PrivateScheduleCreateReqDto; +import gg.calendar.api.user.schedule.privateschedule.controller.request.PrivateScheduleUpdateReqDto; +import gg.calendar.api.user.schedule.privateschedule.controller.response.PrivateScheduleUpdateResDto; import gg.calendar.api.user.schedule.privateschedule.service.PrivateScheduleService; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; @@ -28,4 +32,14 @@ public ResponseEntity privateScheduleCreate(@Login @Parameter(hidden = tru privateScheduleService.createPrivateSchedule(userDto, privateScheduleCreateReqDto); return ResponseEntity.status(HttpStatus.CREATED).build(); } + + @PutMapping("/{id}") + public ResponseEntity privateScheduleUpdate( + @Login @Parameter(hidden = true) UserDto userDto, + @Valid @RequestBody PrivateScheduleUpdateReqDto privateScheduleUpdateReqDto, + @PathVariable Long id) { + PrivateScheduleUpdateResDto privateScheduleUpdateResDto = privateScheduleService.updatePrivateSchedule(userDto, + privateScheduleUpdateReqDto, id); + return ResponseEntity.status(HttpStatus.OK).body(privateScheduleUpdateResDto); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleCreateReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleCreateReqDto.java index 4d58624d8..e655c59a6 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleCreateReqDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleCreateReqDto.java @@ -21,9 +21,6 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PrivateScheduleCreateReqDto { - @NotNull - private DetailClassification classification; - private EventTag eventTag; private JobTag jobTag; @@ -39,6 +36,7 @@ public class PrivateScheduleCreateReqDto { private String link; + @NotNull private ScheduleStatus status; @NotNull @@ -54,11 +52,9 @@ public class PrivateScheduleCreateReqDto { private Long groupId; @Builder - private PrivateScheduleCreateReqDto(DetailClassification classification, EventTag eventTag, JobTag jobTag, - TechTag techTag, String title, String content, String link, - LocalDateTime startTime, LocalDateTime endTime, boolean alarm, Long groupId, + private PrivateScheduleCreateReqDto(EventTag eventTag, JobTag jobTag, TechTag techTag, String title, String content, + String link, LocalDateTime startTime, LocalDateTime endTime, boolean alarm, Long groupId, ScheduleStatus status) { - this.classification = classification; this.eventTag = eventTag; this.jobTag = jobTag; this.techTag = techTag; @@ -74,11 +70,12 @@ private PrivateScheduleCreateReqDto(DetailClassification classification, EventTa public static PublicSchedule toEntity(String intraId, PrivateScheduleCreateReqDto privateScheduleCreateReqDto) { return PublicSchedule.builder() - .classification(privateScheduleCreateReqDto.classification) + .classification(DetailClassification.PRIVATE_SCHEDULE) .eventTag(privateScheduleCreateReqDto.eventTag) .jobTag(privateScheduleCreateReqDto.jobTag) .techTag(privateScheduleCreateReqDto.techTag) - .author(intraId).title(privateScheduleCreateReqDto.title) + .author(intraId) + .title(privateScheduleCreateReqDto.title) .content(privateScheduleCreateReqDto.content) .link(privateScheduleCreateReqDto.link) .startTime(privateScheduleCreateReqDto.startTime) diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleUpdateReqDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleUpdateReqDto.java index 48d9adf22..fb0622e95 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleUpdateReqDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/request/PrivateScheduleUpdateReqDto.java @@ -1,10 +1,66 @@ package gg.calendar.api.user.schedule.privateschedule.controller.request; +import java.time.LocalDateTime; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor public class PrivateScheduleUpdateReqDto { + private EventTag eventTag; + + private JobTag jobTag; + + private TechTag techTag; + + @NotBlank + @Size(max = 50) + private String title; + + @Size(max = 2000) + private String content; + + private String link; + + @NotNull + private ScheduleStatus status; + + @NotNull + private LocalDateTime startTime; + + @NotNull + private LocalDateTime endTime; + + @NotNull + private boolean alarm; + + @NotNull + private Long groupId; + @Builder + public PrivateScheduleUpdateReqDto(EventTag eventTag, JobTag jobTag, TechTag techTag, String title, String content, + String link, ScheduleStatus status, LocalDateTime startTime, LocalDateTime endTime, boolean alarm, + Long groupId) { + this.eventTag = eventTag; + this.jobTag = jobTag; + this.techTag = techTag; + this.title = title; + this.content = content; + this.link = link; + this.status = status; + this.startTime = startTime; + this.endTime = endTime; + this.alarm = alarm; + this.groupId = groupId; + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/response/PrivateScheduleUpdateResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/response/PrivateScheduleUpdateResDto.java index a16b07671..482ced24a 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/response/PrivateScheduleUpdateResDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/response/PrivateScheduleUpdateResDto.java @@ -1,11 +1,85 @@ package gg.calendar.api.user.schedule.privateschedule.controller.response; +import java.time.LocalDateTime; + +import gg.data.calendar.PrivateSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PrivateScheduleUpdateResDto { + private Long id; + + private DetailClassification classification; + + private EventTag eventTag; + + private JobTag jobTag; + + private TechTag techTag; + + private String author; + + private String title; + + private String content; + + private String link; + + private ScheduleStatus status; + + private LocalDateTime startTime; + + private LocalDateTime endTime; + + private boolean alarm; + + private Long groupId; + + @Builder + private PrivateScheduleUpdateResDto(Long id, DetailClassification classification, EventTag eventTag, JobTag jobTag, + TechTag techTag, String author, String title, String content, String link, ScheduleStatus status, + LocalDateTime startTime, LocalDateTime endTime, boolean alarm, Long groupId) { + this.id = id; + this.classification = classification; + this.eventTag = eventTag; + this.jobTag = jobTag; + this.techTag = techTag; + this.author = author; + this.title = title; + this.content = content; + this.link = link; + this.status = status; + this.startTime = startTime; + this.endTime = endTime; + this.alarm = alarm; + this.groupId = groupId; + } + public static PrivateScheduleUpdateResDto toDto(PrivateSchedule privateSchedule) { + return PrivateScheduleUpdateResDto.builder() + .id(privateSchedule.getId()) + .classification(privateSchedule.getPublicSchedule().getClassification()) + .eventTag(privateSchedule.getPublicSchedule().getEventTag()) + .jobTag(privateSchedule.getPublicSchedule().getJobTag()) + .techTag(privateSchedule.getPublicSchedule().getTechTag()) + .author(privateSchedule.getPublicSchedule().getAuthor()) + .title(privateSchedule.getPublicSchedule().getTitle()) + .content(privateSchedule.getPublicSchedule().getContent()) + .link(privateSchedule.getPublicSchedule().getLink()) + .status(privateSchedule.getStatus()) + .startTime(privateSchedule.getPublicSchedule().getStartTime()) + .endTime(privateSchedule.getPublicSchedule().getEndTime()) + .alarm(privateSchedule.isAlarm()) + .groupId(privateSchedule.getGroupId()) + .build(); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/service/PrivateScheduleService.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/service/PrivateScheduleService.java index f02ab8e0b..f514ccbbe 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/service/PrivateScheduleService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/service/PrivateScheduleService.java @@ -7,6 +7,8 @@ import gg.auth.UserDto; import gg.calendar.api.user.schedule.privateschedule.controller.request.PrivateScheduleCreateReqDto; +import gg.calendar.api.user.schedule.privateschedule.controller.request.PrivateScheduleUpdateReqDto; +import gg.calendar.api.user.schedule.privateschedule.controller.response.PrivateScheduleUpdateResDto; import gg.data.calendar.PrivateSchedule; import gg.data.calendar.PublicSchedule; import gg.data.calendar.ScheduleGroup; @@ -16,6 +18,7 @@ import gg.repo.calendar.ScheduleGroupRepository; import gg.repo.user.UserRepository; import gg.utils.exception.ErrorCode; +import gg.utils.exception.custom.ForbiddenException; import gg.utils.exception.custom.InvalidParameterException; import gg.utils.exception.custom.NotExistException; import lombok.RequiredArgsConstructor; @@ -43,9 +46,34 @@ public void createPrivateSchedule(UserDto userDto, PrivateScheduleCreateReqDto p privateScheduleRepository.save(privateSchedule); } + @Transactional + public PrivateScheduleUpdateResDto updatePrivateSchedule(UserDto userDto, + PrivateScheduleUpdateReqDto privateScheduleUpdateReqDto, Long privateScheduleId) { + validateTimeRange(privateScheduleUpdateReqDto.getStartTime(), privateScheduleUpdateReqDto.getEndTime()); + PrivateSchedule privateSchedule = privateScheduleRepository.findById(privateScheduleId) + .orElseThrow(() -> new NotExistException(ErrorCode.PRIVATE_SCHEDULE_NOT_FOUND)); + validateAuthor(userDto.getIntraId(), privateSchedule.getPublicSchedule().getAuthor()); + scheduleGroupRepository.findById(privateScheduleUpdateReqDto.getGroupId()) + .orElseThrow(() -> new NotExistException(ErrorCode.SCHEDULE_GROUP_NOT_FOUND)); + + privateSchedule.update(privateScheduleUpdateReqDto.getEventTag(), privateScheduleUpdateReqDto.getJobTag(), + privateScheduleUpdateReqDto.getTechTag(), privateScheduleUpdateReqDto.getTitle(), + privateScheduleUpdateReqDto.getContent(), privateScheduleUpdateReqDto.getLink(), + privateScheduleUpdateReqDto.getStatus(), privateScheduleUpdateReqDto.getStartTime(), + privateScheduleUpdateReqDto.getEndTime(), privateScheduleUpdateReqDto.isAlarm(), + privateScheduleUpdateReqDto.getGroupId()); + return PrivateScheduleUpdateResDto.toDto(privateSchedule); + } + public void validateTimeRange(LocalDateTime startTime, LocalDateTime endTime) { if (endTime.isBefore(startTime)) { throw new InvalidParameterException(ErrorCode.CALENDAR_BEFORE_DATE); } } + + public void validateAuthor(String intraId, String author) { + if (!intraId.equals(author)) { + throw new ForbiddenException(ErrorCode.CALENDAR_AUTHOR_NOT_MATCH); + } + } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/PrivateScheduleMockData.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/PrivateScheduleMockData.java index 54d34817c..7d95b56e9 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/PrivateScheduleMockData.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/PrivateScheduleMockData.java @@ -4,11 +4,13 @@ import org.springframework.stereotype.Component; +import gg.data.calendar.PrivateSchedule; import gg.data.calendar.PublicSchedule; import gg.data.calendar.ScheduleGroup; import gg.data.calendar.type.DetailClassification; import gg.data.calendar.type.ScheduleStatus; import gg.data.user.User; +import gg.repo.calendar.PrivateScheduleRepository; import gg.repo.calendar.PublicScheduleRepository; import gg.repo.calendar.ScheduleGroupRepository; import lombok.RequiredArgsConstructor; @@ -18,15 +20,16 @@ public class PrivateScheduleMockData { private final PublicScheduleRepository publicScheduleRepository; private final ScheduleGroupRepository scheduleGroupRepository; + private final PrivateScheduleRepository privateScheduleRepository; - public PublicSchedule createPublicSchedule() { + public PublicSchedule createPublicSchedule(String author) { PublicSchedule publicSchedule = PublicSchedule.builder() .classification(DetailClassification.EVENT) .eventTag(null) .jobTag(null) .techTag(null) .title("Test Schedule") - .author("author") + .author(author) .content("Test Content") .link("http://test.com") .status(ScheduleStatus.ACTIVATE) @@ -44,4 +47,10 @@ public ScheduleGroup createScheduleGroup(User user) { .build(); return scheduleGroupRepository.save(scheduleGroup); } + + public PrivateSchedule createPrivateSchedule(PublicSchedule publicSchedule, ScheduleGroup scheduleGroup) { + PrivateSchedule privateSchedule = new PrivateSchedule(scheduleGroup.getUser(), publicSchedule, false, + scheduleGroup.getId()); + return privateScheduleRepository.save(privateSchedule); + } } diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleControllerTest.java index fc8861105..5e8513be6 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/user/schedule/privateschedule/controller/PrivateScheduleControllerTest.java @@ -1,9 +1,11 @@ package gg.calendar.api.user.schedule.privateschedule.controller; +import static org.assertj.core.api.AssertionsForClassTypes.*; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.time.LocalDateTime; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -20,17 +22,19 @@ import gg.calendar.api.user.schedule.privateschedule.PrivateScheduleMockData; import gg.calendar.api.user.schedule.privateschedule.controller.request.PrivateScheduleCreateReqDto; +import gg.calendar.api.user.schedule.privateschedule.controller.request.PrivateScheduleUpdateReqDto; import gg.data.calendar.PrivateSchedule; +import gg.data.calendar.PublicSchedule; import gg.data.calendar.ScheduleGroup; -import gg.data.calendar.type.DetailClassification; import gg.data.calendar.type.EventTag; import gg.data.calendar.type.ScheduleStatus; import gg.data.user.User; import gg.repo.calendar.PrivateScheduleRepository; import gg.utils.TestDataUtils; import gg.utils.annotation.IntegrationTest; +import lombok.extern.slf4j.Slf4j; -@Transactional +@Slf4j @IntegrationTest @AutoConfigureMockMvc public class PrivateScheduleControllerTest { @@ -62,12 +66,12 @@ void setUp() { @DisplayName("PrivateSchedule 생성하기") class CreatePrivateSchedule { @Test + @Transactional @DisplayName("성공") void success() throws Exception { //given ScheduleGroup scheduleGroup = privateScheduleMockData.createScheduleGroup(user); PrivateScheduleCreateReqDto reqDto = PrivateScheduleCreateReqDto.builder() - .classification(DetailClassification.PRIVATE_SCHEDULE) .eventTag(EventTag.ETC) .jobTag(null) .techTag(null) @@ -77,7 +81,7 @@ void success() throws Exception { .startTime(LocalDateTime.now()) .endTime(LocalDateTime.now().plusDays(1)) .alarm(true) - .groupId(1L) + .groupId(scheduleGroup.getId()) .status(ScheduleStatus.ACTIVATE) .build(); //when @@ -87,17 +91,20 @@ void success() throws Exception { .content(objectMapper.writeValueAsString(reqDto))) .andExpect(status().isCreated()); //then - PrivateSchedule privateSchedule = privateScheduleRepository.findById(1L).orElseThrow(); + + List schedules = privateScheduleRepository.findAll(); + assertThat(schedules.size()).isEqualTo(1); + PrivateSchedule privateSchedule = schedules.get(0); Assertions.assertThat(privateSchedule.getGroupId()).isEqualTo(scheduleGroup.getId()); Assertions.assertThat(privateSchedule.isAlarm()).isEqualTo(reqDto.isAlarm()); } @Test + @Transactional @DisplayName("일정 그룹이 없는 경우 404") void noGroup() throws Exception { //given PrivateScheduleCreateReqDto reqDto = PrivateScheduleCreateReqDto.builder() - .classification(DetailClassification.PRIVATE_SCHEDULE) .eventTag(EventTag.ETC) .jobTag(null) .techTag(null) @@ -119,11 +126,11 @@ void noGroup() throws Exception { } @Test + @Transactional @DisplayName("시작 날짜보다 끝나는 날짜가 빠른 경우 400") void endTimeBeforeStartTime() throws Exception { //given PrivateScheduleCreateReqDto reqDto = PrivateScheduleCreateReqDto.builder() - .classification(DetailClassification.PRIVATE_SCHEDULE) .eventTag(EventTag.ETC) .jobTag(null) .techTag(null) @@ -144,4 +151,134 @@ void endTimeBeforeStartTime() throws Exception { .andExpect(status().isBadRequest()); } } + + @Nested + @DisplayName("PrivateSchedule 수정하기") + class UpdatePrivateSchedule { + @Test + @Transactional + @DisplayName("성공") + void success() throws Exception { + //given + ScheduleGroup scheduleGroup = privateScheduleMockData.createScheduleGroup(user); + PublicSchedule publicSchedule = privateScheduleMockData.createPublicSchedule(user.getIntraId()); + PrivateSchedule privateSchedule = privateScheduleMockData.createPrivateSchedule(publicSchedule, + scheduleGroup); + PrivateScheduleUpdateReqDto reqDto = PrivateScheduleUpdateReqDto.builder() + .eventTag(null) + .techTag(null) + .jobTag(null) + .alarm(false) + .title("123") + .content("") + .link(null) + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .groupId(scheduleGroup.getId()) + .build(); + //when + mockMvc.perform(put("/calendar/private/" + privateSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(reqDto))) + .andExpect(status().isOk()); + //then + PrivateSchedule updated = privateScheduleRepository.findById(privateSchedule.getId()).orElseThrow(); + Assertions.assertThat(privateSchedule.getGroupId()).isEqualTo(updated.getGroupId()); + Assertions.assertThat(privateSchedule.isAlarm()).isEqualTo(updated.isAlarm()); + Assertions.assertThat(privateSchedule.getGroupId()).isEqualTo(updated.getGroupId()); + Assertions.assertThat(privateSchedule.getPublicSchedule()).isEqualTo(updated.getPublicSchedule()); + } + + @Test + @Transactional + @DisplayName("종료 날짜가 시작 날짜보다 빠른 경우 400") + void endTimeBeforeStartTime() throws Exception { + //given + ScheduleGroup scheduleGroup = privateScheduleMockData.createScheduleGroup(user); + PublicSchedule publicSchedule = privateScheduleMockData.createPublicSchedule(user.getIntraId()); + PrivateSchedule privateSchedule = privateScheduleMockData.createPrivateSchedule(publicSchedule, + scheduleGroup); + PrivateScheduleUpdateReqDto reqDto = PrivateScheduleUpdateReqDto.builder() + .eventTag(null) + .techTag(null) + .jobTag(null) + .alarm(false) + .title("123") + .content("") + .link(null) + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now().plusDays(1)) + .endTime(LocalDateTime.now()) + .groupId(scheduleGroup.getId()) + .build(); + //when&then + mockMvc.perform(put("/calendar/private/" + privateSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(reqDto))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + @DisplayName("작성자가 아닌 사람이 일정을 수정 하려는 경우 403") + void notMatchAuthor() throws Exception { + //given + ScheduleGroup scheduleGroup = privateScheduleMockData.createScheduleGroup(user); + PublicSchedule publicSchedule = privateScheduleMockData.createPublicSchedule("notMatchAuthor"); + PrivateSchedule privateSchedule = privateScheduleMockData.createPrivateSchedule(publicSchedule, + scheduleGroup); + PrivateScheduleUpdateReqDto reqDto = PrivateScheduleUpdateReqDto.builder() + .eventTag(null) + .techTag(null) + .jobTag(null) + .alarm(false) + .title("123") + .content("") + .link(null) + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .groupId(scheduleGroup.getId()) + .build(); + //when + mockMvc.perform(put("/calendar/private/" + privateSchedule.getId()) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(reqDto))) + .andExpect(status().isForbidden()); + } + + @Test + @Transactional + @DisplayName("일정이 없는 경우 404") + void noSchedule() throws Exception { + //given + ScheduleGroup scheduleGroup = privateScheduleMockData.createScheduleGroup(user); + PublicSchedule publicSchedule = privateScheduleMockData.createPublicSchedule("notMatchAuthor"); + PrivateSchedule privateSchedule = privateScheduleMockData.createPrivateSchedule(publicSchedule, + scheduleGroup); + PrivateScheduleUpdateReqDto reqDto = PrivateScheduleUpdateReqDto.builder() + .eventTag(null) + .techTag(null) + .jobTag(null) + .alarm(false) + .title("123") + .content("") + .link(null) + .status(ScheduleStatus.ACTIVATE) + .startTime(LocalDateTime.now()) + .endTime(LocalDateTime.now().plusDays(1)) + .groupId(scheduleGroup.getId()) + .build(); + //when + mockMvc.perform(put("/calendar/private/" + privateSchedule.getId() + 123411243) + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(reqDto))) + .andExpect(status().isNotFound()); + } + } } diff --git a/gg-data/src/main/java/gg/data/calendar/PrivateSchedule.java b/gg-data/src/main/java/gg/data/calendar/PrivateSchedule.java index 20661c8db..630077b8e 100644 --- a/gg-data/src/main/java/gg/data/calendar/PrivateSchedule.java +++ b/gg-data/src/main/java/gg/data/calendar/PrivateSchedule.java @@ -1,5 +1,7 @@ package gg.data.calendar; +import java.time.LocalDateTime; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; @@ -12,7 +14,10 @@ import javax.persistence.ManyToOne; import gg.data.BaseTimeEntity; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; import gg.data.user.User; import lombok.AccessLevel; import lombok.Getter; @@ -51,4 +56,13 @@ public PrivateSchedule(User user, PublicSchedule publicSchedule, boolean alarm, this.groupId = groupId; this.status = ScheduleStatus.ACTIVATE; } + + public void update(EventTag eventTag, JobTag jobTag, TechTag techTag, String title, String content, + String link, ScheduleStatus status, LocalDateTime startTime, LocalDateTime endTime, boolean alarm, + Long groupId) { + this.alarm = alarm; + this.groupId = groupId; + this.publicSchedule.update(publicSchedule.getClassification(), eventTag, jobTag, techTag, title, content, link, + startTime, endTime, status); + } } diff --git a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java index ee8c8db59..f0eaaa193 100644 --- a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java +++ b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java @@ -86,7 +86,6 @@ private PublicSchedule(DetailClassification classification, EventTag eventTag, J this.endTime = endTime; } - public void update(DetailClassification classification, EventTag eventTag, JobTag jobTag, TechTag techTag, String title, String content, String link, LocalDateTime startTime, LocalDateTime endTime, ScheduleStatus status) { diff --git a/gg-utils/src/main/java/gg/utils/dto/PageResponseDto.java b/gg-utils/src/main/java/gg/utils/dto/PageResponseDto.java index c8395b339..82972a750 100644 --- a/gg-utils/src/main/java/gg/utils/dto/PageResponseDto.java +++ b/gg-utils/src/main/java/gg/utils/dto/PageResponseDto.java @@ -1,7 +1,6 @@ package gg.utils.dto; import java.util.List; -import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.Builder; From 6d74226a6436046b1155c4ac42520c74e87a64f1 Mon Sep 17 00:00:00 2001 From: seyeon22222 <92151066+seyeon22222@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:19:48 +0900 Subject: [PATCH 06/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20Admin=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=EC=9D=BC=EC=A0=95=20=EC=83=81=EC=84=B8=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20#1065=20(#1088)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PublicScheduleAdminController.java | 6 ++ .../response/PublicScheduleAdminResDto.java | 1 + .../service/PublicScheduleAdminService.java | 7 ++ .../admin/PublicScheduleAdminMockData.java | 4 +- .../PublicScheduleAdminControllerTest.java | 68 ++++++++++++++++++- 5 files changed, 82 insertions(+), 4 deletions(-) diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java index ecee0bed1..b395b3fa7 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java @@ -57,4 +57,10 @@ public ResponseEntity publicScheduleUpdate( publicScheduleAdminUpdateReqDto, id); return ResponseEntity.ok(publicScheduleAdminUpdateRes); } + + @GetMapping("/{id}") + public ResponseEntity publicScheduleDetail(@PathVariable Long id) { + PublicScheduleAdminResDto publicScheduleAdminResDto = publicScheduleAdminService.detailPublicSchedule(id); + return ResponseEntity.ok(publicScheduleAdminResDto); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java index b26e996d8..5557b42ed 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java @@ -16,6 +16,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PublicScheduleAdminResDto { + private Long id; private DetailClassification classification; diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java index 32ab751a0..69c291dd1 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java @@ -75,6 +75,13 @@ public PublicScheduleAdminUpdateResDto updatePublicSchedule( return PublicScheduleAdminUpdateResDto.toDto(publicSchedule); } + public PublicScheduleAdminResDto detailPublicSchedule(Long id) { + PublicSchedule publicSchedule = publicScheduleAdminRepository.findById(id) + .orElseThrow(() -> new NotExistException(ErrorCode.PUBLIC_SCHEDULE_NOT_FOUND)); + + return new PublicScheduleAdminResDto(publicSchedule); + } + private void dateTimeErrorCheck(LocalDateTime startTime, LocalDateTime endTime) { if (startTime.isAfter(endTime)) { throw new InvalidParameterException(ErrorCode.CALENDAR_BEFORE_DATE); diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java index dd3128148..a44db1ad9 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/PublicScheduleAdminMockData.java @@ -26,8 +26,8 @@ public PublicSchedule createPublicSchedule() { .classification(DetailClassification.EVENT) .eventTag(EventTag.JOB_FORUM) .author("42GG") - .title("취업설명회") - .content("취업설명회입니다.") + .title("Job Forum") + .content("Job Forum Test.") .link("https://gg.42seoul.kr") .status(ScheduleStatus.ACTIVATE) .startTime(LocalDateTime.now()) diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java index d2565029f..737eb9e4a 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java @@ -186,8 +186,8 @@ public void createPublicScheduleContentMax() throws Exception { @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Nested - @DisplayName("Admin PublicSchedule 태그 조회 테스트") - class GetPublicScheduleAdminClassificationListTest { + @DisplayName("Admin PublicSchedule 조회 테스트") + class GetPublicScheduleAdminTest { private Stream inputParams() { return Stream.of(Arguments.of("EVENT", 2, 10), Arguments.of("JOB_NOTICE", 1, 10), @@ -233,6 +233,70 @@ void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, System.out.println(dto.toString()); } } + + @Test + @DisplayName("Admin PublicSchedule 상세 조회 테스트 - 성공") + void getPublicScheduleAdminDetailTestSuccess() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + + // when + String response = mockMvc.perform( + get("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken)) + .andDo(print()) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + + PublicScheduleAdminResDto result = objectMapper.readValue(response, PublicScheduleAdminResDto.class); + + // then + assertThat(result.getId()).isEqualTo(publicSchedule.getId()); + assertThat(result.getClassification()).isEqualTo(publicSchedule.getClassification()); + assertThat(result.getEventTag()).isEqualTo(publicSchedule.getEventTag()); + assertThat(result.getJobTag()).isEqualTo(publicSchedule.getJobTag()); + assertThat(result.getTechTag()).isEqualTo(publicSchedule.getTechTag()); + assertThat(result.getAuthor()).isEqualTo(publicSchedule.getAuthor()); + assertThat(result.getTitle()).isEqualTo(publicSchedule.getTitle()); + assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); + assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); + assertThat(result.getLink()).isEqualTo(publicSchedule.getLink()); + assertThat(result.getSharedCount()).isEqualTo(publicSchedule.getSharedCount()); + assertThat(result.getStatus()).isEqualTo(publicSchedule.getStatus()); + } + + @Test + @DisplayName("Admin PublicSchedule 상세 조회 테스트 - 실패 : 잘못된 id가 들어왔을 경우") + void getPublicScheduleAdminDetailTestFailNotCorrectType() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + + // when + String response = mockMvc.perform( + get("/admin/calendar/public/qweksd").header("Authorization", + "Bearer " + accessToken)) + .andDo(print()) + .andExpect(status().isBadRequest()).andReturn().getResponse().getContentAsString(); + + // then + log.info("response :{}", response); + } + + @Test + @DisplayName("Admin PublicSchedule 상세 조회 테스트 - 실패 : 없는 id가 들어왔을 경우") + void getPublicScheduleAdminDetailTestFailNotFound() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + + // when + String response = mockMvc.perform( + get("/admin/calendar/public/500123").header("Authorization", + "Bearer " + accessToken)) + .andDo(print()) + .andExpect(status().isNotFound()).andReturn().getResponse().getContentAsString(); + + // then + log.info("response :{}", response); + } } @Nested From 93fa00fa0644bf3af609bd7162254af8f6874541 Mon Sep 17 00:00:00 2001 From: seyeon22222 <92151066+seyeon22222@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:41:20 +0900 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=A8=20[Feature]=20Admin=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=EC=9D=BC=EC=A0=95=20=EC=82=AD=EC=A0=9C=20API=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20#1089=20(#1090)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PublicScheduleAdminController.java | 8 ++ .../service/PublicScheduleAdminService.java | 11 ++ .../PublicScheduleAdminControllerTest.java | 133 ++++++++++++++---- .../java/gg/data/calendar/PublicSchedule.java | 4 + .../java/gg/utils/exception/ErrorCode.java | 1 + 5 files changed, 132 insertions(+), 25 deletions(-) diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java index b395b3fa7..555253c77 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java @@ -6,6 +6,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -58,9 +59,16 @@ public ResponseEntity publicScheduleUpdate( return ResponseEntity.ok(publicScheduleAdminUpdateRes); } + @PatchMapping("/{id}") + public ResponseEntity publicScheduleDelete(@PathVariable Long id) { + publicScheduleAdminService.deletePublicSchedule(id); + return ResponseEntity.status(HttpStatus.OK).build(); + } + @GetMapping("/{id}") public ResponseEntity publicScheduleDetail(@PathVariable Long id) { PublicScheduleAdminResDto publicScheduleAdminResDto = publicScheduleAdminService.detailPublicSchedule(id); return ResponseEntity.ok(publicScheduleAdminResDto); + } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java index 69c291dd1..c2e7a4b19 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java @@ -18,6 +18,7 @@ import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminUpdateResDto; import gg.data.calendar.PublicSchedule; import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.ScheduleStatus; import gg.utils.dto.PageResponseDto; import gg.utils.exception.ErrorCode; import gg.utils.exception.custom.InvalidParameterException; @@ -75,6 +76,16 @@ public PublicScheduleAdminUpdateResDto updatePublicSchedule( return PublicScheduleAdminUpdateResDto.toDto(publicSchedule); } + @Transactional + public void deletePublicSchedule(Long id) { + PublicSchedule publicSchedule = publicScheduleAdminRepository.findById(id) + .orElseThrow(() -> new NotExistException(ErrorCode.PUBLIC_SCHEDULE_NOT_FOUND)); + if (publicSchedule.getStatus().equals(ScheduleStatus.DELETE)) { + throw new InvalidParameterException(ErrorCode.PUBLIC_SCHEDULE_ALREADY_DELETED); + } + publicSchedule.delete(); + } + public PublicScheduleAdminResDto detailPublicSchedule(Long id) { PublicSchedule publicSchedule = publicScheduleAdminRepository.findById(id) .orElseThrow(() -> new NotExistException(ErrorCode.PUBLIC_SCHEDULE_NOT_FOUND)); diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java index 737eb9e4a..159a841ef 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java @@ -197,8 +197,7 @@ private Stream inputParams() { @ParameterizedTest @MethodSource("inputParams") @DisplayName("Admin PublicSchedule 태그 조회 테스트 - 성공") - void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, int size) throws - Exception { + void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, int size) throws Exception { // given publicScheduleAdminMockData.createPublicScheduleEvent(20); publicScheduleAdminMockData.createPublicScheduleJob(10); @@ -212,14 +211,16 @@ void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, // multivalue map 을 통해서 값이 넘어옴 String response = mockMvc.perform( get("/admin/calendar/public/list/{detailClassification}", tags).header("Authorization", - "Bearer " + accessToken) - .params(params)) + "Bearer " + accessToken).params(params)) .andDo(print()) - .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(); + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); // then - PageResponseDto pageResponseDto = objectMapper.readValue( - response, new TypeReference<>() { + PageResponseDto pageResponseDto = objectMapper.readValue(response, + new TypeReference<>() { }); List result = pageResponseDto.getContent(); @@ -322,13 +323,15 @@ void updatePublicScheduleAdminTestSuccess() throws Exception { // when String response = mockMvc.perform( - put("/admin/calendar/public/{id}", publicSchedule.getId()) - .header("Authorization", "Bearer " + accessToken) + put("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) .andDo(print()) .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); + .andReturn() + .getResponse() + .getContentAsString(); PublicScheduleAdminUpdateResDto result = objectMapper.readValue(response, PublicScheduleAdminUpdateResDto.class); @@ -367,13 +370,15 @@ void updatePublicScheduleAdminTestFailEndBeforeStart() throws Exception { // when String response = mockMvc.perform( - put("/admin/calendar/public/{id}", publicSchedule.getId()) - .header("Authorization", "Bearer " + accessToken) + put("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) .andDo(print()) .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(); + .andReturn() + .getResponse() + .getContentAsString(); List schedules = publicScheduleAdminRepository.findAll(); PublicSchedule result = schedules.get(0); @@ -406,13 +411,15 @@ void updatePublicScheduleAdminTestFailTitleMax() throws Exception { // when String response = mockMvc.perform( - put("/admin/calendar/public/{id}", publicSchedule.getId()) - .header("Authorization", "Bearer " + accessToken) + put("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) .andDo(print()) .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(); + .andReturn() + .getResponse() + .getContentAsString(); List schedules = publicScheduleAdminRepository.findAll(); PublicSchedule result = schedules.get(0); @@ -445,13 +452,15 @@ void updatePublicScheduleAdminTestFailContentMax() throws Exception { // when String response = mockMvc.perform( - put("/admin/calendar/public/{id}", publicSchedule.getId()) - .header("Authorization", "Bearer " + accessToken) + put("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) .andDo(print()) .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(); + .andReturn() + .getResponse() + .getContentAsString(); List schedules = publicScheduleAdminRepository.findAll(); PublicSchedule result = schedules.get(0); @@ -484,13 +493,14 @@ void updatePublicScheduleAdminTestFailNotExist() throws Exception { // when String response = mockMvc.perform( - put("/admin/calendar/public/100") - .header("Authorization", "Bearer " + accessToken) + put("/admin/calendar/public/100").header("Authorization", "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) .andDo(print()) .andExpect(status().isNotFound()) - .andReturn().getResponse().getContentAsString(); + .andReturn() + .getResponse() + .getContentAsString(); List schedules = publicScheduleAdminRepository.findAll(); PublicSchedule result = schedules.get(0); @@ -523,13 +533,14 @@ void updatePublicScheduleAdminTestFailBadArgument() throws Exception { // when String response = mockMvc.perform( - put("/admin/calendar/public/asdasdasd") - .header("Authorization", "Bearer " + accessToken) + put("/admin/calendar/public/asdasdasd").header("Authorization", "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(publicScheduleAdminUpdateReqDto))) .andDo(print()) .andExpect(status().isBadRequest()) - .andReturn().getResponse().getContentAsString(); + .andReturn() + .getResponse() + .getContentAsString(); List schedules = publicScheduleAdminRepository.findAll(); PublicSchedule result = schedules.get(0); @@ -542,5 +553,77 @@ void updatePublicScheduleAdminTestFailBadArgument() throws Exception { assertThat(result.getStartTime()).isEqualTo(publicSchedule.getStartTime()); assertThat(result.getEndTime()).isEqualTo(publicSchedule.getEndTime()); } + + @Test + @DisplayName("Admin PublicSchedule 삭제 테스트 - 성공") + void deletePublicScheduleAdminTestSuccess() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + + // when + mockMvc.perform(patch("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()); + + PublicSchedule result = publicScheduleAdminRepository.findById(publicSchedule.getId()).get(); + assertThat(result.getStatus()).isEqualTo(ScheduleStatus.DELETE); + System.out.println("PublicSchedule Status : " + result.getStatus()); + } + + @Test + @DisplayName("Admin PublicSchedule 삭제 테스트 - 실패 : 잘못된 id형식이 들어왔을 경우") + void deletePublicScheduleAdminTestFailNotBadArgument() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + + // when + mockMvc.perform(patch("/admin/calendar/public/qwe1asdv").header("Authorization", + "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isBadRequest()); + + PublicSchedule result = publicScheduleAdminRepository.findById(publicSchedule.getId()).get(); + assertThat(result.getStatus()).isEqualTo(ScheduleStatus.ACTIVATE); + System.out.println("PublicSchedule Status : " + result.getStatus()); + } + + @Test + @DisplayName("Admin PublicSchedule 삭제 테스트 - 실패 : 없는 id가 들어왔을 경우") + void deletePublicScheduleAdminTestFailNotFound() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + + // when + mockMvc.perform(patch("/admin/calendar/public/50123125").header("Authorization", + "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isNotFound()); + + PublicSchedule result = publicScheduleAdminRepository.findById(publicSchedule.getId()).get(); + assertThat(result.getStatus()).isEqualTo(ScheduleStatus.ACTIVATE); + System.out.println("PublicSchedule Status : " + result.getStatus()); + } + + @Test + @DisplayName("Admin PublicSchedule 삭제 테스트 - 실패 : 이미 삭제된 일정을 삭제하는 경우") + void deletePublicScheduleAdminTestFailAlreadyDelete() throws Exception { + // given + PublicSchedule publicSchedule = publicScheduleAdminMockData.createPublicSchedule(); + publicSchedule.delete(); + // when + mockMvc.perform(patch("/admin/calendar/public/{id}", publicSchedule.getId()).header("Authorization", + "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isBadRequest()); + + PublicSchedule result = publicScheduleAdminRepository.findById(publicSchedule.getId()).get(); + assertThat(result.getStatus()).isEqualTo(ScheduleStatus.DELETE); + System.out.println("PublicSchedule Status : " + result.getStatus()); + } } } diff --git a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java index f0eaaa193..2d3d616cb 100644 --- a/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java +++ b/gg-data/src/main/java/gg/data/calendar/PublicSchedule.java @@ -100,5 +100,9 @@ public void update(DetailClassification classification, EventTag eventTag, JobTa this.endTime = endTime; this.status = status; } + + public void delete() { + this.status = ScheduleStatus.DELETE; + } } diff --git a/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java index 017c51a21..2bdb97764 100644 --- a/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java +++ b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java @@ -243,6 +243,7 @@ public enum ErrorCode { CALENDAR_AUTHOR_NOT_MATCH(403, "CA205", "잘못된 사용자입니다."), PRIVATE_SCHEDULE_NOT_FOUND(404, "CA101", "개인 일정을 찾을 수 없습니다."), PUBLIC_SCHEDULE_NOT_FOUND(404, "CA102", "공유 일정을 찾을 수 없습니다."), + PUBLIC_SCHEDULE_ALREADY_DELETED(409, "CA104", "이미 삭제된 개인 일정입니다."), SCHEDULE_GROUP_NOT_FOUND(404, "CA103", "스캐줄 그룹을 찾을 수 없습니다."); private final int status; From c0961f7b786d8d3fa9055441a617330a96897c1e Mon Sep 17 00:00:00 2001 From: seykim Date: Tue, 31 Dec 2024 15:23:19 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=94=A8=20[Refactoring]=20Admin=20?= =?UTF-8?q?=EA=B3=B5=EC=9C=A0=EC=9D=BC=EC=A0=95=20=EC=A1=B0=ED=9A=8C=20API?= =?UTF-8?q?=20->=20=EB=B6=84=EB=A5=98=EB=B3=84=20=EC=9D=BC=EC=A0=95?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PrivateScheduleAdminController.java | 5 +- .../PublicScheduleAdminController.java | 16 --- .../response/PublicScheduleAdminResDto.java | 8 -- .../service/PublicScheduleAdminService.java | 23 ---- .../TotalScheduleAdminController.java | 37 +++++ .../response/TotalScheduleAdminResDto.java | 59 ++++++++ .../service/TotalScheduleAdminService.java | 41 ++++++ .../PublicScheduleAdminControllerTest.java | 56 -------- .../TotalScheduleAdminControllerTest.java | 126 ++++++++++++++++++ .../security/config/SecurityConfig.java | 4 +- 10 files changed, 269 insertions(+), 106 deletions(-) create mode 100644 gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminController.java create mode 100644 gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/response/TotalScheduleAdminResDto.java create mode 100644 gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/service/TotalScheduleAdminService.java create mode 100644 gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminControllerTest.java diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/privateschedule/controller/PrivateScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/privateschedule/controller/PrivateScheduleAdminController.java index 68f41d79f..037376730 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/privateschedule/controller/PrivateScheduleAdminController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/privateschedule/controller/PrivateScheduleAdminController.java @@ -1,17 +1,18 @@ package gg.calendar.api.admin.schedule.privateschedule.controller; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import gg.calendar.api.admin.schedule.privateschedule.service.PrivateScheduleAdminService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @RestController @RequiredArgsConstructor -@RequestMapping("/admin/calendar") +@RequestMapping("/admin/calendar/private") public class PrivateScheduleAdminController { + private final PrivateScheduleAdminService privateScheduleAdminService; } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java index 555253c77..5966b2ca5 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminController.java @@ -5,7 +5,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -19,9 +18,6 @@ import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminUpdateResDto; import gg.calendar.api.admin.schedule.publicschedule.service.PublicScheduleAdminService; -import gg.data.calendar.type.DetailClassification; -import gg.utils.dto.PageRequestDto; -import gg.utils.dto.PageResponseDto; import lombok.RequiredArgsConstructor; @RestController @@ -38,18 +34,6 @@ public ResponseEntity publicScheduleCreate( return ResponseEntity.status(HttpStatus.CREATED).build(); } - @GetMapping("/list/{detailClassification}") - public ResponseEntity> publicScheduleAdminClassificationList( - @PathVariable DetailClassification detailClassification, @ModelAttribute @Valid PageRequestDto pageRequestDto) { - int page = pageRequestDto.getPage(); - int size = pageRequestDto.getSize(); - - PageResponseDto pageResponseDto = publicScheduleAdminService.findAllByClassification( - detailClassification, page, size); - - return ResponseEntity.ok(pageResponseDto); - } - @PutMapping("/{id}") public ResponseEntity publicScheduleUpdate( @RequestBody @Valid PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto, diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java index 5557b42ed..327844e8a 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/controller/response/PublicScheduleAdminResDto.java @@ -56,12 +56,4 @@ public PublicScheduleAdminResDto(PublicSchedule publicSchedule) { this.sharedCount = publicSchedule.getSharedCount(); this.status = publicSchedule.getStatus(); } - - @Override - public String toString() { - return "PublicScheduleAdminResDto{" + "id=" + id + ", classification=" + classification + ", eventTag=" - + eventTag + ", jobTag=" + jobTag + ", techTag=" + techTag + ", author='" + author + '\'' + ", title='" - + title + '\'' + ", startTime=" + startTime + ", endTime=" + endTime + ", link='" + link + '\'' - + ", sharedCount=" + sharedCount + ", status=" + status + '}'; - } } diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java index c2e7a4b19..58310d45e 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java @@ -1,13 +1,7 @@ package gg.calendar.api.admin.schedule.publicschedule.service; import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,9 +11,7 @@ import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminResDto; import gg.calendar.api.admin.schedule.publicschedule.controller.response.PublicScheduleAdminUpdateResDto; import gg.data.calendar.PublicSchedule; -import gg.data.calendar.type.DetailClassification; import gg.data.calendar.type.ScheduleStatus; -import gg.utils.dto.PageResponseDto; import gg.utils.exception.ErrorCode; import gg.utils.exception.custom.InvalidParameterException; import gg.utils.exception.custom.NotExistException; @@ -42,21 +34,6 @@ public void createPublicSchedule(PublicScheduleAdminCreateReqDto publicScheduleA publicScheduleAdminRepository.save(publicSchedule); } - public PageResponseDto findAllByClassification(DetailClassification detailClassification, - int page, int size) { - - Pageable pageable = PageRequest.of(page - 1, size, - Sort.by(Sort.Order.asc("status"), Sort.Order.asc("startTime"))); - - Page publicSchedules = publicScheduleAdminRepository.findAllByClassification( - detailClassification, pageable); - - List publicScheduleList = publicSchedules.stream() - .map(PublicScheduleAdminResDto::new) - .collect(Collectors.toList()); - return PageResponseDto.of(publicSchedules.getTotalElements(), publicScheduleList); - } - @Transactional public PublicScheduleAdminUpdateResDto updatePublicSchedule( PublicScheduleAdminUpdateReqDto publicScheduleAdminUpdateReqDto, Long id) { diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminController.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminController.java new file mode 100644 index 000000000..c7151b20d --- /dev/null +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminController.java @@ -0,0 +1,37 @@ +package gg.calendar.api.admin.schedule.totalschedule.controller; + +import javax.validation.Valid; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gg.calendar.api.admin.schedule.totalschedule.controller.response.TotalScheduleAdminResDto; +import gg.calendar.api.admin.schedule.totalschedule.service.TotalScheduleAdminService; +import gg.data.calendar.type.DetailClassification; +import gg.utils.dto.PageRequestDto; +import gg.utils.dto.PageResponseDto; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/admin/calendar") +public class TotalScheduleAdminController { + + private final TotalScheduleAdminService totalScheduleAdminService; + + @GetMapping("/list/{detailClassification}") + public ResponseEntity> totalScheduleAdminClassificationList( + @PathVariable DetailClassification detailClassification, @ModelAttribute @Valid PageRequestDto pageRequestDto) { + int page = pageRequestDto.getPage(); + int size = pageRequestDto.getSize(); + + PageResponseDto pageResponseDto = totalScheduleAdminService.findAllByClassification( + detailClassification, page, size); + + return ResponseEntity.ok(pageResponseDto); + } +} diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/response/TotalScheduleAdminResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/response/TotalScheduleAdminResDto.java new file mode 100644 index 000000000..54c65ab77 --- /dev/null +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/controller/response/TotalScheduleAdminResDto.java @@ -0,0 +1,59 @@ +package gg.calendar.api.admin.schedule.totalschedule.controller.response; + +import java.time.LocalDateTime; + +import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.data.calendar.type.EventTag; +import gg.data.calendar.type.JobTag; +import gg.data.calendar.type.ScheduleStatus; +import gg.data.calendar.type.TechTag; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class TotalScheduleAdminResDto { + + private Long id; + + private DetailClassification classification; + + private EventTag eventTag; + + private JobTag jobTag; + + private TechTag techTag; + + private String author; + + private String title; + + private LocalDateTime startTime; + + private LocalDateTime endTime; + + private String link; + + private Integer sharedCount; + + private ScheduleStatus status; + + @Builder + public TotalScheduleAdminResDto(PublicSchedule publicSchedule) { + this.id = publicSchedule.getId(); + this.classification = publicSchedule.getClassification(); + this.eventTag = publicSchedule.getEventTag(); + this.jobTag = publicSchedule.getJobTag(); + this.techTag = publicSchedule.getTechTag(); + this.author = publicSchedule.getAuthor(); + this.title = publicSchedule.getTitle(); + this.startTime = publicSchedule.getStartTime(); + this.endTime = publicSchedule.getEndTime(); + this.link = publicSchedule.getLink(); + this.sharedCount = publicSchedule.getSharedCount(); + this.status = publicSchedule.getStatus(); + } +} diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/service/TotalScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/service/TotalScheduleAdminService.java new file mode 100644 index 000000000..f54b56c88 --- /dev/null +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/totalschedule/service/TotalScheduleAdminService.java @@ -0,0 +1,41 @@ +package gg.calendar.api.admin.schedule.totalschedule.service; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import gg.admin.repo.calendar.PublicScheduleAdminRepository; +import gg.calendar.api.admin.schedule.totalschedule.controller.response.TotalScheduleAdminResDto; +import gg.data.calendar.PublicSchedule; +import gg.data.calendar.type.DetailClassification; +import gg.utils.dto.PageResponseDto; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class TotalScheduleAdminService { + + private final PublicScheduleAdminRepository publicScheduleAdminRepository; + + public PageResponseDto findAllByClassification(DetailClassification detailClassification, + int page, int size) { + + Pageable pageable = PageRequest.of(page - 1, size, + Sort.by(Sort.Order.asc("status"), Sort.Order.asc("startTime"))); + + Page publicSchedules = publicScheduleAdminRepository.findAllByClassification( + detailClassification, pageable); + + List publicScheduleList = publicSchedules.stream() + .map(TotalScheduleAdminResDto::new) + .collect(Collectors.toList()); + return PageResponseDto.of(publicSchedules.getTotalElements(), publicScheduleList); + } +} diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java index 159a841ef..8c2203415 100644 --- a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/publicschedule/controller/PublicScheduleAdminControllerTest.java @@ -7,7 +7,6 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.stream.Stream; import javax.persistence.EntityManager; import javax.transaction.Transactional; @@ -16,18 +15,11 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import gg.admin.repo.calendar.PublicScheduleAdminRepository; @@ -46,7 +38,6 @@ import gg.data.user.User; import gg.utils.TestDataUtils; import gg.utils.annotation.IntegrationTest; -import gg.utils.dto.PageResponseDto; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -184,57 +175,10 @@ public void createPublicScheduleContentMax() throws Exception { } } - @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Nested @DisplayName("Admin PublicSchedule 조회 테스트") class GetPublicScheduleAdminTest { - private Stream inputParams() { - return Stream.of(Arguments.of("EVENT", 2, 10), Arguments.of("JOB_NOTICE", 1, 10), - Arguments.of("PRIVATE_SCHEDULE", 1, 2)); - } - - @ParameterizedTest - @MethodSource("inputParams") - @DisplayName("Admin PublicSchedule 태그 조회 테스트 - 성공") - void getPublicScheduleAdminClassificationListTestSuccess(String tags, int page, int size) throws Exception { - // given - publicScheduleAdminMockData.createPublicScheduleEvent(20); - publicScheduleAdminMockData.createPublicScheduleJob(10); - publicScheduleAdminMockData.createPublicSchedulePrivate(5); - - MultiValueMap params = new LinkedMultiValueMap<>(); - params.add("page", String.valueOf(page)); - params.add("size", String.valueOf(size)); - - // when - // multivalue map 을 통해서 값이 넘어옴 - String response = mockMvc.perform( - get("/admin/calendar/public/list/{detailClassification}", tags).header("Authorization", - "Bearer " + accessToken).params(params)) - .andDo(print()) - .andExpect(status().isOk()) - .andReturn() - .getResponse() - .getContentAsString(); - - // then - PageResponseDto pageResponseDto = objectMapper.readValue(response, - new TypeReference<>() { - }); - List result = pageResponseDto.getContent(); - - if (DetailClassification.valueOf(tags) == DetailClassification.PRIVATE_SCHEDULE) { - assertThat(result.size()).isEqualTo(2); - } else { - assertThat(result.size()).isEqualTo(10); - } - - for (PublicScheduleAdminResDto dto : result) { - System.out.println(dto.toString()); - } - } - @Test @DisplayName("Admin PublicSchedule 상세 조회 테스트 - 성공") void getPublicScheduleAdminDetailTestSuccess() throws Exception { diff --git a/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminControllerTest.java b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminControllerTest.java new file mode 100644 index 000000000..9badd5c37 --- /dev/null +++ b/gg-calendar-api/src/test/java/gg/calendar/api/admin/schedule/totalschedule/controller/TotalScheduleAdminControllerTest.java @@ -0,0 +1,126 @@ +package gg.calendar.api.admin.schedule.totalschedule.controller; + +import static org.assertj.core.api.Assertions.*; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import java.util.List; +import java.util.stream.Stream; + +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.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import gg.admin.repo.calendar.PublicScheduleAdminRepository; +import gg.calendar.api.admin.PublicScheduleAdminMockData; +import gg.calendar.api.admin.schedule.totalschedule.controller.response.TotalScheduleAdminResDto; +import gg.data.calendar.type.DetailClassification; +import gg.data.user.User; +import gg.utils.TestDataUtils; +import gg.utils.annotation.IntegrationTest; +import gg.utils.dto.PageResponseDto; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@IntegrationTest +@Transactional +@AutoConfigureMockMvc +class TotalScheduleAdminControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + EntityManager em; + + @Autowired + private PublicScheduleAdminMockData publicScheduleAdminMockData; + + @Autowired + private PublicScheduleAdminRepository publicScheduleAdminRepository; + + @Autowired + private TestDataUtils testDataUtils; + + private User user; + + private String accessToken; + + @Autowired + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + user = testDataUtils.createAdminUser(); + accessToken = testDataUtils.getLoginAccessTokenFromUser(user); + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Nested + @DisplayName("Admin TotalSchedule 조회 테스트") + class GetTotalScheduleAdminTest { + + private Stream inputParams() { + return Stream.of(Arguments.of("EVENT", 2, 10), Arguments.of("JOB_NOTICE", 1, 10), + Arguments.of("PRIVATE_SCHEDULE", 1, 2)); + } + + @ParameterizedTest + @MethodSource("inputParams") + @DisplayName("Admin TotalSchedule 태그 조회 테스트 - 성공") + void getTotalAdminClassificationListTestSuccess(String tags, int page, int size) throws Exception { + // given + publicScheduleAdminMockData.createPublicScheduleEvent(20); + publicScheduleAdminMockData.createPublicScheduleJob(10); + publicScheduleAdminMockData.createPublicSchedulePrivate(5); + + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("page", String.valueOf(page)); + params.add("size", String.valueOf(size)); + + // when + // multivalue map 을 통해서 값이 넘어옴 + String response = mockMvc.perform( + get("/admin/calendar/list/{detailClassification}", tags).header("Authorization", + "Bearer " + accessToken).params(params)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + // then + PageResponseDto pageResponseDto = objectMapper.readValue(response, + new TypeReference<>() { + }); + List result = pageResponseDto.getContent(); + + if (DetailClassification.valueOf(tags) == DetailClassification.PRIVATE_SCHEDULE) { + assertThat(result.size()).isEqualTo(2); + } else { + assertThat(result.size()).isEqualTo(10); + } + + for (TotalScheduleAdminResDto dto : result) { + System.out.println(dto.toString()); + } + } + + } +} diff --git a/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java b/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java index 9ac204776..e5ee48a17 100644 --- a/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java +++ b/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java @@ -48,6 +48,8 @@ protected void configure(HttpSecurity http) throws Exception { .antMatchers("/agenda/admin/**") .hasRole("ADMIN") .antMatchers(HttpMethod.PUT, "/pingpong/users/{intraId}") + .hasRole("ADMIN") + .antMatchers("/admin/calendar/**") .hasAnyRole("USER", "ADMIN") .antMatchers(HttpMethod.POST, "/pingpong/match") .hasAnyRole("USER", "ADMIN") @@ -55,7 +57,7 @@ protected void configure(HttpSecurity http) throws Exception { .hasAnyRole("USER", "ADMIN") .antMatchers("/login", "/oauth2/authorization/**", "/", "/pingpong/users/oauth/**", "/pingpong/users/accesstoken", "/actuator/**", "/swagger-ui/**", "/swagger-ui**", "/v3/api-docs/**", - "/v3/api-docs**", "/api-docs", "/admin/calendar/**") + "/v3/api-docs**", "/api-docs", "/calendar/**") .permitAll() .anyRequest() .authenticated() From 0489b19d28751dc411a7aa755f44ddb35ace60f0 Mon Sep 17 00:00:00 2001 From: seykim Date: Tue, 31 Dec 2024 15:31:24 +0900 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=94=A8=20[Refactoring]=20if?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=EB=AC=B8=20helper=ED=95=A8=EC=88=98=EB=A1=9C?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../publicschedule/service/PublicScheduleAdminService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java index 58310d45e..bfdca9fe2 100644 --- a/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java +++ b/gg-calendar-api/src/main/java/gg/calendar/api/admin/schedule/publicschedule/service/PublicScheduleAdminService.java @@ -57,10 +57,14 @@ public PublicScheduleAdminUpdateResDto updatePublicSchedule( public void deletePublicSchedule(Long id) { PublicSchedule publicSchedule = publicScheduleAdminRepository.findById(id) .orElseThrow(() -> new NotExistException(ErrorCode.PUBLIC_SCHEDULE_NOT_FOUND)); + isDeleted(publicSchedule); + publicSchedule.delete(); + } + + private void isDeleted(PublicSchedule publicSchedule) { if (publicSchedule.getStatus().equals(ScheduleStatus.DELETE)) { throw new InvalidParameterException(ErrorCode.PUBLIC_SCHEDULE_ALREADY_DELETED); } - publicSchedule.delete(); } public PublicScheduleAdminResDto detailPublicSchedule(Long id) { From d02b73445dd9eec2a4fd8606bd0918ca68e1bd28 Mon Sep 17 00:00:00 2001 From: seykim Date: Tue, 31 Dec 2024 16:18:26 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=E2=9C=A8=20=20[Fix]=20SecurityConfig=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gg/pingpong/api/global/security/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java b/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java index e5ee48a17..2b9b45b7e 100644 --- a/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java +++ b/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java @@ -57,7 +57,7 @@ protected void configure(HttpSecurity http) throws Exception { .hasAnyRole("USER", "ADMIN") .antMatchers("/login", "/oauth2/authorization/**", "/", "/pingpong/users/oauth/**", "/pingpong/users/accesstoken", "/actuator/**", "/swagger-ui/**", "/swagger-ui**", "/v3/api-docs/**", - "/v3/api-docs**", "/api-docs", "/calendar/**") + "/v3/api-docs**", "/api-docs") .permitAll() .anyRequest() .authenticated() From 8810f8d3786dc681ea51360140be6f923e54b4e2 Mon Sep 17 00:00:00 2001 From: seykim Date: Tue, 31 Dec 2024 16:24:48 +0900 Subject: [PATCH 11/12] =?UTF-8?q?=E2=9C=A8=20=20[Fix]=20SecurityConfig=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pingpong/api/global/security/config/SecurityConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java b/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java index 2b9b45b7e..5f759a847 100644 --- a/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java +++ b/gg-pingpong-api/src/main/java/gg/pingpong/api/global/security/config/SecurityConfig.java @@ -48,9 +48,9 @@ protected void configure(HttpSecurity http) throws Exception { .antMatchers("/agenda/admin/**") .hasRole("ADMIN") .antMatchers(HttpMethod.PUT, "/pingpong/users/{intraId}") - .hasRole("ADMIN") - .antMatchers("/admin/calendar/**") .hasAnyRole("USER", "ADMIN") + .antMatchers("/admin/calendar/**") + .hasRole("ADMIN") .antMatchers(HttpMethod.POST, "/pingpong/match") .hasAnyRole("USER", "ADMIN") .antMatchers(HttpMethod.POST, "/pingpong/tournaments/{tournamentId}/users") From 21ac71bfee772b96e6d1954316be606add4447aa Mon Sep 17 00:00:00 2001 From: seykim Date: Tue, 31 Dec 2024 19:34:46 +0900 Subject: [PATCH 12/12] =?UTF-8?q?[Fix]=20Proejct=20List=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gg-utils/build.gradle | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gg-utils/build.gradle b/gg-utils/build.gradle index 5cd09ebf3..0d494e2b0 100644 --- a/gg-utils/build.gradle +++ b/gg-utils/build.gradle @@ -48,7 +48,9 @@ integrationTestCoverageReport { getClassDirectories().setFrom(files( [project(':gg-data'), project(':gg-admin-repo'), project(':gg-repo'), project(':gg-pingpong-api'), - project(':gg-auth'), project(':gg-utils')].collect { + project(':gg-auth'), project(':gg-utils'), + project(':gg-recruit-api'), project(':gg-agenda-api'), + project(':gg-calendar-api')].collect { it.fileTree(dir: "${it.buildDir}/classes/java/main", exclude: jacocoExcludes) } )) @@ -65,7 +67,9 @@ unitTestCoverageReport { getClassDirectories().setFrom(files( [project(':gg-data'), project(':gg-admin-repo'), project(':gg-repo'), project(':gg-pingpong-api'), - project(':gg-auth'), project(':gg-utils')].collect { + project(':gg-auth'), project(':gg-utils'), + project(':gg-recruit-api'), project(':gg-agenda-api'), + project(':gg-calendar-api')].collect { it.fileTree(dir: "${it.buildDir}/classes/java/main", exclude: jacocoExcludes) } )) @@ -100,6 +104,8 @@ dependencies { testFixturesImplementation project(":gg-admin-repo") testFixturesImplementation project(":gg-pingpong-api") testFixturesImplementation project(":gg-recruit-api") + testFixturesImplementation project(":gg-agenda-api") + testFixturesImplementation project(":gg-calendar-api") jacocoAggregation(project(':gg-data')) jacocoAggregation(project(':gg-auth')) @@ -107,6 +113,8 @@ dependencies { jacocoAggregation(project(':gg-admin-repo')) jacocoAggregation(project(':gg-pingpong-api')) jacocoAggregation(project(':gg-recruit-api')) + jacocoAggregation(project(':gg-agenda-api')) + jacocoAggregation(project(':gg-calendar-api')) } test {