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 99db490f2..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,11 +4,11 @@ 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.RequestParam; import org.springframework.web.bind.annotation.RestController; import gg.auth.UserDto; @@ -37,7 +37,7 @@ public ResponseEntity privateScheduleCreate(@Login @Parameter(hidden = tru public ResponseEntity privateScheduleUpdate( @Login @Parameter(hidden = true) UserDto userDto, @Valid @RequestBody PrivateScheduleUpdateReqDto privateScheduleUpdateReqDto, - @RequestParam Long id) { + @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/response/PrivateScheduleUpdateResDto.java b/gg-calendar-api/src/main/java/gg/calendar/api/user/schedule/privateschedule/controller/response/PrivateScheduleUpdateResDto.java index 1966d7a8a..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 @@ -47,8 +47,7 @@ public class PrivateScheduleUpdateResDto { @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) { + LocalDateTime startTime, LocalDateTime endTime, boolean alarm, Long groupId) { this.id = id; this.classification = classification; this.eventTag = eventTag; 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 ac08e3809..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 @@ -18,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; @@ -54,6 +55,7 @@ public PrivateScheduleUpdateResDto updatePrivateSchedule(UserDto userDto, 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(), @@ -70,8 +72,8 @@ public void validateTimeRange(LocalDateTime startTime, LocalDateTime endTime) { } public void validateAuthor(String intraId, String author) { - if (intraId.equals(author)) { - throw new InvalidParameterException(ErrorCode.CALENDAR_AUTHOR_NOT_MATCH); + 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 ebbad4d6d..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,7 +22,9 @@ 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.EventTag; import gg.data.calendar.type.ScheduleStatus; @@ -28,8 +32,9 @@ 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 { @@ -61,6 +66,7 @@ void setUp() { @DisplayName("PrivateSchedule 생성하기") class CreatePrivateSchedule { @Test + @Transactional @DisplayName("성공") void success() throws Exception { //given @@ -75,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 @@ -85,12 +91,16 @@ 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 @@ -116,6 +126,7 @@ void noGroup() throws Exception { } @Test + @Transactional @DisplayName("시작 날짜보다 끝나는 날짜가 빠른 경우 400") void endTimeBeforeStartTime() throws Exception { //given @@ -140,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-utils/src/main/java/gg/utils/exception/ErrorCode.java b/gg-utils/src/main/java/gg/utils/exception/ErrorCode.java index 8fa62caca..d1302e1c8 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", "스캐줄 그룹을 찾을 수 없습니다.");