diff --git a/src/main/java/com/dateplan/dateplan/domain/calender/service/CalenderReadService.java b/src/main/java/com/dateplan/dateplan/domain/calender/service/CalenderReadService.java index dd41ce11..778be629 100644 --- a/src/main/java/com/dateplan/dateplan/domain/calender/service/CalenderReadService.java +++ b/src/main/java/com/dateplan/dateplan/domain/calender/service/CalenderReadService.java @@ -37,7 +37,7 @@ public CalenderDateServiceResponse readCalenderDates(Member member, Long memberI Long partnerId = coupleReadService.getPartnerId(member); DatingDatesServiceResponse datingDates = datingReadService.readDatingDates( - member, coupleId, year, month); + coupleId, year, month); ScheduleDatesServiceResponse myScheduleDates = scheduleReadService.readScheduleDates( member, memberId, year, month); ScheduleDatesServiceResponse partnerScheduleDates = scheduleReadService.readScheduleDates( diff --git a/src/main/java/com/dateplan/dateplan/domain/dating/controller/DatingController.java b/src/main/java/com/dateplan/dateplan/domain/dating/controller/DatingController.java index 858fcbb1..efd1626d 100644 --- a/src/main/java/com/dateplan/dateplan/domain/dating/controller/DatingController.java +++ b/src/main/java/com/dateplan/dateplan/domain/dating/controller/DatingController.java @@ -35,12 +35,9 @@ public class DatingController { @ResponseStatus(value = HttpStatus.CREATED) @PostMapping("/{couple_id}/dating") - public ApiResponse createDating( - @PathVariable("couple_id") Long coupleId, - @Valid @RequestBody DatingCreateRequest request - ) { + public ApiResponse createDating(@Valid @RequestBody DatingCreateRequest request) { final Member member = MemberThreadLocal.get(); - datingService.createDating(member, coupleId, request.toDatingCreateServiceRequest()); + datingService.createDating(member, request.toDatingCreateServiceRequest()); return ApiResponse.ofSuccess(); } @@ -50,23 +47,20 @@ public ApiResponse readDatingDates( @RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month ) { - final Member member = MemberThreadLocal.get(); - DatingDatesServiceResponse response = datingReadService.readDatingDates( - member, coupleId, year, month); + DatingDatesServiceResponse response = datingReadService.readDatingDates(coupleId, year, + month); return ApiResponse.ofSuccess(DatingDatesResponse.from(response)); } @PutMapping("/{couple_id}/dating/{dating_id}") public ApiResponse updateDating( - @PathVariable("couple_id") Long coupleId, @PathVariable("dating_id") Long datingId, @Valid @RequestBody DatingUpdateRequest request ) { - final Member member = MemberThreadLocal.get(); - datingService.updateDating(member, coupleId, datingId, - request.toDatingUpdateServiceRequest()); + datingService.updateDating(datingId, request.toDatingUpdateServiceRequest()); return ApiResponse.ofSuccess(); } + @GetMapping("/{couple_id}/dating") public ApiResponse readDating( @PathVariable("couple_id") Long coupleId, @@ -74,19 +68,15 @@ public ApiResponse readDating( @RequestParam("month") Integer month, @RequestParam("day") Integer day ) { - final Member member = MemberThreadLocal.get(); - DatingServiceResponse response = datingReadService.readDating(member, coupleId, year, month, - day); + DatingServiceResponse response = datingReadService.readDating(coupleId, year, month, day); return ApiResponse.ofSuccess(DatingResponse.from(response)); } @DeleteMapping("/{couple_id}/dating/{dating_id}") public ApiResponse deleteDating( - @PathVariable("couple_id") Long coupleId, @PathVariable("dating_id") Long datingId ) { - final Member member = MemberThreadLocal.get(); - datingService.deleteDating(member, coupleId, datingId); + datingService.deleteDating(datingId); return ApiResponse.ofSuccess(); } } diff --git a/src/main/java/com/dateplan/dateplan/domain/dating/interceptor/DatingAuthInterceptor.java b/src/main/java/com/dateplan/dateplan/domain/dating/interceptor/DatingAuthInterceptor.java new file mode 100644 index 00000000..ad21c258 --- /dev/null +++ b/src/main/java/com/dateplan/dateplan/domain/dating/interceptor/DatingAuthInterceptor.java @@ -0,0 +1,72 @@ +package com.dateplan.dateplan.domain.dating.interceptor; + +import com.dateplan.dateplan.domain.couple.entity.Couple; +import com.dateplan.dateplan.domain.couple.service.CoupleReadService; +import com.dateplan.dateplan.domain.dating.entity.Dating; +import com.dateplan.dateplan.domain.dating.service.DatingReadService; +import com.dateplan.dateplan.domain.member.entity.Member; +import com.dateplan.dateplan.global.auth.MemberThreadLocal; +import com.dateplan.dateplan.global.constant.Operation; +import com.dateplan.dateplan.global.constant.Resource; +import com.dateplan.dateplan.global.exception.auth.NoPermissionException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Map; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.HandlerMapping; + +@Component +@RequiredArgsConstructor +public class DatingAuthInterceptor implements HandlerInterceptor { + + private final CoupleReadService coupleReadService; + private final DatingReadService datingReadService; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, + Object handler) throws Exception { + Map map = (Map) request.getAttribute( + HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + String method = request.getMethod(); + + Member member = MemberThreadLocal.get(); + String coupleId = map.get("couple_id"); + String datingId = map.get("dating_id"); + Couple couple = coupleReadService.findCoupleByMemberOrElseThrow(member); + + if (coupleId != null) { + if (isNotSameCouple(Long.valueOf(coupleId), couple.getId())) { + throwNoPermissionException(method); + } + if (datingId != null) { + Dating dating = datingReadService.findByDatingId(Long.valueOf(datingId)); + if (isNotDatingOwner(Long.valueOf(coupleId), dating.getCouple().getId())) { + throwNoPermissionException(method); + } + } + } + + return true; + } + + private boolean isNotSameCouple(Long requestId, Long coupleId) { + return !Objects.equals(requestId, coupleId); + } + + private boolean isNotDatingOwner(Long coupleId, Long datingOwnerId) { + return !Objects.equals(coupleId, datingOwnerId); + } + + private void throwNoPermissionException(String method) { + Operation operation = switch (method) { + case "GET" -> Operation.READ; + case "POST" -> Operation.CREATE; + case "PUT" -> Operation.UPDATE; + default -> Operation.DELETE; + }; + throw new NoPermissionException(Resource.DATING, operation); + } +} diff --git a/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingReadService.java b/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingReadService.java index e52b881e..8831ede0 100644 --- a/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingReadService.java +++ b/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingReadService.java @@ -1,20 +1,13 @@ package com.dateplan.dateplan.domain.dating.service; -import com.dateplan.dateplan.domain.couple.entity.Couple; -import com.dateplan.dateplan.domain.couple.service.CoupleReadService; import com.dateplan.dateplan.domain.dating.entity.Dating; import com.dateplan.dateplan.domain.dating.repository.DatingQueryRepository; import com.dateplan.dateplan.domain.dating.repository.DatingRepository; import com.dateplan.dateplan.domain.dating.service.dto.response.DatingDatesServiceResponse; import com.dateplan.dateplan.domain.dating.service.dto.response.DatingServiceResponse; -import com.dateplan.dateplan.domain.member.entity.Member; -import com.dateplan.dateplan.global.constant.Operation; -import com.dateplan.dateplan.global.constant.Resource; -import com.dateplan.dateplan.global.exception.auth.NoPermissionException; import com.dateplan.dateplan.global.exception.dating.DatingNotFoundException; import java.time.LocalDate; import java.util.List; -import java.util.Objects; import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -26,7 +19,6 @@ public class DatingReadService { private final DatingQueryRepository datingQueryRepository; - private final CoupleReadService coupleReadService; private final DatingRepository datingRepository; public Dating findByDatingId(Long datingId) { @@ -35,34 +27,21 @@ public Dating findByDatingId(Long datingId) { } public DatingServiceResponse readDating( - Member member, Long coupleId, Integer year, Integer month, Integer day ) { - Couple couple = coupleReadService.findCoupleByMemberOrElseThrow(member); - if (isNotSameCouple(coupleId, couple.getId())) { - throw new NoPermissionException(Resource.COUPLE, Operation.READ); - } - List datingList = datingQueryRepository .findByDateBetween(coupleId, year, month, day); return DatingServiceResponse.from(datingList); } public DatingDatesServiceResponse readDatingDates( - Member member, Long coupleId, Integer year, Integer month ) { - Couple couple = coupleReadService.findCoupleByMemberOrElseThrow(member); - - if (isNotSameCouple(coupleId, couple.getId())) { - throw new NoPermissionException(Resource.COUPLE, Operation.READ); - } - List datingList = datingQueryRepository.findByYearAndMonthOrderByDate(coupleId, year, month); return DatingDatesServiceResponse.builder() @@ -101,8 +80,4 @@ private boolean checkDateRange(Integer year, Integer month, LocalDate date) { } return date.getYear() == year && date.getMonthValue() == month; } - - private boolean isNotSameCouple(Long requestId, Long coupleId) { - return !Objects.equals(requestId, coupleId); - } } diff --git a/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingService.java b/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingService.java index 9eb4a934..a2dbad16 100644 --- a/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingService.java +++ b/src/main/java/com/dateplan/dateplan/domain/dating/service/DatingService.java @@ -7,10 +7,6 @@ import com.dateplan.dateplan.domain.dating.service.dto.request.DatingCreateServiceRequest; import com.dateplan.dateplan.domain.dating.service.dto.request.DatingUpdateServiceRequest; import com.dateplan.dateplan.domain.member.entity.Member; -import com.dateplan.dateplan.global.constant.Operation; -import com.dateplan.dateplan.global.constant.Resource; -import com.dateplan.dateplan.global.exception.auth.NoPermissionException; -import java.util.Objects; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,35 +20,19 @@ public class DatingService { private final CoupleReadService coupleReadService; private final DatingReadService datingReadService; - public void createDating(Member member, Long coupleId, DatingCreateServiceRequest request) { + public void createDating(Member member, DatingCreateServiceRequest request) { Couple couple = coupleReadService.findCoupleByMemberOrElseThrow(member); - if (isNotSameCouple(coupleId, couple.getId())) { - throw new NoPermissionException(Resource.COUPLE, Operation.CREATE); - } - Dating dating = request.toDatingEntity(couple); datingRepository.save(dating); } public void updateDating( - Member member, - Long coupleId, Long datingId, DatingUpdateServiceRequest request ) { - Couple couple = coupleReadService.findCoupleByMemberOrElseThrow(member); - - if (isNotSameCouple(coupleId, couple.getId())) { - throw new NoPermissionException(Resource.COUPLE, Operation.UPDATE); - } - Dating dating = datingReadService.findByDatingId(datingId); - if (isNotDatingOwner(couple.getId(), dating.getCouple().getId())) { - throw new NoPermissionException(Resource.DATING, Operation.UPDATE); - } - dating.updateDating( request.getTitle(), request.getLocation(), @@ -62,27 +42,9 @@ public void updateDating( ); } - public void deleteDating(Member member, Long coupleId, Long datingId) { - Couple couple = coupleReadService.findCoupleByMemberOrElseThrow(member); - - if (isNotSameCouple(coupleId, couple.getId())) { - throw new NoPermissionException(Resource.COUPLE, Operation.DELETE); - } - + public void deleteDating(Long datingId) { Dating dating = datingReadService.findByDatingId(datingId); - if (isNotDatingOwner(couple.getId(), dating.getCouple().getId())) { - throw new NoPermissionException(Resource.DATING, Operation.DELETE); - } - datingRepository.delete(dating); } - - private boolean isNotSameCouple(Long requestId, Long coupleId) { - return !Objects.equals(requestId, coupleId); - } - - private boolean isNotDatingOwner(Long coupleId, Long datingOwnerId) { - return !Objects.equals(coupleId, datingOwnerId); - } } diff --git a/src/main/java/com/dateplan/dateplan/global/config/web/WebConfig.java b/src/main/java/com/dateplan/dateplan/global/config/web/WebConfig.java index 8b7a7c94..7194294c 100644 --- a/src/main/java/com/dateplan/dateplan/global/config/web/WebConfig.java +++ b/src/main/java/com/dateplan/dateplan/global/config/web/WebConfig.java @@ -1,6 +1,7 @@ package com.dateplan.dateplan.global.config.web; import com.dateplan.dateplan.domain.anniversary.interceptor.AnniversaryAuthInterceptor; +import com.dateplan.dateplan.domain.dating.interceptor.DatingAuthInterceptor; import com.dateplan.dateplan.global.interceptor.AuthInterceptor; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; @@ -13,6 +14,7 @@ public class WebConfig implements WebMvcConfigurer { private final AuthInterceptor authInterceptor; private final AnniversaryAuthInterceptor anniversaryAuthInterceptor; + private final DatingAuthInterceptor datingAuthInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { @@ -24,5 +26,9 @@ public void addInterceptors(InterceptorRegistry registry) { registry .addInterceptor(anniversaryAuthInterceptor) .addPathPatterns("/api/couples/**/anniversary/**"); + + registry + .addInterceptor(datingAuthInterceptor) + .addPathPatterns("/api/couples/**/dating/**"); } } diff --git a/src/test/java/com/dateplan/dateplan/controller/ControllerTestSupport.java b/src/test/java/com/dateplan/dateplan/controller/ControllerTestSupport.java index 457b0289..886b0012 100644 --- a/src/test/java/com/dateplan/dateplan/controller/ControllerTestSupport.java +++ b/src/test/java/com/dateplan/dateplan/controller/ControllerTestSupport.java @@ -10,6 +10,7 @@ import com.dateplan.dateplan.domain.couple.service.CoupleReadService; import com.dateplan.dateplan.domain.couple.service.CoupleService; import com.dateplan.dateplan.domain.dating.controller.DatingController; +import com.dateplan.dateplan.domain.dating.interceptor.DatingAuthInterceptor; import com.dateplan.dateplan.domain.dating.service.DatingReadService; import com.dateplan.dateplan.domain.dating.service.DatingService; import com.dateplan.dateplan.domain.member.controller.AuthController; @@ -89,4 +90,7 @@ public abstract class ControllerTestSupport { @MockBean protected CalenderReadService calenderReadService; + + @MockBean + protected DatingAuthInterceptor datingAuthInterceptor; } diff --git a/src/test/java/com/dateplan/dateplan/controller/dating/DatingControllerTest.java b/src/test/java/com/dateplan/dateplan/controller/dating/DatingControllerTest.java index da4d75d2..adbb4d8c 100644 --- a/src/test/java/com/dateplan/dateplan/controller/dating/DatingControllerTest.java +++ b/src/test/java/com/dateplan/dateplan/controller/dating/DatingControllerTest.java @@ -26,11 +26,8 @@ import com.dateplan.dateplan.domain.member.entity.Member; import com.dateplan.dateplan.global.auth.MemberThreadLocal; import com.dateplan.dateplan.global.constant.Gender; -import com.dateplan.dateplan.global.constant.Operation; -import com.dateplan.dateplan.global.constant.Resource; import com.dateplan.dateplan.global.exception.ErrorCode; import com.dateplan.dateplan.global.exception.ErrorCode.DetailMessage; -import com.dateplan.dateplan.global.exception.auth.NoPermissionException; import com.dateplan.dateplan.global.exception.couple.MemberNotConnectedException; import com.dateplan.dateplan.global.exception.dating.DatingNotFoundException; import com.dateplan.dateplan.global.exception.schedule.InvalidDateTimeRangeException; @@ -56,9 +53,18 @@ public class DatingControllerTest extends ControllerTestSupport { @BeforeEach - void setUp() { + void setUp() throws Exception { given( - authInterceptor.preHandle(any(HttpServletRequest.class), any(HttpServletResponse.class), + authInterceptor.preHandle( + any(HttpServletRequest.class), + any(HttpServletResponse.class), + any(Object.class))) + .willReturn(true); + + given( + datingAuthInterceptor.preHandle( + any(HttpServletRequest.class), + any(HttpServletResponse.class), any(Object.class))) .willReturn(true); } @@ -89,7 +95,7 @@ void successWithValidRequest() throws Exception { // Stubbing willDoNothing() .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then mockMvc.perform( @@ -114,7 +120,7 @@ void failWithInvalidTitle() throws Exception { // Stubbing willDoNothing() .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then mockMvc.perform( @@ -141,7 +147,7 @@ void failWithInvalidContent() throws Exception { // Stubbing willDoNothing() .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then mockMvc.perform( @@ -168,7 +174,7 @@ void failWithInvalidLocation() throws Exception { // Stubbing willDoNothing() .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then mockMvc.perform( @@ -184,60 +190,6 @@ void failWithInvalidLocation() throws Exception { ); } - @DisplayName("요청한 couple_id와 현재 로그인한 멤버의 couple_id가 다르면 실패한다") - @Test - void failWithNoPermission() throws Exception { - - // Given - DatingCreateRequest request = createDatingCreateRequest(null, null, null, null, null); - - // Stubbing - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.CREATE); - willThrow(exception) - .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); - - // When & Then - mockMvc.perform( - post(REQUEST_URL, 1) - .content(om.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding(StandardCharsets.UTF_8) - ).andExpectAll( - status().isForbidden(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(exception.getErrorCode().getCode()), - jsonPath("$.message").value(exception.getMessage()) - ); - } - - @DisplayName("pathVariable의 타입이 유효하지 않으면 실패한다") - @Test - void failWithInvalidTypeMismatch() throws Exception { - - // Given - DatingCreateRequest request = createDatingCreateRequest(null, null, null, null, null); - - // Stubbing - willDoNothing() - .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); - - // When & Then - mockMvc.perform( - post(REQUEST_URL, "abc") - .content(om.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding(StandardCharsets.UTF_8) - ).andExpectAll( - status().isBadRequest(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(ErrorCode.METHOD_ARGUMENT_TYPE_MISMATCH.getCode()), - jsonPath("$.message").value(containsString("Long")) - ); - } - @DisplayName("데이트 일정 종료 시간이 2049년 12월 31일 이후이면 실패한다") @Test void failWithInvalidCalendarEndDate() throws Exception { @@ -249,7 +201,7 @@ void failWithInvalidCalendarEndDate() throws Exception { // Stubbing willDoNothing() .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then mockMvc.perform( @@ -277,7 +229,7 @@ void failWithInvalidDateTimeRange() throws Exception { // Stubbing willDoNothing() .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then InvalidDateTimeRangeException exception = new InvalidDateTimeRangeException(); @@ -306,7 +258,7 @@ void failWithMemberNotConnected() throws Exception { MemberNotConnectedException exception = new MemberNotConnectedException(); willThrow(exception) .given(datingService) - .createDating(any(Member.class), anyLong(), any(DatingCreateServiceRequest.class)); + .createDating(any(Member.class), any(DatingCreateServiceRequest.class)); // When & Then mockMvc.perform( @@ -350,7 +302,7 @@ void successWithValidRequest() throws Exception { // Stubbing given( - datingReadService.readDatingDates(any(Member.class), anyLong(), anyInt(), anyInt())) + datingReadService.readDatingDates(anyLong(), anyInt(), anyInt())) .willReturn(response); // When & Then @@ -364,28 +316,6 @@ void successWithValidRequest() throws Exception { ); } - @DisplayName("현재 로그인한 회원이 연결된 커플의 couple_id와 요청의 couple_id가 다르면 실패한다.") - @Test - void failWithNoPermissionRequest() throws Exception { - - // Stubbing - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.READ); - given( - datingReadService.readDatingDates(any(Member.class), anyLong(), anyInt(), anyInt())) - .willThrow(exception); - - // When & Then - mockMvc.perform(get(REQUEST_URL, 1L) - .param("year", String.valueOf(LocalDate.now().getYear())) - .param("month", String.valueOf(LocalDate.now().getMonthValue()))) - .andExpect(status().isForbidden()) - .andExpectAll( - jsonPath("$.code").value(ErrorCode.NO_PERMISSION.getCode()), - jsonPath("$.message").value(exception.getMessage()) - ); - } - @DisplayName("현재 로그인한 회원이 연결되어 있지 않다면 실패한다.") @Test void failWithNotConnectedRequest() throws Exception { @@ -393,7 +323,7 @@ void failWithNotConnectedRequest() throws Exception { // Stubbing MemberNotConnectedException exception = new MemberNotConnectedException(); given( - datingReadService.readDatingDates(any(Member.class), anyLong(), anyInt(), anyInt())) + datingReadService.readDatingDates(anyLong(), anyInt(), anyInt())) .willThrow(exception); // When & Then @@ -417,7 +347,7 @@ void failWithInvalidQueryParameter(String year, String month) throws Exception { // Stubbing given( - datingReadService.readDatingDates(any(Member.class), anyLong(), anyInt(), anyInt())) + datingReadService.readDatingDates(anyLong(), anyInt(), anyInt())) .willReturn(response); // When & Then @@ -457,8 +387,7 @@ void tearDown() { LocalDate now = LocalDate.now(); // Stubbing - given(datingReadService.readDating(any(Member.class), anyLong(), anyInt(), anyInt(), - anyInt())) + given(datingReadService.readDating(anyLong(), anyInt(), anyInt(), anyInt())) .willReturn(response); // When & Then @@ -490,8 +419,8 @@ void tearDown() { DatingServiceResponse response = createDatingServiceResponse(); // Stubbing - given(datingReadService.readDating - (any(Member.class), anyLong(), anyInt(), anyInt(), anyInt())).willReturn(response); + given(datingReadService.readDating(anyLong(), anyInt(), anyInt(), anyInt())) + .willReturn(response); // When & Then mockMvc.perform( @@ -506,36 +435,12 @@ void tearDown() { jsonPath("$.message").value(containsString("Integer"))); } - @Test - void 실패_로그인한회원의coupleId와_요청의coupleId가다르면_예외를반환한다() throws Exception { - - // Stubbing - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.READ); - given(datingReadService.readDating(any(Member.class), anyLong(), anyInt(), anyInt(), - anyInt())) - .willThrow(exception); - - // When & Then - mockMvc.perform( - get(REQUEST_URL, 1) - .param("year", "2020") - .param("month", "10") - .param("day", "10")) - .andExpectAll( - status().isForbidden(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(exception.getErrorCode().getCode()), - jsonPath("$.message").value(exception.getMessage())); - } - @Test void 실패_회원이_연결되어있지않으면_예외를_반환한다() throws Exception { // Stubbing MemberNotConnectedException exception = new MemberNotConnectedException(); - given(datingReadService.readDating(any(Member.class), anyLong(), anyInt(), anyInt(), - anyInt())) + given(datingReadService.readDating(anyLong(), anyInt(), anyInt(), anyInt())) .willThrow(exception); // When & Then @@ -574,8 +479,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, 1, 1) @@ -595,8 +499,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, 1, 1) @@ -618,8 +521,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, 1, 1) @@ -641,8 +543,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, 1, 1) @@ -663,8 +564,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, "a", "b") @@ -679,30 +579,6 @@ void tearDown() { ); } - @Test - void 실패_요청한회원이연결된couple의id와_요청의coupleId가다르면_예외를반환한다() throws Exception { - DatingUpdateRequest request = createDatingUpdateRequest(null, null, null, null, null); - - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.UPDATE); - willThrow(exception) - .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); - - mockMvc.perform( - put(REQUEST_URL, 1, 1) - .content(om.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding(StandardCharsets.UTF_8)) - .andExpectAll( - status().isForbidden(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(exception.getErrorCode().getCode()), - jsonPath("$.message").value(exception.getMessage()) - ); - } - @Test void 실패_요청에해당하는데이트일정이_존재하지않으면_예외를반환한다() throws Exception { DatingUpdateRequest request = createDatingUpdateRequest(null, null, null, null, null); @@ -710,8 +586,7 @@ void tearDown() { DatingNotFoundException exception = new DatingNotFoundException(); willThrow(exception) .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, 1, 1) @@ -733,8 +608,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); InvalidDateTimeRangeException exception = new InvalidDateTimeRangeException(); mockMvc.perform( @@ -757,8 +631,7 @@ void tearDown() { willDoNothing() .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); + .updateDating(anyLong(), any(DatingUpdateServiceRequest.class)); mockMvc.perform( put(REQUEST_URL, 1, 1) @@ -772,30 +645,6 @@ void tearDown() { jsonPath("$.message").value(DetailMessage.INVALID_CALENDER_TIME_RANGE) ); } - - @Test - void 실패_요청한coupleId와_조회한데이트일정의coupldId가다르면_예외를반환한다() throws Exception { - DatingUpdateRequest request = createDatingUpdateRequest(null, null, null, null, null); - - NoPermissionException exception = new NoPermissionException(Resource.DATING, - Operation.UPDATE); - willThrow(exception) - .given(datingService) - .updateDating(any(Member.class), anyLong(), anyLong(), - any(DatingUpdateServiceRequest.class)); - - mockMvc.perform( - put(REQUEST_URL, 1, 1) - .content(om.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding(StandardCharsets.UTF_8)) - .andExpectAll( - status().isForbidden(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(exception.getErrorCode().getCode()), - jsonPath("$.message").value(exception.getMessage()) - ); - } } @Nested @@ -819,7 +668,7 @@ void tearDown() { willDoNothing() .given(datingService) - .deleteDating(any(Member.class), anyLong(), anyLong()); + .deleteDating(anyLong()); mockMvc.perform( delete(REQUEST_URL, 1, 1)) @@ -829,49 +678,13 @@ void tearDown() { ); } - @Test - void 실패_pathVariable의타입이_올바르지않으면_예외를반환한다() throws Exception { - - willDoNothing() - .given(datingService) - .deleteDating(any(Member.class), anyLong(), anyLong()); - - mockMvc.perform( - delete(REQUEST_URL, "a", "b")) - .andExpectAll( - status().isBadRequest(), - jsonPath("success").value("false"), - jsonPath("$.code").value(ErrorCode.METHOD_ARGUMENT_TYPE_MISMATCH.getCode()), - jsonPath("$.message").value(containsString("Long")) - ); - } - - @Test - void 실패_요청의coupldId와_회원이연결된커플의Id가다르면_예외를반환한다() throws Exception { - - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.DELETE); - willThrow(exception) - .given(datingService) - .deleteDating(any(Member.class), anyLong(), anyLong()); - - mockMvc.perform( - delete(REQUEST_URL, 1, 1)) - .andExpectAll( - status().isForbidden(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(exception.getErrorCode().getCode()), - jsonPath("$.message").value(exception.getMessage()) - ); - } - @Test void 실패_요청한datingId에_해당하는데이트일정이없으면_예외를반환한다() throws Exception { DatingNotFoundException exception = new DatingNotFoundException(); willThrow(exception) .given(datingService) - .deleteDating(any(Member.class), anyLong(), anyLong()); + .deleteDating(anyLong()); mockMvc.perform( delete(REQUEST_URL, 1, 1)) @@ -882,25 +695,6 @@ void tearDown() { jsonPath("$.message").value(exception.getMessage()) ); } - - @Test - void 실패_요청한coupleId와_조회한데이트일정의coupldId가다르면_예외를반환한다() throws Exception { - - NoPermissionException exception = new NoPermissionException(Resource.DATING, - Operation.DELETE); - willThrow(exception) - .given(datingService) - .deleteDating(any(Member.class), anyLong(), anyLong()); - - mockMvc.perform( - delete(REQUEST_URL, 1, 1)) - .andExpectAll( - status().isForbidden(), - jsonPath("$.success").value("false"), - jsonPath("$.code").value(exception.getErrorCode().getCode()), - jsonPath("$.message").value(exception.getMessage()) - ); - } } private static Member createMember() { diff --git a/src/test/java/com/dateplan/dateplan/service/dating/DatingReadServiceTest.java b/src/test/java/com/dateplan/dateplan/service/dating/DatingReadServiceTest.java index ccd28b81..b407be23 100644 --- a/src/test/java/com/dateplan/dateplan/service/dating/DatingReadServiceTest.java +++ b/src/test/java/com/dateplan/dateplan/service/dating/DatingReadServiceTest.java @@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; import com.dateplan.dateplan.domain.couple.entity.Couple; import com.dateplan.dateplan.domain.couple.repository.CoupleRepository; @@ -20,10 +19,6 @@ import com.dateplan.dateplan.domain.member.repository.MemberRepository; import com.dateplan.dateplan.global.auth.MemberThreadLocal; import com.dateplan.dateplan.global.constant.Gender; -import com.dateplan.dateplan.global.constant.Operation; -import com.dateplan.dateplan.global.constant.Resource; -import com.dateplan.dateplan.global.exception.auth.NoPermissionException; -import com.dateplan.dateplan.global.exception.couple.MemberNotConnectedException; import com.dateplan.dateplan.global.exception.dating.DatingNotFoundException; import com.dateplan.dateplan.service.ServiceTestSupport; import java.time.LocalDate; @@ -58,22 +53,18 @@ public class DatingReadServiceTest extends ServiceTestSupport { @Autowired private DatingReadService datingReadService; - @SpyBean - private DatingQueryRepository queryRepository; - @DisplayName("일정 날짜를 조회할 때") @Nested class ReadDatingDate { private static final String NEED_DATING = "needDating"; - private Member member; private Couple couple; private List savedDatingDates; @BeforeEach void setUp(TestInfo testInfo) { - member = memberRepository.save(createMember("01012345678", "aaa")); + Member member = memberRepository.save(createMember("01012345678", "aaa")); Member partner = memberRepository.save(createMember("01012345679", "bbb")); couple = coupleRepository.save(createCouple(member, partner)); MemberThreadLocal.set(member); @@ -110,7 +101,7 @@ void successWithValidRequest() { // Given & When DatingDatesServiceResponse response = datingReadService.readDatingDates( - member, couple.getId(), null, null); + couple.getId(), null, null); // Then List actualDates = response.getDatingDates(); @@ -134,7 +125,7 @@ void successWithValidRequestAndParam() { // When DatingDatesServiceResponse response = datingReadService.readDatingDates( - member, couple.getId(), year, month); + couple.getId(), year, month); // Then List actualDates = response.getDatingDates(); @@ -148,47 +139,6 @@ void successWithValidRequestAndParam() { assertThat(actualDates) .isSortedAccordingTo(LocalDate::compareTo); } - - @DisplayName("로그인한 회원이 연결된 커플의 id와 요청한 coupldId가 다르면 실패한다.") - @Test - void failWithNoPermission() { - - // Stubbing - given(coupleReadService.findCoupleByMemberOrElseThrow(any(Member.class))) - .willReturn(couple); - - // When & Then - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.READ); - assertThatThrownBy( - () -> datingReadService.readDatingDates(member, couple.getId() + 100, null, null)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - - // Verify - then(queryRepository) - .shouldHaveNoInteractions(); - } - - @DisplayName("회원이 연결되어 있지 않으면 실패한다.") - @Test - void failWithNotConnected() { - - // Stubbing - MemberNotConnectedException exception = new MemberNotConnectedException(); - given(coupleReadService.findCoupleByMemberOrElseThrow(any(Member.class))) - .willThrow(exception); - - // When & Then - assertThatThrownBy( - () -> datingReadService.readDatingDates(member, couple.getId(), null, null)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - - // Verify - then(queryRepository) - .shouldHaveNoInteractions(); - } } @Nested @@ -253,7 +203,7 @@ void tearDown() { // When LocalDate now = LocalDate.now(); - DatingServiceResponse response = datingReadService.readDating(member, + DatingServiceResponse response = datingReadService.readDating( couple.getId(), now.getYear(), now.getMonthValue(), now.getDayOfMonth()); // Then @@ -265,37 +215,6 @@ void tearDown() { assertThat(datingEntryResponse.getStartDateTime()).isEqualTo(today.getStartDateTime()); assertThat(datingEntryResponse.getEndDateTime()).isEqualTo(today.getEndDateTime()); } - - @Test - void 실패_회원이_커플에연결되어있지않으면_예외를반환한다() { - - // Stubbing - MemberNotConnectedException exception = new MemberNotConnectedException(); - given(coupleReadService.findCoupleByMemberOrElseThrow(any(Member.class))) - .willThrow(exception); - - // When & Then - assertThatThrownBy( - () -> datingReadService.readDating(member, couple.getId() + 100, 2010, 10, 10)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - } - - @Test - void 실패_요청한coupleId와_회원이연결된커플의id가다르면_예외를반환한다() { - - // Stubbing - given(coupleReadService.findCoupleByMemberOrElseThrow(member)) - .willReturn(couple); - - // When & Then - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.READ); - assertThatThrownBy( - () -> datingReadService.readDating(member, couple.getId() + 100, 2010, 10, 10)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - } } @Nested diff --git a/src/test/java/com/dateplan/dateplan/service/dating/DatingServiceTest.java b/src/test/java/com/dateplan/dateplan/service/dating/DatingServiceTest.java index 29a73188..0137a2ab 100644 --- a/src/test/java/com/dateplan/dateplan/service/dating/DatingServiceTest.java +++ b/src/test/java/com/dateplan/dateplan/service/dating/DatingServiceTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.BDDMockito.then; import com.dateplan.dateplan.domain.couple.entity.Couple; import com.dateplan.dateplan.domain.couple.repository.CoupleRepository; @@ -16,9 +15,6 @@ import com.dateplan.dateplan.domain.member.repository.MemberRepository; import com.dateplan.dateplan.global.auth.MemberThreadLocal; import com.dateplan.dateplan.global.constant.Gender; -import com.dateplan.dateplan.global.constant.Operation; -import com.dateplan.dateplan.global.constant.Resource; -import com.dateplan.dateplan.global.exception.auth.NoPermissionException; import com.dateplan.dateplan.global.exception.couple.MemberNotConnectedException; import com.dateplan.dateplan.global.exception.dating.DatingNotFoundException; import com.dateplan.dateplan.service.ServiceTestSupport; @@ -50,9 +46,6 @@ public class DatingServiceTest extends ServiceTestSupport { @Autowired private DatingService datingService; - @SpyBean - private DatingReadService datingReadService; - @Nested @DisplayName("데이트 일정 생성 시") class CreateDating { @@ -99,7 +92,7 @@ void successWithValidRequest() { DatingCreateServiceRequest request = createServiceRequest(); // When - datingService.createDating(member, couple.getId(), request); + datingService.createDating(member, request); // Then List datingList = datingRepository.findAll(); @@ -112,23 +105,6 @@ void successWithValidRequest() { assertThat(dating.getEndDateTime()).isEqualTo(request.getEndDateTime()); } - @Tag(NEED_COUPLE) - @DisplayName("로그인한 회원의 coupleId와 요청의 coupleId가 다르면 실패한다") - @Test - void failWithNoPermission() { - - // Given - DatingCreateServiceRequest request = createServiceRequest(); - - // When & Then - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.CREATE); - assertThatThrownBy( - () -> datingService.createDating(member, couple.getId() + 100, request)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - } - @DisplayName("회원이 연결되어 있지 않으면 실패한다") @Test void failWithMemberNotConnected() { @@ -138,7 +114,7 @@ void failWithMemberNotConnected() { // When & Then MemberNotConnectedException exception = new MemberNotConnectedException(); - assertThatThrownBy(() -> datingService.createDating(member, 1L, request)) + assertThatThrownBy(() -> datingService.createDating(member, request)) .isInstanceOf(exception.getClass()) .hasMessage(exception.getMessage()); } @@ -148,16 +124,14 @@ void failWithMemberNotConnected() { @DisplayName("데이트 일정 삭제 시") class DeleteDating { - private Member member; - private Couple couple; private Dating savedDating; @BeforeEach void setUp() { - member = memberRepository.save(createMember("01012345678", "aaa")); + Member member = memberRepository.save(createMember("01012345678", "aaa")); Member partner = memberRepository.save(createMember("01012345679", "bbb")); - couple = coupleRepository.save(Couple.builder() + Couple couple = coupleRepository.save(Couple.builder() .member1(member) .member2(partner) .firstDate(LocalDate.now()) @@ -183,80 +157,19 @@ void tearDown() { void 성공_올바른coupleId와_존재하는데이트일정의Id를요청하면_해당데이트일정이삭제된다() { // When - datingService.deleteDating(member, couple.getId(), savedDating.getId()); + datingService.deleteDating(savedDating.getId()); // When assertThat(datingRepository.findById(savedDating.getId())).isEmpty(); } - @Test - void 실패_요청한coupldId와_회원이연결된커플의id가다르면_예외를반환한다() { - - // When & Then - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.DELETE); - assertThatThrownBy(() -> - datingService.deleteDating(member, couple.getId() + 100, savedDating.getId())) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - - // Verify - then(datingReadService) - .shouldHaveNoInteractions(); - } - - @Test - void 실패_회원이_연결되어있지않으면_예외를반환한다() { - - // Given - Member other = memberRepository.save(createMember("01011112222", "ccc")); - - // When & Then - MemberNotConnectedException exception = new MemberNotConnectedException(); - assertThatThrownBy( - () -> datingService.deleteDating(other, couple.getId(), savedDating.getId())) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - - // Verify - then(datingReadService) - .shouldHaveNoInteractions(); - } - @Test void 실패_존재하지않는_데이트일정id를요청하면_예외를반환한다() { // When & Then DatingNotFoundException exception = new DatingNotFoundException(); assertThatThrownBy(() -> - datingService.deleteDating(member, couple.getId(), savedDating.getId() + 100)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - } - - @Test - void 실패_요청한coupleId와_조회한데이트일정의coupleId가다르면_예외를반환한다() { - Member otherMember1 = memberRepository.save(createMember("01012345670", "ccc")); - Member otherMember2 = memberRepository.save(createMember("01012345671", "ddd")); - - Couple other = coupleRepository.save(Couple.builder() - .member1(otherMember1) - .member2(otherMember2) - .firstDate(LocalDate.now()) - .build()); - - Dating otherDating = datingRepository.save(Dating.builder() - .title("otherDating") - .startDateTime(LocalDateTime.now()) - .endDateTime(LocalDateTime.now()) - .couple(other) - .build()); - - NoPermissionException exception = new NoPermissionException(Resource.DATING, - Operation.DELETE); - - assertThatThrownBy(() -> - datingService.deleteDating(member, couple.getId(), otherDating.getId())) + datingService.deleteDating(savedDating.getId() + 100)) .isInstanceOf(exception.getClass()) .hasMessage(exception.getMessage()); } @@ -266,16 +179,14 @@ void tearDown() { @DisplayName("데이트 일정 수정 시") class UpdateDating { - private Member member; - private Couple couple; private Dating savedDating; @BeforeEach void setUp() { - member = memberRepository.save(createMember("01012345678", "aaa")); + Member member = memberRepository.save(createMember("01012345678", "aaa")); Member partner = memberRepository.save(createMember("01012345679", "bbb")); - couple = coupleRepository.save(Couple.builder() + Couple couple = coupleRepository.save(Couple.builder() .member1(member) .member2(partner) .firstDate(LocalDate.now()) @@ -306,7 +217,7 @@ void tearDown() { DatingUpdateServiceRequest request = createDatingUpdateServiceRequest(); // When - datingService.updateDating(member, couple.getId(), savedDating.getId(), request); + datingService.updateDating(savedDating.getId(), request); // Then Dating updatedDating = datingRepository.findById(savedDating.getId()).get(); @@ -317,42 +228,6 @@ void tearDown() { assertThat(updatedDating.getEndDateTime()).isEqualTo(request.getEndDateTime()); } - @Test - void 실패_회원이_연결되어있지않으면_예외를반환한다() { - - // Given - DatingUpdateServiceRequest request = createDatingUpdateServiceRequest(); - Member other = memberRepository.save(createMember("01011112222", "ccc")); - - // When & Then - MemberNotConnectedException exception = new MemberNotConnectedException(); - assertThatThrownBy(() -> datingService.updateDating(other, couple.getId(), - savedDating.getId(), request)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - - then(datingReadService) - .shouldHaveNoInteractions(); - } - - @Test - void 실패_요청한coupleId와_연결된커플의Id가다르면_예외를반환한다() { - - // Given - DatingUpdateServiceRequest request = createDatingUpdateServiceRequest(); - - // When & Then - NoPermissionException exception = new NoPermissionException(Resource.COUPLE, - Operation.UPDATE); - assertThatThrownBy(() -> datingService.updateDating(member, couple.getId() + 100, - savedDating.getId(), request)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - - then(datingReadService) - .shouldHaveNoInteractions(); - } - @Test void 실패_요청에해당하는_데이트일정이존재하지않으면_예외를반환한다() { @@ -361,38 +236,7 @@ void tearDown() { // When & Then DatingNotFoundException exception = new DatingNotFoundException(); - assertThatThrownBy(() -> datingService.updateDating(member, couple.getId(), - savedDating.getId() + 100, request)) - .isInstanceOf(exception.getClass()) - .hasMessage(exception.getMessage()); - } - - @Test - void 실패_요청한coupleId와_조회한데이트일정의coupleId가다르면_예외를반환한다() { - Member otherMember1 = memberRepository.save(createMember("01012345670", "ccc")); - Member otherMember2 = memberRepository.save(createMember("01012345671", "ddd")); - - Couple other = coupleRepository.save(Couple.builder() - .member1(otherMember1) - .member2(otherMember2) - .firstDate(LocalDate.now()) - .build()); - - Dating otherDating = datingRepository.save(Dating.builder() - .title("otherDating") - .startDateTime(LocalDateTime.now()) - .endDateTime(LocalDateTime.now()) - .couple(other) - .build()); - - DatingUpdateServiceRequest request = createDatingUpdateServiceRequest(); - - NoPermissionException exception = new NoPermissionException(Resource.DATING, - Operation.UPDATE); - - assertThatThrownBy(() -> - datingService.updateDating(member, couple.getId(), otherDating.getId(), - request)) + assertThatThrownBy(() -> datingService.updateDating(savedDating.getId() + 100, request)) .isInstanceOf(exception.getClass()) .hasMessage(exception.getMessage()); }