From 3cde27d662c97df130d99f6590c3c8810344ccaf Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 00:38:08 +0900 Subject: [PATCH 01/14] =?UTF-8?q?docs:=20ReadMe.md=201=EC=B0=A8=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 --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..bfad227 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ + +## ModooSpace +스터디룸, 회의실, 연습실, 파티룸, 스튜디오 등 모든 공간을 시간단위로 대여할 수 있는 공간 대여 플랫폼입니다. +> ❗️ 단 호스트의 승인이 있어야 사용이 가능합니다. + +### 프로젝트 목표 +- 국내 [SpaceCloud](https://www.spacecloud.kr/) 같은 공간대여 플랫폼을 구현하였습니다. +- 비즈니스 로직을 객체에게 최대한 위임하여 Service Layer에서 객체가 서로 협력하여 사용자 요청을 수행할 수 있도록 아키텍처를 구성하였습니다. +- 해당 프로젝트에서는 Mock없는 테스트를 지향하며 Domain 단위테스트, Service 통합테스트를 수행하여 TestCoverage 80%를 달성하였습니다. +- 단순 기능만 구현한 것이 아닌, 성능 테스트를 통해 높은 트래픽을 가정한 상황에서도 안정적인 서비스를 유지할 수 있도록 지속적으로 서버 구조를 개선 중입니다. + +### 사용 기술 +스크린샷 2024-03-27 오전 12 19 02 + +### ERD 구조 +스크린샷 2024-03-26 오후 11 10 16 + +### 1차 서버 아키텍처 +![image](https://github.com/f-lab-edu/modoospace/assets/48192141/b8b63d8c-a09b-492f-a825-cd5b981d34e4) + +### 주요 기술 Issue +- [CI/CD를 구축해보자1 - NCP서버 생성 및 Docker로 어플리케이션 배포하기](https://velog.io/@gjwjdghk123/CI-CD1) +- [CI/CD를 구축해보자2 - JaCoCo와 GitHub Actions으로 CI/CD구축해보기](https://velog.io/@gjwjdghk123/CI-CD2) +- [nGrinder를 이용한 성능 테스트 및 성능 개선(ElasticSearch, Redis)](https://velog.io/@gjwjdghk123/nGrinder%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%84%B1%EB%8A%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0ElasticSearch-Redis) +- [ElasticSearch TimeOutException 해결과정](https://velog.io/@gjwjdghk123/ElasticSearch-TimeOutException-%ED%95%B4%EA%B2%B0%EA%B3%BC%EC%A0%95) \ No newline at end of file From 575bd062bf4320fc15cbd04405a51b39a7c8e08e Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 02:56:32 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feature:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?check=20aop=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../config/auth/aop/CheckLogin.java | 11 +++++++ .../config/auth/aop/CheckLoginAspect.java | 29 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/main/java/com/modoospace/config/auth/aop/CheckLogin.java create mode 100644 src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java diff --git a/src/main/java/com/modoospace/config/auth/aop/CheckLogin.java b/src/main/java/com/modoospace/config/auth/aop/CheckLogin.java new file mode 100644 index 0000000..584206b --- /dev/null +++ b/src/main/java/com/modoospace/config/auth/aop/CheckLogin.java @@ -0,0 +1,11 @@ +package com.modoospace.config.auth.aop; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CheckLogin { +} diff --git a/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java b/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java new file mode 100644 index 0000000..b93bc94 --- /dev/null +++ b/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java @@ -0,0 +1,29 @@ +package com.modoospace.config.auth.aop; + +import com.modoospace.common.exception.PermissionDeniedException; +import com.modoospace.config.auth.dto.SessionMember; +import lombok.RequiredArgsConstructor; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; + +import javax.servlet.http.HttpSession; + +@Component +@Aspect +@RequiredArgsConstructor +public class CheckLoginAspect { + + private final HttpSession httpSession; + + @Before("@annotation(com.modoospace.config.auth.aop.CheckLogin)") + public void checkLogin() throws HttpClientErrorException { + + SessionMember member = (SessionMember) httpSession.getAttribute("member"); + + if (member == null) { + throw new PermissionDeniedException(); + } + } +} From 0a352e2a32f2a6fea6ae0ae18bfaa357fadf54c1 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 02:57:53 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feature:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?Memeber=20ArgumentResolver=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Email로 받는 ArgumentResolver는 제거 Related: #64 --- .../auth/LoginEmailArgumentResolver.java | 51 ------------------- .../LoginMember.java} | 4 +- .../resolver/LoginMemberArgumentResolver.java | 45 ++++++++++++++++ 3 files changed, 47 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/com/modoospace/config/auth/LoginEmailArgumentResolver.java rename src/main/java/com/modoospace/config/auth/{LoginEmail.java => resolver/LoginMember.java} (75%) create mode 100644 src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java diff --git a/src/main/java/com/modoospace/config/auth/LoginEmailArgumentResolver.java b/src/main/java/com/modoospace/config/auth/LoginEmailArgumentResolver.java deleted file mode 100644 index 4070902..0000000 --- a/src/main/java/com/modoospace/config/auth/LoginEmailArgumentResolver.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.modoospace.config.auth; - -import com.modoospace.config.auth.dto.SessionMember; -import javax.servlet.http.HttpSession; -import lombok.RequiredArgsConstructor; -import org.springframework.core.MethodParameter; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -@RequiredArgsConstructor -@Component -public class LoginEmailArgumentResolver implements HandlerMethodArgumentResolver { - - private final HttpSession httpSession; - - /** - * 컨트롤러 메서드의 특정 파라미터를 지원하는지 판단 - * - * @param parameter - * @return - */ - @Override - public boolean supportsParameter(MethodParameter parameter) { - boolean isLoginEmailAnnotation = - parameter.getParameterAnnotation(LoginEmail.class) != null; - boolean isStringClass = String.class - .equals(parameter.getParameterType()); - - return isLoginEmailAnnotation && isStringClass; - } - - /** - * 파라미터에 전달할 객체 생성 - * - * @param parameter - * @param mavContainer - * @param webRequest - * @param binderFactory - * @return - * @throws Exception - */ - @Override - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - SessionMember member = (SessionMember) httpSession.getAttribute("member"); - return member == null ? null : member.getEmail(); - } -} diff --git a/src/main/java/com/modoospace/config/auth/LoginEmail.java b/src/main/java/com/modoospace/config/auth/resolver/LoginMember.java similarity index 75% rename from src/main/java/com/modoospace/config/auth/LoginEmail.java rename to src/main/java/com/modoospace/config/auth/resolver/LoginMember.java index 37f2828..07d62ec 100644 --- a/src/main/java/com/modoospace/config/auth/LoginEmail.java +++ b/src/main/java/com/modoospace/config/auth/resolver/LoginMember.java @@ -1,4 +1,4 @@ -package com.modoospace.config.auth; +package com.modoospace.config.auth.resolver; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -7,6 +7,6 @@ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) -public @interface LoginEmail { +public @interface LoginMember { } diff --git a/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java b/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java new file mode 100644 index 0000000..0237c97 --- /dev/null +++ b/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java @@ -0,0 +1,45 @@ +package com.modoospace.config.auth.resolver; + +import com.modoospace.common.exception.PermissionDeniedException; +import com.modoospace.config.auth.dto.SessionMember; +import com.modoospace.member.domain.Member; +import com.modoospace.member.service.MemberService; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpSession; + +@RequiredArgsConstructor +@Component +public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { + + private final HttpSession httpSession; + private final MemberService memberService; + + /** + * 컨트롤러 메서드의 특정 파라미터를 지원하는지 판단 + */ + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(LoginMember.class) && parameter.getParameterType().equals(Member.class); + } + + /** + * 파라미터에 전달할 객체 생성 + */ + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + try { + SessionMember sessionMember = (SessionMember) httpSession.getAttribute("member"); + return memberService.findMemberByEmail(sessionMember.getEmail()); + } catch (RuntimeException e) { + throw new PermissionDeniedException(); + } + } +} From b2fca0b120422f0db713a6b3019ccfa246524bb1 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:00:43 +0900 Subject: [PATCH 04/14] =?UTF-8?q?refactor:=20=EC=95=8C=EB=9E=8C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../alarm/controller/AlarmController.java | 19 ++++++++++++------- .../alarm/service/AlarmService.java | 8 +++----- .../alarm/service/AlarmServiceTest.java | 13 +++++++------ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/modoospace/alarm/controller/AlarmController.java b/src/main/java/com/modoospace/alarm/controller/AlarmController.java index def7257..e9fd280 100644 --- a/src/main/java/com/modoospace/alarm/controller/AlarmController.java +++ b/src/main/java/com/modoospace/alarm/controller/AlarmController.java @@ -3,7 +3,9 @@ import com.modoospace.alarm.controller.dto.AlarmResponse; import com.modoospace.alarm.domain.AlarmType; import com.modoospace.alarm.service.AlarmService; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -18,23 +20,26 @@ public class AlarmController { private final AlarmService alarmService; + @CheckLogin @GetMapping() - public ResponseEntity> search(@LoginEmail String loginEmail, + public ResponseEntity> search(@LoginMember Member loginMember, Pageable pageable) { - Page alarms = alarmService.searchAlarms(loginEmail, pageable); + Page alarms = alarmService.searchAlarms(loginMember, pageable); return ResponseEntity.ok().body(alarms); } + @CheckLogin @DeleteMapping("/{alarmId}") public ResponseEntity delete(@PathVariable Long alarmId, - @LoginEmail String loginEmail) { - alarmService.delete(alarmId, loginEmail); + @LoginMember Member loginMember) { + alarmService.delete(alarmId, loginMember); return ResponseEntity.noContent().build(); } + @CheckLogin @GetMapping(value = "/subscribe", produces = "text/event-stream") - public ResponseEntity subscribe(@LoginEmail String loginEmail) { - return ResponseEntity.ok(alarmService.connectAlarm(loginEmail)); + public ResponseEntity subscribe(@LoginMember Member loginMember) { + return ResponseEntity.ok(alarmService.connectAlarm(loginMember.getEmail())); } @PostMapping(value = "/send/{email}") diff --git a/src/main/java/com/modoospace/alarm/service/AlarmService.java b/src/main/java/com/modoospace/alarm/service/AlarmService.java index 4bfd504..f53e92e 100644 --- a/src/main/java/com/modoospace/alarm/service/AlarmService.java +++ b/src/main/java/com/modoospace/alarm/service/AlarmService.java @@ -35,8 +35,7 @@ public class AlarmService { private final AlarmQueryRepository alarmQueryRepository; private final EmitterLocalCacheRepository emitterRepository; - public Page searchAlarms(String loginEmail, Pageable pageable) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + public Page searchAlarms(Member loginMember, Pageable pageable) { return alarmQueryRepository.searchByMember(loginMember, pageable); } @@ -80,9 +79,8 @@ private void sendToClient(SseEmitter emitter, String email, Object data) { } @Transactional - @CachePrefixEvict(cacheNames = "searchAlarms", key = "#loginEmail") - public void delete(Long alarmId, String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + @CachePrefixEvict(cacheNames = "searchAlarms", key = "#loginMember.email") + public void delete(Long alarmId, Member loginMember) { Alarm alarm = findAlarmById(alarmId); alarm.verifyManagementPermission(loginMember); diff --git a/src/test/java/com/modoospace/alarm/service/AlarmServiceTest.java b/src/test/java/com/modoospace/alarm/service/AlarmServiceTest.java index db2b805..7f16cf5 100644 --- a/src/test/java/com/modoospace/alarm/service/AlarmServiceTest.java +++ b/src/test/java/com/modoospace/alarm/service/AlarmServiceTest.java @@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import java.util.Objects; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -53,7 +54,7 @@ public void setUp() { .role(Role.HOST) .build(); - memberRepository.save(hostMember); + hostMember = memberRepository.save(hostMember); for (int i = 0; i < 10; i++) { AlarmEvent testEvent = AlarmEvent.builder() @@ -68,14 +69,14 @@ public void setUp() { @AfterEach public void after() { - redisTemplate.getConnectionFactory().getConnection().flushAll(); + Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection().flushAll(); } @DisplayName("알람을 검색하면, searchAlarms::이메일:페이지넘버를 키값으로 결과가 캐싱된다.") @Test public void searchAlarms_redisSave() { PageRequest pageRequest = PageRequest.of(0, 10); - alarmService.searchAlarms("host@email", pageRequest); + alarmService.searchAlarms(hostMember, pageRequest); String pattern = "searchAlarms::" + hostMember.getEmail() + ":*"; Set keys = redisTemplate.keys(pattern); @@ -97,7 +98,7 @@ public void connectAlarm_saveSseEmitterByEmail() { @Test public void saveAndSend_EmptyRedisKeys() { PageRequest pageRequest = PageRequest.of(0, 10); - alarmService.searchAlarms("host@email", pageRequest); + alarmService.searchAlarms(hostMember, pageRequest); AlarmEvent testEvent = AlarmEvent.builder() .email(hostMember.getEmail()) .reservationId(1L) @@ -116,9 +117,9 @@ public void saveAndSend_EmptyRedisKeys() { @Test public void deleteAlarm_EmptyRedisKeys() { PageRequest pageRequest = PageRequest.of(0, 10); - alarmService.searchAlarms("host@email", pageRequest); + alarmService.searchAlarms(hostMember, pageRequest); - alarmService.delete(alarm.getId(), "host@email"); + alarmService.delete(alarm.getId(), hostMember); String pattern = "searchAlarms::" + hostMember.getEmail() + ":*"; Set keys = redisTemplate.keys(pattern); From 57783d5eff4ba209e3272649f9f63cad99a886d0 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:01:29 +0900 Subject: [PATCH 05/14] =?UTF-8?q?refactor:=20Facility=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../space/controller/FacilityController.java | 56 +++++++++---------- .../space/sevice/FacilityService.java | 16 ++---- .../space/sevice/FacilityServiceTest.java | 14 ++--- 3 files changed, 38 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/modoospace/space/controller/FacilityController.java b/src/main/java/com/modoospace/space/controller/FacilityController.java index e6e401e..ff8f64f 100644 --- a/src/main/java/com/modoospace/space/controller/FacilityController.java +++ b/src/main/java/com/modoospace/space/controller/FacilityController.java @@ -1,26 +1,18 @@ package com.modoospace.space.controller; -import com.modoospace.config.auth.LoginEmail; -import com.modoospace.space.controller.dto.facility.FacilityCreateRequest; -import com.modoospace.space.controller.dto.facility.FacilityResponse; -import com.modoospace.space.controller.dto.facility.FacilitySearchRequest; -import com.modoospace.space.controller.dto.facility.FacilitySettingUpdateRequest; -import com.modoospace.space.controller.dto.facility.FacilityUpdateRequest; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; +import com.modoospace.space.controller.dto.facility.*; import com.modoospace.space.sevice.FacilityService; -import java.net.URI; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -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 org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; @RequiredArgsConstructor @RestController @@ -29,20 +21,21 @@ public class FacilityController { private final FacilityService facilityService; + @CheckLogin @PostMapping() public ResponseEntity create(@PathVariable Long spaceId, - @RequestBody @Valid FacilityCreateRequest createRequest, - @LoginEmail String loginEmail) { - Long facilityId = facilityService.createFacility(spaceId, createRequest, loginEmail); + @RequestBody @Valid FacilityCreateRequest createRequest, + @LoginMember Member loginMember) { + Long facilityId = facilityService.createFacility(spaceId, createRequest, loginMember); return ResponseEntity - .created(URI.create("/api/v1/spaces/" + spaceId + "/facilities/" + facilityId)).build(); + .created(URI.create("/api/v1/spaces/" + spaceId + "/facilities/" + facilityId)).build(); } @GetMapping() public ResponseEntity> search(@PathVariable Long spaceId, - FacilitySearchRequest searchRequest, Pageable pageable) { + FacilitySearchRequest searchRequest, Pageable pageable) { Page facilityResponses = facilityService - .searchFacility(spaceId, searchRequest, pageable); + .searchFacility(spaceId, searchRequest, pageable); return ResponseEntity.ok().body(facilityResponses); } @@ -52,26 +45,29 @@ public ResponseEntity find(@PathVariable Long facilityId) { return ResponseEntity.ok().body(facilityReadDto); } + @CheckLogin @PutMapping("/{facilityId}") public ResponseEntity update(@PathVariable Long facilityId, - @RequestBody @Valid FacilityUpdateRequest updateRequest, - @LoginEmail String loginEmail) { - facilityService.updateFacility(facilityId, updateRequest, loginEmail); + @RequestBody @Valid FacilityUpdateRequest updateRequest, + @LoginMember Member loginMember) { + facilityService.updateFacility(facilityId, updateRequest, loginMember); return ResponseEntity.noContent().build(); } + @CheckLogin @PutMapping("/{facilityId}/setting") public ResponseEntity updateSetting(@PathVariable Long facilityId, - @RequestBody @Valid FacilitySettingUpdateRequest updateRequest, - @LoginEmail String loginEmail) { - facilityService.updateFacilitySetting(facilityId, updateRequest, loginEmail); + @RequestBody @Valid FacilitySettingUpdateRequest updateRequest, + @LoginMember Member loginMember) { + facilityService.updateFacilitySetting(facilityId, updateRequest, loginMember); return ResponseEntity.noContent().build(); } + @CheckLogin @DeleteMapping("/{facilityId}") public ResponseEntity delete(@PathVariable Long facilityId, - @LoginEmail String loginEmail) { - facilityService.deleteFacility(facilityId, loginEmail); + @LoginMember Member loginMember) { + facilityService.deleteFacility(facilityId, loginMember); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/modoospace/space/sevice/FacilityService.java b/src/main/java/com/modoospace/space/sevice/FacilityService.java index 4261091..94d2a8c 100644 --- a/src/main/java/com/modoospace/space/sevice/FacilityService.java +++ b/src/main/java/com/modoospace/space/sevice/FacilityService.java @@ -2,7 +2,6 @@ import com.modoospace.common.exception.NotFoundEntityException; import com.modoospace.member.domain.Member; -import com.modoospace.member.service.MemberService; import com.modoospace.space.controller.dto.facility.*; import com.modoospace.space.domain.Facility; import com.modoospace.space.domain.FacilityRepository; @@ -19,8 +18,7 @@ @RequiredArgsConstructor @Service public class FacilityService { - - private final MemberService memberService; +¬ private final SpaceRepository spaceRepository; private final FacilityRepository facilityRepository; private final ScheduleQueryRepository scheduleQueryRepository; @@ -28,8 +26,7 @@ public class FacilityService { @Transactional public Long createFacility(Long spaceId, FacilityCreateRequest createRequest, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Space space = findSpaceById(spaceId); space.verifyManagementPermission(loginMember); @@ -54,8 +51,7 @@ public FacilityResponse findFacility(Long facilityId) { @Transactional public void updateFacility(Long facilityId, FacilityUpdateRequest updateRequest, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Facility facility = findFacilityById(facilityId); facility.verifyManagementPermission(loginMember); @@ -65,8 +61,7 @@ public void updateFacility(Long facilityId, FacilityUpdateRequest updateRequest, @Transactional public void updateFacilitySetting(Long facilityId, FacilitySettingUpdateRequest updateRequest, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Facility facility = findFacilityById(facilityId); facility.verifyManagementPermission(loginMember); @@ -75,8 +70,7 @@ public void updateFacilitySetting(Long facilityId, FacilitySettingUpdateRequest } @Transactional - public void deleteFacility(Long facilityId, String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + public void deleteFacility(Long facilityId, Member loginMember) { Facility facility = findFacilityById(facilityId); facility.verifyManagementPermission(loginMember); diff --git a/src/test/java/com/modoospace/space/sevice/FacilityServiceTest.java b/src/test/java/com/modoospace/space/sevice/FacilityServiceTest.java index 9180618..17663bb 100644 --- a/src/test/java/com/modoospace/space/sevice/FacilityServiceTest.java +++ b/src/test/java/com/modoospace/space/sevice/FacilityServiceTest.java @@ -62,7 +62,7 @@ public void setUp() { .name("host") .role(Role.HOST) .build(); - memberRepository.save(hostMember); + hostMember = memberRepository.save(hostMember); Category category = new Category("스터디 공간"); categoryRepository.save(category); @@ -89,7 +89,7 @@ public void setUp() { public void createFacility_24HourOpen_ifNotSelectSetting() { FacilityCreateRequest createRequest = createFacility(true); Long facilityId = facilityService - .createFacility(space.getId(), createRequest, hostMember.getEmail()); + .createFacility(space.getId(), createRequest, hostMember); Facility facility = facilityRepository.findById(facilityId).get(); @@ -131,7 +131,7 @@ public void createFacility() { weekdaySettings); Long facilityId = facilityService - .createFacility(space.getId(), createRequest, hostMember.getEmail()); + .createFacility(space.getId(), createRequest, hostMember); Facility facility = facilityRepository.findById(facilityId).get(); assertThat(facility.getId()).isEqualTo(facilityId); @@ -169,7 +169,7 @@ private FacilityCreateRequest createFacilityWithSetting(Boolean enable, public void updateFacility() { FacilityCreateRequest createRequest = createFacility(false); Long facilityId = facilityService - .createFacility(space.getId(), createRequest, hostMember.getEmail()); + .createFacility(space.getId(), createRequest, hostMember); FacilityUpdateRequest updateRequest = FacilityUpdateRequest.builder() .name("스터디룸2") .reservationEnable(true) @@ -179,7 +179,7 @@ public void updateFacility() { .build(); facilityService - .updateFacility(facilityId, updateRequest, hostMember.getEmail()); + .updateFacility(facilityId, updateRequest, hostMember); Facility facility = facilityRepository.findById(facilityId).get(); assertThatFacilityInfo(facility, updateRequest); @@ -201,7 +201,7 @@ private void assertThatFacilityInfo(Facility facility, FacilityUpdateRequest req public void updateFacilitySetting() { // 1. 데이터 생성 Transaction(Commit) Long facilityId = facilityService - .createFacility(space.getId(), createFacility(true), hostMember.getEmail()); + .createFacility(space.getId(), createFacility(true), hostMember); TestTransaction.flagForCommit(); TestTransaction.end(); @@ -225,7 +225,7 @@ private void updateFacilitySetting(Long facilityId) { DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY) ); - facilityService.updateFacilitySetting(facilityId, updateRequest, hostMember.getEmail()); + facilityService.updateFacilitySetting(facilityId, updateRequest, hostMember); } private void assertThatSchedules(Long facilityId) { From ee7767ec20619718873f2d8d72d13895b797928a Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:08:30 +0900 Subject: [PATCH 06/14] =?UTF-8?q?refactor:=20Member=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../java/com/modoospace/MainController.java | 17 ++++++++++------- .../controller/AdminMemberController.java | 9 ++++++--- .../member/service/MemberService.java | 6 ++---- .../space/sevice/FacilityService.java | 2 +- .../member/service/MemberServiceTest.java | 19 +++++++++++-------- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/modoospace/MainController.java b/src/main/java/com/modoospace/MainController.java index 8016715..1fb6640 100644 --- a/src/main/java/com/modoospace/MainController.java +++ b/src/main/java/com/modoospace/MainController.java @@ -1,20 +1,23 @@ package com.modoospace; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.dto.SessionMember; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import javax.servlet.http.HttpSession; + @RequiredArgsConstructor @Controller public class MainController { - @GetMapping({"", "/"}) - public String index(Model model, @LoginEmail String loginEmail) { - if (loginEmail != null) { - model.addAttribute("userName", loginEmail); + @GetMapping({"", "/"}) + public String index(Model model, HttpSession session) { + SessionMember member = (SessionMember) session.getAttribute("member"); + if (member != null) { + model.addAttribute("userName", member.getEmail()); + } + return "index"; } - return "index"; - } } diff --git a/src/main/java/com/modoospace/member/controller/AdminMemberController.java b/src/main/java/com/modoospace/member/controller/AdminMemberController.java index 773ac3e..4b947a9 100644 --- a/src/main/java/com/modoospace/member/controller/AdminMemberController.java +++ b/src/main/java/com/modoospace/member/controller/AdminMemberController.java @@ -1,7 +1,9 @@ package com.modoospace.member.controller; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; import com.modoospace.member.controller.dto.MemberUpdateRequest; +import com.modoospace.member.domain.Member; import com.modoospace.member.service.MemberService; import javax.validation.Valid; import lombok.RequiredArgsConstructor; @@ -19,11 +21,12 @@ public class AdminMemberController { private final MemberService memberService; + @CheckLogin @PutMapping("/{memberId}") public ResponseEntity updateRole(@PathVariable Long memberId, @RequestBody @Valid MemberUpdateRequest updateRequest, - @LoginEmail String loginEmail) { - memberService.updateMemberRole(memberId, updateRequest, loginEmail); + @LoginMember Member member) { + memberService.updateMemberRole(memberId, updateRequest, member); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/modoospace/member/service/MemberService.java b/src/main/java/com/modoospace/member/service/MemberService.java index 82f16b5..6f7c02f 100644 --- a/src/main/java/com/modoospace/member/service/MemberService.java +++ b/src/main/java/com/modoospace/member/service/MemberService.java @@ -17,8 +17,7 @@ public class MemberService { private final MemberCacheRepository memberCacheRepository; @Transactional - public void updateMemberRole(Long memberId, MemberUpdateRequest updateRequest, String loginEmail) { - Member loginMember = findMemberByEmail(loginEmail); + public void updateMemberRole(Long memberId, MemberUpdateRequest updateRequest, Member loginMember) { Member member = findMemberById(memberId); member.updateRoleOnlyAdmin(updateRequest.getRole(), loginMember); @@ -34,8 +33,7 @@ public Member findMemberByEmail(String email) { } public Member findMemberById(Long id) { - Member member = memberRepository.findById(id) + return memberRepository.findById(id) .orElseThrow(() -> new NotFoundEntityException("사용자", id)); - return member; } } diff --git a/src/main/java/com/modoospace/space/sevice/FacilityService.java b/src/main/java/com/modoospace/space/sevice/FacilityService.java index 94d2a8c..7adbe65 100644 --- a/src/main/java/com/modoospace/space/sevice/FacilityService.java +++ b/src/main/java/com/modoospace/space/sevice/FacilityService.java @@ -18,7 +18,7 @@ @RequiredArgsConstructor @Service public class FacilityService { -¬ + private final SpaceRepository spaceRepository; private final FacilityRepository facilityRepository; private final ScheduleQueryRepository scheduleQueryRepository; diff --git a/src/test/java/com/modoospace/member/service/MemberServiceTest.java b/src/test/java/com/modoospace/member/service/MemberServiceTest.java index 2c50b13..b5f283c 100644 --- a/src/test/java/com/modoospace/member/service/MemberServiceTest.java +++ b/src/test/java/com/modoospace/member/service/MemberServiceTest.java @@ -14,6 +14,8 @@ import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.transaction.annotation.Transactional; +import java.util.Objects; + import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; @@ -29,12 +31,13 @@ class MemberServiceTest extends AbstractIntegrationContainerBaseTest { @Autowired private StringRedisTemplate redisTemplate; + private Member adminMember; private Member hostMember; private Member visitorMember; @BeforeEach public void setUp() { - Member adminMember = Member.builder() + adminMember = Member.builder() .email("admin@email") .name("admin") .role(Role.ADMIN) @@ -52,14 +55,14 @@ public void setUp() { .role(Role.VISITOR) .build(); - memberRepository.save(adminMember); - memberRepository.save(hostMember); - memberRepository.save(visitorMember); + adminMember = memberRepository.save(adminMember); + hostMember = memberRepository.save(hostMember); + visitorMember = memberRepository.save(visitorMember); } @AfterEach public void after() { - redisTemplate.getConnectionFactory().getConnection().flushAll(); + Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection().flushAll(); } @DisplayName("Visitor 사용자를 Host로 변경한디.") @@ -69,7 +72,7 @@ public void updateMemberRole() { .role(Role.HOST) .build(); - memberService.updateMemberRole(visitorMember.getId(), updateRequest, "admin@email"); + memberService.updateMemberRole(visitorMember.getId(), updateRequest, adminMember); Member updateMember = memberRepository.findByEmail("visitor@email").get(); updateMember.verifyRolePermission(Role.HOST); @@ -84,10 +87,10 @@ public void updateMemberRole_throwException_ifNotAdmin() { assertAll( () -> assertThatThrownBy( - () -> memberService.updateMemberRole(visitorMember.getId(), updateRequest, "visitor@email")) + () -> memberService.updateMemberRole(visitorMember.getId(), updateRequest, visitorMember)) .isInstanceOf(PermissionDeniedException.class), () -> assertThatThrownBy( - () -> memberService.updateMemberRole(hostMember.getId(), updateRequest, "host@email")) + () -> memberService.updateMemberRole(hostMember.getId(), updateRequest, hostMember)) .isInstanceOf(PermissionDeniedException.class) ); } From 055b65f5971e7537fd9046bff120788b7af62446 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:08:52 +0900 Subject: [PATCH 07/14] =?UTF-8?q?refactor:=20Reservation=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../AdminReservationController.java | 40 ++++----- .../controller/HostReservationController.java | 41 ++++----- .../VisitorsReservationController.java | 48 +++++------ .../serivce/ReservationService.java | 84 +++++++------------ .../service/ReservationServiceTest.java | 48 +++++------ 5 files changed, 121 insertions(+), 140 deletions(-) diff --git a/src/main/java/com/modoospace/reservation/controller/AdminReservationController.java b/src/main/java/com/modoospace/reservation/controller/AdminReservationController.java index 1abb458..e62533d 100644 --- a/src/main/java/com/modoospace/reservation/controller/AdminReservationController.java +++ b/src/main/java/com/modoospace/reservation/controller/AdminReservationController.java @@ -1,19 +1,17 @@ package com.modoospace.reservation.controller; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import com.modoospace.reservation.controller.dto.ReservationResponse; import com.modoospace.reservation.controller.dto.ReservationUpdateRequest; import com.modoospace.reservation.serivce.ReservationService; -import java.util.List; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -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 org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; @RequiredArgsConstructor @RestController @@ -22,37 +20,41 @@ public class AdminReservationController { private final ReservationService reservationService; + @CheckLogin @GetMapping("/visitor/{memberId}") public ResponseEntity> findAllAsMember(@PathVariable Long memberId, - @LoginEmail final String loginEmail) { + @LoginMember Member loginMember) { List reservations = reservationService - .findAllAsVisitorByAdmin(memberId, loginEmail); + .findAllAsVisitorByAdmin(memberId, loginMember); return ResponseEntity.ok().body(reservations); } + @CheckLogin @GetMapping("/host/{memberId}") public ResponseEntity> findAllAsHost(@PathVariable Long memberId, - @LoginEmail final String loginEmail) { + @LoginMember Member loginMember) { List reservations = reservationService - .findAllAsHostByAdmin(memberId, loginEmail); + .findAllAsHostByAdmin(memberId, loginMember); return ResponseEntity.ok().body(reservations); } + @CheckLogin @PutMapping("/{reservationId}") public ResponseEntity update( - @PathVariable Long reservationId, - @RequestBody @Valid ReservationUpdateRequest updateRequest, - @LoginEmail String loginEmail) { + @PathVariable Long reservationId, + @RequestBody @Valid ReservationUpdateRequest updateRequest, + @LoginMember Member loginMember) { - reservationService.updateReservation(reservationId, updateRequest, loginEmail); + reservationService.updateReservation(reservationId, updateRequest, loginMember); return ResponseEntity.ok().build(); } + @CheckLogin @GetMapping("/{reservationId}") public ResponseEntity find(@PathVariable Long reservationId, - @LoginEmail final String loginEmail) { + @LoginMember Member loginMember) { ReservationResponse reservation = reservationService - .findReservation(reservationId, loginEmail); + .findReservation(reservationId, loginMember); return ResponseEntity.ok().body(reservation); } } diff --git a/src/main/java/com/modoospace/reservation/controller/HostReservationController.java b/src/main/java/com/modoospace/reservation/controller/HostReservationController.java index a2e8009..468bbf8 100644 --- a/src/main/java/com/modoospace/reservation/controller/HostReservationController.java +++ b/src/main/java/com/modoospace/reservation/controller/HostReservationController.java @@ -1,19 +1,17 @@ package com.modoospace.reservation.controller; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import com.modoospace.reservation.controller.dto.ReservationResponse; import com.modoospace.reservation.controller.dto.ReservationUpdateRequest; import com.modoospace.reservation.serivce.ReservationService; -import java.util.List; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -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 org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; @RequiredArgsConstructor @RestController @@ -22,34 +20,37 @@ public class HostReservationController { private final ReservationService reservationService; + @CheckLogin @GetMapping - public ResponseEntity> findAll(@LoginEmail final String loginEmail) { - List reservations = reservationService.findAllAsHost(loginEmail); + public ResponseEntity> findAll(@LoginMember Member loginMember) { + List reservations = reservationService.findAllAsHost(loginMember); return ResponseEntity.ok().body(reservations); } + @CheckLogin @PutMapping("/{reservationId}/approve") public ResponseEntity approveReservation(@PathVariable Long reservationId, - @LoginEmail final String loginEmail) { - reservationService.approveReservation(reservationId, loginEmail); + @LoginMember Member loginMember) { + reservationService.approveReservation(reservationId, loginMember); return ResponseEntity.noContent().build(); } + @CheckLogin @PutMapping("/{reservationId}") public ResponseEntity update( - @PathVariable Long reservationId, - @RequestBody @Valid ReservationUpdateRequest updateRequest, - @LoginEmail String loginEmail) { + @PathVariable Long reservationId, + @RequestBody @Valid ReservationUpdateRequest updateRequest, + @LoginMember Member loginMember) { - reservationService.updateReservation(reservationId, updateRequest, loginEmail); + reservationService.updateReservation(reservationId, updateRequest, loginMember); return ResponseEntity.ok().build(); } + @CheckLogin @GetMapping("/{reservationId}") public ResponseEntity find(@PathVariable Long reservationId, - @LoginEmail String loginEmail) { - ReservationResponse reservation = reservationService - .findReservation(reservationId, loginEmail); + @LoginMember Member loginMember) { + ReservationResponse reservation = reservationService.findReservation(reservationId, loginMember); return ResponseEntity.ok().body(reservation); } } diff --git a/src/main/java/com/modoospace/reservation/controller/VisitorsReservationController.java b/src/main/java/com/modoospace/reservation/controller/VisitorsReservationController.java index 2a73d54..5cbd0cc 100644 --- a/src/main/java/com/modoospace/reservation/controller/VisitorsReservationController.java +++ b/src/main/java/com/modoospace/reservation/controller/VisitorsReservationController.java @@ -1,25 +1,21 @@ package com.modoospace.reservation.controller; import com.modoospace.common.DateFormatManager; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import com.modoospace.reservation.controller.dto.AvailabilityTimeResponse; import com.modoospace.reservation.controller.dto.ReservationCreateRequest; import com.modoospace.reservation.controller.dto.ReservationResponse; import com.modoospace.reservation.serivce.ReservationService; -import java.time.LocalDate; -import java.util.List; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -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 org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.time.LocalDate; +import java.util.List; @RequiredArgsConstructor @RestController @@ -28,42 +24,46 @@ public class VisitorsReservationController { private final ReservationService reservationService; + @CheckLogin @GetMapping - public ResponseEntity> findAll(@LoginEmail final String loginEmail) { - List reservations = reservationService.findAllAsVisitor(loginEmail); + public ResponseEntity> findAll(@LoginMember Member loginMember) { + List reservations = reservationService.findAllAsVisitor(loginMember); return ResponseEntity.ok().body(reservations); } @GetMapping("/facilities/{facilityId}/availability") public ResponseEntity getAvailabilityTime( - @PathVariable Long facilityId, - @RequestParam @DateTimeFormat(pattern = DateFormatManager.DATE_FORMAT) final LocalDate date) { + @PathVariable Long facilityId, + @RequestParam @DateTimeFormat(pattern = DateFormatManager.DATE_FORMAT) final LocalDate date) { AvailabilityTimeResponse availableTimes = reservationService - .getAvailabilityTime(facilityId, date); + .getAvailabilityTime(facilityId, date); return ResponseEntity.ok().body(availableTimes); } + @CheckLogin @PostMapping("/facilities/{facilityId}") public ResponseEntity createReservation(@PathVariable Long facilityId, - @LoginEmail String loginEmail, - @RequestBody @Valid ReservationCreateRequest createRequest) { + @LoginMember Member loginMember, + @RequestBody @Valid ReservationCreateRequest createRequest) { Long reservationId = reservationService.createReservation( - createRequest, facilityId, loginEmail); + createRequest, facilityId, loginMember); return ResponseEntity.ok().body(reservationId); } + @CheckLogin @GetMapping("/{reservationId}") public ResponseEntity find(@PathVariable Long reservationId, - @LoginEmail String loginEmail) { + @LoginMember Member loginMember) { ReservationResponse reservation = reservationService.findReservation( - reservationId, loginEmail); + reservationId, loginMember); return ResponseEntity.ok().body(reservation); } + @CheckLogin @PutMapping("/{reservationId}/cancel") public ResponseEntity cancelReservation(@PathVariable Long reservationId, - @LoginEmail String loginEmail) { - reservationService.cancelReservation(reservationId, loginEmail); + @LoginMember Member loginMember) { + reservationService.cancelReservation(reservationId, loginMember); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/modoospace/reservation/serivce/ReservationService.java b/src/main/java/com/modoospace/reservation/serivce/ReservationService.java index 2e00790..28f5fde 100644 --- a/src/main/java/com/modoospace/reservation/serivce/ReservationService.java +++ b/src/main/java/com/modoospace/reservation/serivce/ReservationService.java @@ -8,11 +8,7 @@ import com.modoospace.member.domain.Member; import com.modoospace.member.domain.Role; import com.modoospace.member.service.MemberService; -import com.modoospace.reservation.controller.dto.AvailabilityTimeResponse; -import com.modoospace.reservation.controller.dto.ReservationCreateRequest; -import com.modoospace.reservation.controller.dto.ReservationResponse; -import com.modoospace.reservation.controller.dto.ReservationUpdateRequest; -import com.modoospace.reservation.controller.dto.TimeResponse; +import com.modoospace.reservation.controller.dto.*; import com.modoospace.reservation.domain.Reservation; import com.modoospace.reservation.domain.ReservationRepository; import com.modoospace.reservation.repository.ReservationQueryRepository; @@ -22,13 +18,14 @@ import com.modoospace.space.domain.Schedule; import com.modoospace.space.domain.ScheduleRepository; import com.modoospace.space.repository.ScheduleQueryRepository; -import java.time.LocalDate; -import java.util.List; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Collectors; + @RequiredArgsConstructor @Service public class ReservationService { @@ -43,10 +40,9 @@ public class ReservationService { @Transactional public Long createReservation(ReservationCreateRequest createRequest, Long facilityId, - String loginEmail) { - Member visitor = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Facility facility = findFacilityById(facilityId); - Reservation reservation = createRequest.toEntity(facility, visitor); + Reservation reservation = createRequest.toEntity(facility, loginMember); verifyAvailability(facility, reservation); reservationRepository.save(reservation); @@ -65,7 +61,7 @@ private void verifyAvailability(Facility facility, Reservation reservation) { private void verifyFacilitySchedulesOpen(Facility facility, Reservation reservation) { Boolean isSchedulesOpen = scheduleQueryRepository.isIncludingSchedule( - facility, reservation.getDateTimeRange()); + facility, reservation.getDateTimeRange()); if (!isSchedulesOpen) { throw new NotOpenedFacilityException(); @@ -74,7 +70,7 @@ private void verifyFacilitySchedulesOpen(Facility facility, Reservation reservat private void verifyReservationAvailability(Facility facility, Reservation reservation) { Boolean conflictingReservation = reservationQueryRepository.isConflictingReservation( - facility, reservation.getDateTimeRange()); + facility, reservation.getDateTimeRange()); if (conflictingReservation) { throw new ConflictingReservationException(); @@ -85,25 +81,23 @@ public AvailabilityTimeResponse getAvailabilityTime(Long facilityId, LocalDate s Facility facility = findFacilityById(facilityId); List schedules = scheduleRepository.findByFacilityAndDate(facility, searchDate); List reservations = reservationQueryRepository.findActiveReservations(facility, - searchDate); + searchDate); List timeResponse = TimeResponse.createTimeResponse(schedules, reservations, - searchDate); + searchDate); return new AvailabilityTimeResponse(FacilityResponse.of(facility), timeResponse); } - public ReservationResponse findReservation(Long reservationId, String loginEmail) { + public ReservationResponse findReservation(Long reservationId, Member loginMember) { Reservation reservation = findReservationById(reservationId); - Member loginMember = memberService.findMemberByEmail(loginEmail); reservation.verifyReservationAccess(loginMember); return ReservationResponse.of(reservation); } @Transactional - public void approveReservation(Long reservationId, String loginEmail) { + public void approveReservation(Long reservationId, Member loginMember) { Reservation reservation = findReservationById(reservationId); - Member loginMember = memberService.findMemberByEmail(loginEmail); reservation.approveAsHost(loginMember); AlarmEvent alarmEvent = AlarmEvent.ofApprovedReservationAlarm(reservation); @@ -112,63 +106,47 @@ public void approveReservation(Long reservationId, String loginEmail) { @Transactional public void updateReservation(Long reservationId, ReservationUpdateRequest updateRequest, - String loginEmail) { + Member loginMember) { Reservation reservation = findReservationById(reservationId); - Member loginMember = memberService.findMemberByEmail(loginEmail); Reservation updatedReservation = updateRequest.toEntity(reservation); reservation.updateAsHost(updatedReservation, loginMember); } - public List findAllAsVisitorByAdmin(Long memberId, String loginEmail) { - Member admin = memberService.findMemberByEmail(loginEmail); - admin.verifyRolePermission(Role.ADMIN); + public List findAllAsVisitorByAdmin(Long memberId, Member loginMember) { + loginMember.verifyRolePermission(Role.ADMIN); Member visitor = memberService.findMemberById(memberId); return findAllAsVisitor(visitor); } - public List findAllAsVisitor(String loginEmail) { - Member visitor = memberService.findMemberByEmail(loginEmail); - visitor.verifyRolePermission(Role.VISITOR); - - return findAllAsVisitor(visitor); - } - - private List findAllAsVisitor(Member visitor) { - List reservations = reservationRepository.findByVisitor(visitor); + public List findAllAsVisitor(Member loginMember) { + loginMember.verifyRolePermission(Role.VISITOR); + List reservations = reservationRepository.findByVisitor(loginMember); return reservations.stream() - .map(ReservationResponse::of) - .collect(Collectors.toList()); + .map(ReservationResponse::of) + .collect(Collectors.toList()); } - public List findAllAsHostByAdmin(Long memberId, String loginEmail) { - Member admin = memberService.findMemberByEmail(loginEmail); - admin.verifyRolePermission(Role.ADMIN); + public List findAllAsHostByAdmin(Long memberId, Member loginMember) { + loginMember.verifyRolePermission(Role.ADMIN); Member host = memberService.findMemberById(memberId); return findAllAsHost(host); } - public List findAllAsHost(String loginEmail) { - Member host = memberService.findMemberByEmail(loginEmail); - host.verifyRolePermission(Role.HOST); - - return findAllAsHost(host); - } - - private List findAllAsHost(Member host) { - List reservations = reservationRepository.findByFacilitySpaceHost(host); + public List findAllAsHost(Member loginMember) { + loginMember.verifyRolePermission(Role.HOST); + List reservations = reservationRepository.findByFacilitySpaceHost(loginMember); return reservations.stream() - .map(ReservationResponse::of) - .collect(Collectors.toList()); + .map(ReservationResponse::of) + .collect(Collectors.toList()); } @Transactional - public void cancelReservation(Long reservationId, String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + public void cancelReservation(Long reservationId, Member loginMember) { Reservation reservation = findReservationById(reservationId); reservation.cancelAsVisitor(loginMember); @@ -178,11 +156,11 @@ public void cancelReservation(Long reservationId, String loginEmail) { private Reservation findReservationById(Long reservationId) { return reservationRepository.findById(reservationId) - .orElseThrow(() -> new NotFoundEntityException("예약", reservationId)); + .orElseThrow(() -> new NotFoundEntityException("예약", reservationId)); } private Facility findFacilityById(Long facilityId) { return facilityRepository.findById(facilityId) - .orElseThrow(() -> new NotFoundEntityException("시설", facilityId)); + .orElseThrow(() -> new NotFoundEntityException("시설", facilityId)); } } diff --git a/src/test/java/com/modoospace/reservation/service/ReservationServiceTest.java b/src/test/java/com/modoospace/reservation/service/ReservationServiceTest.java index 545f117..45c5b25 100644 --- a/src/test/java/com/modoospace/reservation/service/ReservationServiceTest.java +++ b/src/test/java/com/modoospace/reservation/service/ReservationServiceTest.java @@ -92,14 +92,14 @@ public void setUp() { .name("host") .role(Role.HOST) .build(); - memberRepository.save(hostMember); + hostMember = memberRepository.save(hostMember); visitorMember = Member.builder() .email("visitor@email") .name("visitor") .role(Role.VISITOR) .build(); - memberRepository.save(visitorMember); + visitorMember = memberRepository.save(visitorMember); Category category = new Category("스터디 공간"); categoryRepository.save(category); @@ -152,10 +152,10 @@ public void createReservation_IfVisitor() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 18, now, 21); Long reservationId = reservationService.createReservation(createRequest, facilityOpen9Close24.getId(), - visitorMember.getEmail()); + visitorMember); ReservationResponse retResponse = reservationService.findReservation(reservationId, - visitorMember.getEmail()); + visitorMember); assertAll( () -> assertThat(retResponse.getId()).isEqualTo(reservationId), () -> assertThat(retResponse.getFacility().getId()).isEqualTo(facilityOpen9Close24.getId()), @@ -169,11 +169,11 @@ public void createReservation_IfVisitor() { public void createReservationRoom_throwException_ifOverlappingReservation() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); reservationService.createReservation(createRequest, facilityOpen9Close24.getId(), - visitorMember.getEmail()); + visitorMember); ReservationCreateRequest createRequest2 = new ReservationCreateRequest(3, now, 13, now, 15); assertThatThrownBy(() -> reservationService - .createReservation(createRequest2, facilityOpen9Close24.getId(), visitorMember.getEmail())) + .createReservation(createRequest2, facilityOpen9Close24.getId(), visitorMember)) .isInstanceOf(ConflictingReservationException.class); } @@ -182,7 +182,7 @@ public void createReservationRoom_throwException_ifOverlappingReservation() { public void createReservationRoom_throwException_ifNotAvailable() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); assertThatThrownBy(() -> reservationService.createReservation(createRequest, facilityNotAvailable.getId(), - visitorMember.getEmail())) + visitorMember)) .isInstanceOf(NotOpenedFacilityException.class); } @@ -191,7 +191,7 @@ public void createReservationRoom_throwException_ifNotAvailable() { public void createReservationRoom_throwException_ifNotOpen() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 6, now, 9); assertThatThrownBy(() -> reservationService.createReservation(createRequest, facilityOpen9Close24.getId(), - visitorMember.getEmail())) + visitorMember)) .isInstanceOf(NotOpenedFacilityException.class); } @@ -226,7 +226,7 @@ public void getAvailableTimes_ifPresentReservation() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, tomorrow, 12, tomorrow, 15); reservationService.createReservation(createRequest, facilityOpen9Close24.getId(), - visitorMember.getEmail()); + visitorMember); AvailabilityTimeResponse retResponse = reservationService.getAvailabilityTime(facilityOpen9Close24.getId(), tomorrow); @@ -242,9 +242,9 @@ public void getAvailableTimes_ifPresentReservation() { public void findReservation_ByVisitor() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); Long reservationId = reservationService - .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember.getEmail()); + .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember); - ReservationResponse retResponse = reservationService.findReservation(reservationId, visitorMember.getEmail()); + ReservationResponse retResponse = reservationService.findReservation(reservationId, visitorMember); assertAll( () -> assertThat(retResponse.getId()).isEqualTo(reservationId), @@ -257,9 +257,9 @@ public void findReservation_ByVisitor() { public void findReservation_ByHost() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); Long reservationId = reservationService - .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember.getEmail()); + .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember); - ReservationResponse retResponse = reservationService.findReservation(reservationId, hostMember.getEmail()); + ReservationResponse retResponse = reservationService.findReservation(reservationId, hostMember); assertAll( () -> assertThat(retResponse.getId()).isEqualTo(reservationId), @@ -272,11 +272,11 @@ public void findReservation_ByHost() { public void approveReservation_ByHost() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); Long reservationId = reservationService - .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember.getEmail()); + .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember); - reservationService.approveReservation(reservationId, hostMember.getEmail()); + reservationService.approveReservation(reservationId, hostMember); - ReservationResponse retResponse = reservationService.findReservation(reservationId, hostMember.getEmail()); + ReservationResponse retResponse = reservationService.findReservation(reservationId, hostMember); assertAll( () -> assertThat(retResponse.getId()).isEqualTo(reservationId), () -> assertThat(retResponse.getVisitor().getEmail()).isEqualTo(visitorMember.getEmail()), @@ -289,12 +289,12 @@ public void approveReservation_ByHost() { public void approveReservation_throwException_IfNotHost() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); Long reservationId = reservationService - .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember.getEmail()); + .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember); - reservationService.approveReservation(reservationId, hostMember.getEmail()); + reservationService.approveReservation(reservationId, hostMember); assertThatThrownBy( - () -> reservationService.approveReservation(reservationId, visitorMember.getEmail())) + () -> reservationService.approveReservation(reservationId, visitorMember)) .isInstanceOf(PermissionDeniedException.class); } @@ -303,11 +303,11 @@ public void approveReservation_throwException_IfNotHost() { public void cancelReservation_ByVisitor() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); Long reservationId = reservationService - .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember.getEmail()); + .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember); - reservationService.cancelReservation(reservationId, visitorMember.getEmail()); + reservationService.cancelReservation(reservationId, visitorMember); - ReservationResponse retResponse = reservationService.findReservation(reservationId, visitorMember.getEmail()); + ReservationResponse retResponse = reservationService.findReservation(reservationId, visitorMember); assertAll( () -> assertThat(retResponse.getId()).isEqualTo(reservationId), () -> assertThat(retResponse.getVisitor().getEmail()).isEqualTo(visitorMember.getEmail()), @@ -320,10 +320,10 @@ public void cancelReservation_ByVisitor() { public void cancelReservation_throwException_IfNotMyReservation() { ReservationCreateRequest createRequest = new ReservationCreateRequest(3, now, 12, now, 15); Long reservationId = reservationService - .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember.getEmail()); + .createReservation(createRequest, facilityOpen9Close24.getId(), visitorMember); assertThatThrownBy( - () -> reservationService.cancelReservation(reservationId, hostMember.getEmail())) + () -> reservationService.cancelReservation(reservationId, hostMember)) .isInstanceOf(PermissionDeniedException.class); } } From ee42d5720292c38cd9d257c89824a76458bd724c Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:09:58 +0900 Subject: [PATCH 08/14] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=83=9D=EC=84=B1=20API,=20Se?= =?UTF-8?q?rvice=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../mockData/controller/MockDataController.java | 9 ++++++--- .../mockData/service/MockDataService.java | 11 ++++------- .../mockData/controller/MockDataControllerTest.java | 13 ++++++++++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/modoospace/mockData/controller/MockDataController.java b/src/main/java/com/modoospace/mockData/controller/MockDataController.java index 0b951e4..f5acb76 100644 --- a/src/main/java/com/modoospace/mockData/controller/MockDataController.java +++ b/src/main/java/com/modoospace/mockData/controller/MockDataController.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.modoospace.common.exception.EmptyResponseException; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import com.modoospace.mockData.controller.dto.MockAddressResponse; import com.modoospace.mockData.controller.dto.MockSpaceResponse; import com.modoospace.mockData.service.MockDataService; @@ -73,11 +75,12 @@ private MockAddressResponse getMockAddress(String address) throws IOException, I return addressResponse; } + @CheckLogin @PostMapping("/space/{spaceId}") - public ResponseEntity saveSpace(@PathVariable String spaceId, @LoginEmail String email) throws IOException, InterruptedException { + public ResponseEntity saveSpace(@PathVariable String spaceId, @LoginMember Member loginMember) throws IOException, InterruptedException { MockSpaceResponse spaceResponse = getMockSpace(spaceId); MockAddressResponse addressResponse = getMockAddress(spaceResponse.getLocation().getAddress()); - Long entitySpaceId = mockDataService.saveEntity(spaceResponse, addressResponse, email); + Long entitySpaceId = mockDataService.saveEntity(spaceResponse, addressResponse, loginMember); return ResponseEntity.created(URI.create("/api/v1/spaces/" + entitySpaceId)).build(); } } diff --git a/src/main/java/com/modoospace/mockData/service/MockDataService.java b/src/main/java/com/modoospace/mockData/service/MockDataService.java index bdc00a1..2c4ccee 100644 --- a/src/main/java/com/modoospace/mockData/service/MockDataService.java +++ b/src/main/java/com/modoospace/mockData/service/MockDataService.java @@ -1,7 +1,6 @@ package com.modoospace.mockData.service; import com.modoospace.member.domain.Member; -import com.modoospace.member.service.MemberService; import com.modoospace.mockData.controller.dto.MockAddressResponse; import com.modoospace.mockData.controller.dto.MockSpaceResponse; import com.modoospace.space.domain.*; @@ -14,25 +13,23 @@ @RequiredArgsConstructor public class MockDataService { - private final MemberService memberService; private final CategoryRepository categoryRepository; private final SpaceRepository spaceRepository; private final SpaceIndexRepository spaceIndexRepository; private final FacilityRepository facilityRepository; - public Long saveEntity(MockSpaceResponse spaceResponse, MockAddressResponse addressResponse, String email) { - Space space = makeSpace(spaceResponse, addressResponse, email); + public Long saveEntity(MockSpaceResponse spaceResponse, MockAddressResponse addressResponse, Member loginMember) { + Space space = makeSpace(spaceResponse, addressResponse, loginMember); spaceIndexRepository.save(SpaceIndex.of(space)); makeFacility(spaceResponse, space); return space.getId(); } - private Space makeSpace(MockSpaceResponse spaceResponse, MockAddressResponse addressResponse, String email) { - Member member = memberService.findMemberByEmail(email); + private Space makeSpace(MockSpaceResponse spaceResponse, MockAddressResponse addressResponse, Member loginMember) { Address address = addressResponse.toAddress(spaceResponse.getLocation().getDetailAddress()); Category category = findCategory(spaceResponse.getCategoryName()); - return spaceRepository.save(spaceResponse.toSpace(address, category, member)); + return spaceRepository.save(spaceResponse.toSpace(address, category, loginMember)); } private Category findCategory(String name) { diff --git a/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java b/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java index b8bc0e2..2f11c4b 100644 --- a/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java +++ b/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java @@ -2,6 +2,7 @@ import com.modoospace.AbstractIntegrationContainerBaseTest; import com.modoospace.common.exception.EmptyResponseException; +import com.modoospace.config.auth.dto.SessionMember; import com.modoospace.member.domain.Member; import com.modoospace.member.domain.MemberRepository; import com.modoospace.member.domain.Role; @@ -17,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpSession; import java.io.IOException; import java.net.URI; import java.util.Optional; @@ -39,6 +41,9 @@ class MockDataControllerTest extends AbstractIntegrationContainerBaseTest { @Autowired private CategoryRepository categoryRepository; + @Autowired + HttpSession httpSession; + private Member member; @BeforeEach @@ -48,7 +53,9 @@ public void setUp() { .email("wjdghkwhdl@jr.naver.com") .role(Role.HOST) .build(); - memberRepository.save(member); + member = memberRepository.save(member); + httpSession.setAttribute("member", new SessionMember(member)); + Category category = new Category("스터디룸"); categoryRepository.save(category); } @@ -89,14 +96,14 @@ public void getAddress() throws IOException, InterruptedException { @DisplayName("외부api로 받아온 공간데이터가 비어있을 경우 변환하지 않고 Exception을 던진다.") @Test public void saveSpace_throwException_ifEmptyResponse() { - assertThatThrownBy(() -> mockDataController.saveSpace("2", member.getEmail())) + assertThatThrownBy(() -> mockDataController.saveSpace("2", member)) .isInstanceOf(EmptyResponseException.class); } @DisplayName("외부Api로 받아온 데이터를 모두스페이스 엔티티로 변환 후 저장하여 반환한다.") @Test public void saveSpace() throws IOException, InterruptedException { - URI location = mockDataController.saveSpace("58861", member.getEmail()).getHeaders().getLocation(); + URI location = mockDataController.saveSpace("58861", member).getHeaders().getLocation(); assertThat(location).isNotNull(); Optional space = spaceRepository.findById(extractId(location)); From 6da2c47490cd580d49a4ae061c6014af326dafb9 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:10:46 +0900 Subject: [PATCH 09/14] =?UTF-8?q?refactor:=20Schedule=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../java/com/modoospace/config/WebConfig.java | 4 +- .../space/controller/ScheduleController.java | 29 +++++++----- .../space/sevice/ScheduleService.java | 44 ++++++++----------- .../space/sevice/ScheduleServiceTest.java | 27 ++++++------ 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/modoospace/config/WebConfig.java b/src/main/java/com/modoospace/config/WebConfig.java index 7fc8546..529213c 100644 --- a/src/main/java/com/modoospace/config/WebConfig.java +++ b/src/main/java/com/modoospace/config/WebConfig.java @@ -1,6 +1,6 @@ package com.modoospace.config; -import com.modoospace.config.auth.LoginEmailArgumentResolver; +import com.modoospace.config.auth.resolver.LoginMemberArgumentResolver; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; @@ -12,7 +12,7 @@ @Configuration public class WebConfig implements WebMvcConfigurer { - private final LoginEmailArgumentResolver loginEmailArgumentResolver; + private final LoginMemberArgumentResolver loginEmailArgumentResolver; @Override public void addArgumentResolvers(List resolvers) { diff --git a/src/main/java/com/modoospace/space/controller/ScheduleController.java b/src/main/java/com/modoospace/space/controller/ScheduleController.java index 268a22a..e68355a 100644 --- a/src/main/java/com/modoospace/space/controller/ScheduleController.java +++ b/src/main/java/com/modoospace/space/controller/ScheduleController.java @@ -1,7 +1,9 @@ package com.modoospace.space.controller; import com.modoospace.common.DateFormatManager; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import com.modoospace.space.controller.dto.schedule.ScheduleCreateUpdateRequest; import com.modoospace.space.controller.dto.schedule.ScheduleResponse; import com.modoospace.space.sevice.ScheduleService; @@ -29,11 +31,12 @@ public class ScheduleController { private final ScheduleService scheduleService; + @CheckLogin @PostMapping() public ResponseEntity create(@PathVariable Long facilityId, @RequestBody @Valid ScheduleCreateUpdateRequest createRequest, - @LoginEmail String loginEmail) { - scheduleService.createSchedule(facilityId, createRequest, loginEmail); + @LoginMember Member loginMember) { + scheduleService.createSchedule(facilityId, createRequest, loginMember); return ResponseEntity.ok().build(); } @@ -43,18 +46,20 @@ public ResponseEntity find(@PathVariable Long scheduleId) { return ResponseEntity.ok().body(schedule); } + @CheckLogin @PutMapping("/{scheduleId}") public ResponseEntity update(@PathVariable Long scheduleId, @RequestBody @Valid ScheduleCreateUpdateRequest updateRequest, - @LoginEmail String loginEmail) { - scheduleService.updateSchedule(scheduleId, updateRequest, loginEmail); + @LoginMember Member loginMember) { + scheduleService.updateSchedule(scheduleId, updateRequest, loginMember); return ResponseEntity.noContent().build(); } + @CheckLogin @DeleteMapping("/{scheduleId}") public ResponseEntity delete(@PathVariable Long scheduleId, - @LoginEmail String loginEmail) { - scheduleService.deleteSchedule(scheduleId, loginEmail); + @LoginMember Member loginMember) { + scheduleService.deleteSchedule(scheduleId, loginMember); return ResponseEntity.noContent().build(); } @@ -66,11 +71,12 @@ public ResponseEntity> find1Day(@PathVariable Long facili return ResponseEntity.ok().body(schedules); } + @CheckLogin @PostMapping("/month") public ResponseEntity create1MonthDefault(@PathVariable Long facilityId, @RequestParam @DateTimeFormat(pattern = DateFormatManager.YEARMONTH_FORMAT) final YearMonth yearMonth, - @LoginEmail String loginEmail) { - scheduleService.create1MonthDefaultSchedules(facilityId, yearMonth, loginEmail); + @LoginMember Member loginMember) { + scheduleService.create1MonthDefaultSchedules(facilityId, yearMonth, loginMember); return ResponseEntity.noContent().build(); } @@ -82,12 +88,13 @@ public ResponseEntity> find1Month(@PathVariable Long faci return ResponseEntity.ok().body(schedules); } + @CheckLogin @DeleteMapping("/month") public ResponseEntity delete1Month(@PathVariable Long facilityId, @RequestParam @DateTimeFormat(pattern = DateFormatManager.YEARMONTH_FORMAT) final YearMonth yearMonth, - @LoginEmail String loginEmail) { + @LoginMember Member loginMember) { scheduleService - .delete1MonthSchedules(facilityId, yearMonth, loginEmail); + .delete1MonthSchedules(facilityId, yearMonth, loginMember); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/modoospace/space/sevice/ScheduleService.java b/src/main/java/com/modoospace/space/sevice/ScheduleService.java index f761fd3..f3c59b5 100644 --- a/src/main/java/com/modoospace/space/sevice/ScheduleService.java +++ b/src/main/java/com/modoospace/space/sevice/ScheduleService.java @@ -2,7 +2,6 @@ import com.modoospace.common.exception.NotFoundEntityException; import com.modoospace.member.domain.Member; -import com.modoospace.member.service.MemberService; import com.modoospace.space.controller.dto.schedule.ScheduleCreateUpdateRequest; import com.modoospace.space.controller.dto.schedule.ScheduleResponse; import com.modoospace.space.domain.Facility; @@ -10,27 +9,26 @@ import com.modoospace.space.domain.Schedule; import com.modoospace.space.domain.ScheduleRepository; import com.modoospace.space.repository.ScheduleQueryRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import java.time.LocalDate; import java.time.YearMonth; import java.util.List; import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service public class ScheduleService { - private final MemberService memberService; private final FacilityRepository facilityRepository; private final ScheduleRepository scheduleRepository; private final ScheduleQueryRepository scheduleQueryRepository; @Transactional public void createSchedule(Long facilityId, ScheduleCreateUpdateRequest createRequest, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Facility facility = findFacilityById(facilityId); facility.verifyManagementPermission(loginMember); @@ -45,8 +43,7 @@ public ScheduleResponse findSchedule(Long facilityScheduleId) { @Transactional public void updateSchedule(Long facilityScheduleId, ScheduleCreateUpdateRequest updateRequest, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Schedule schedule = findScheduleById(facilityScheduleId); Facility facility = schedule.getFacility(); facility.verifyManagementPermission(loginMember); @@ -55,8 +52,7 @@ public void updateSchedule(Long facilityScheduleId, ScheduleCreateUpdateRequest } @Transactional - public void deleteSchedule(Long facilityScheduleId, String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + public void deleteSchedule(Long facilityScheduleId, Member loginMember) { Schedule schedule = findScheduleById(facilityScheduleId); Facility facility = schedule.getFacility(); facility.verifyManagementPermission(loginMember); @@ -65,20 +61,19 @@ public void deleteSchedule(Long facilityScheduleId, String loginEmail) { } public List find1DaySchedules(Long facilityId, - LocalDate findDate) { + LocalDate findDate) { Facility facility = findFacilityById(facilityId); List schedules = scheduleQueryRepository - .find1DaySchedules(facility, findDate); + .find1DaySchedules(facility, findDate); return schedules.stream() - .map(ScheduleResponse::of) - .collect(Collectors.toList()); + .map(ScheduleResponse::of) + .collect(Collectors.toList()); } @Transactional public void create1MonthDefaultSchedules(Long facilityId, YearMonth createYearMonth, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Facility facility = findFacilityById(facilityId); facility.verifyManagementPermission(loginMember); @@ -87,20 +82,19 @@ public void create1MonthDefaultSchedules(Long facilityId, YearMonth createYearMo } public List find1MonthSchedules(Long facilityId, - YearMonth findYearMonth) { + YearMonth findYearMonth) { Facility facility = findFacilityById(facilityId); List schedules = scheduleQueryRepository - .find1MonthSchedules(facility, findYearMonth); + .find1MonthSchedules(facility, findYearMonth); return schedules.stream() - .map(ScheduleResponse::of) - .collect(Collectors.toList()); + .map(ScheduleResponse::of) + .collect(Collectors.toList()); } @Transactional public void delete1MonthSchedules(Long facilityId, YearMonth deleteYearMonth, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Facility facility = findFacilityById(facilityId); facility.verifyManagementPermission(loginMember); @@ -109,11 +103,11 @@ public void delete1MonthSchedules(Long facilityId, YearMonth deleteYearMonth, private Facility findFacilityById(Long facilityId) { return facilityRepository.findById(facilityId) - .orElseThrow(() -> new NotFoundEntityException("시설", facilityId)); + .orElseThrow(() -> new NotFoundEntityException("시설", facilityId)); } private Schedule findScheduleById(Long scheduleId) { return scheduleRepository.findById(scheduleId) - .orElseThrow(() -> new NotFoundEntityException("시설스케줄", scheduleId)); + .orElseThrow(() -> new NotFoundEntityException("시설스케줄", scheduleId)); } } diff --git a/src/test/java/com/modoospace/space/sevice/ScheduleServiceTest.java b/src/test/java/com/modoospace/space/sevice/ScheduleServiceTest.java index 47675a2..1a6c391 100644 --- a/src/test/java/com/modoospace/space/sevice/ScheduleServiceTest.java +++ b/src/test/java/com/modoospace/space/sevice/ScheduleServiceTest.java @@ -59,8 +59,7 @@ public void setUp() { .name("host") .role(Role.HOST) .build(); - memberRepository.save(hostMember); - memberRepository.flush(); + hostMember = memberRepository.save(hostMember); Category category = new Category("스터디 공간"); categoryRepository.save(category); @@ -95,7 +94,7 @@ public void createFacilitySchedule() { 24); scheduleService.createSchedule( - facility.getId(), createRequest, hostMember.getEmail()); + facility.getId(), createRequest, hostMember); ScheduleResponse retSchedule = scheduleService.find1DaySchedules( facility.getId(), nowDate).get(1); @@ -112,7 +111,7 @@ public void createFacilitySchedule_merge() { 24); scheduleService.createSchedule( - facility.getId(), createRequest, hostMember.getEmail()); + facility.getId(), createRequest, hostMember); ScheduleResponse retSchedule = scheduleService.find1DaySchedules( facility.getId(), nowDate).get(0); @@ -129,7 +128,7 @@ public void createFacilitySchedule_throwException_ifConflict() { nowDate, 16, 24); assertThatThrownBy(() -> scheduleService - .createSchedule(facility.getId(), createRequest, hostMember.getEmail())) + .createSchedule(facility.getId(), createRequest, hostMember)) .isInstanceOf(ConflictingTimeException.class); } @@ -142,7 +141,7 @@ public void updateFacilitySchedule() { facility.getId(), nowDate).get(0); scheduleService - .updateSchedule(targetSchedule.getId(), updateRequest, hostMember.getEmail()); + .updateSchedule(targetSchedule.getId(), updateRequest, hostMember); ScheduleResponse retSchedule = scheduleService.find1DaySchedules( facility.getId(), nowDate).get(0); @@ -158,14 +157,14 @@ public void updateFacilitySchedule_merge() { ScheduleCreateUpdateRequest createRequest = new ScheduleCreateUpdateRequest( nowDate, 20, 24); scheduleService.createSchedule( - facility.getId(), createRequest, hostMember.getEmail()); + facility.getId(), createRequest, hostMember); ScheduleResponse createSchedule = scheduleService.find1DaySchedules( facility.getId(), nowDate).get(1); ScheduleCreateUpdateRequest updateRequest = new ScheduleCreateUpdateRequest( nowDate, 18, 24); scheduleService.updateSchedule( - createSchedule.getId(), updateRequest, hostMember.getEmail()); + createSchedule.getId(), updateRequest, hostMember); ScheduleResponse retSchedule = scheduleService.find1DaySchedules( facility.getId(), nowDate).get(0); @@ -181,14 +180,14 @@ public void updateFacilitySchedule_throwException_ifConflict() { ScheduleCreateUpdateRequest createRequest = new ScheduleCreateUpdateRequest( nowDate, 20, 24); scheduleService.createSchedule( - facility.getId(), createRequest, hostMember.getEmail()); + facility.getId(), createRequest, hostMember); ScheduleCreateUpdateRequest updateRequest = new ScheduleCreateUpdateRequest( nowDate, 16, 24); ScheduleResponse createSchedule = scheduleService.find1DaySchedules( facility.getId(), nowDate).get(1); assertThatThrownBy(() -> scheduleService.updateSchedule( - createSchedule.getId(), updateRequest, hostMember.getEmail())) + createSchedule.getId(), updateRequest, hostMember)) .isInstanceOf(ConflictingTimeException.class); } @@ -199,7 +198,7 @@ public void deleteFacilitySchedule() { .find1DaySchedules(facility.getId(), nowDate).get(0); scheduleService.deleteSchedule( - targetSchedule.getId(), hostMember.getEmail()); + targetSchedule.getId(), hostMember); assertThatThrownBy( () -> scheduleService.findSchedule(targetSchedule.getId())) @@ -221,7 +220,7 @@ public void create1MonthDefaultFacilitySchedules_plus3Month() { YearMonth createYearMonth = nowYearMonth.plusMonths(3); scheduleService.create1MonthDefaultSchedules( - facility.getId(), createYearMonth, hostMember.getEmail()); + facility.getId(), createYearMonth, hostMember); List retReponses = scheduleService.find1MonthSchedules( facility.getId(), createYearMonth); @@ -254,7 +253,7 @@ public void create1MonthDefaultFacilitySchedules_plus2Month() { TestTransaction.start(); YearMonth createYearMonth = nowYearMonth.plusMonths(2); scheduleService.create1MonthDefaultSchedules( - facility.getId(), createYearMonth, hostMember.getEmail()); + facility.getId(), createYearMonth, hostMember); assertAllSchedules(createYearMonth); TestTransaction.end(); @@ -291,7 +290,7 @@ public void delete1MonthFacilitySchedules() { YearMonth deleteYearMonth = nowYearMonth.plusMonths(2); scheduleService.delete1MonthSchedules( - facility.getId(), deleteYearMonth, hostMember.getEmail()); + facility.getId(), deleteYearMonth, hostMember); List retResponses = scheduleService .find1MonthSchedules(facility.getId(), deleteYearMonth); From 142538e024bfe8528df9c79ac126df9977b5b538 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:11:21 +0900 Subject: [PATCH 10/14] =?UTF-8?q?refactor:=20Space=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../space/controller/SpaceController.java | 41 ++++---- .../modoospace/space/sevice/SpaceService.java | 24 ++--- .../space/sevice/SpaceServiceTest.java | 95 +++++++++++-------- 3 files changed, 81 insertions(+), 79 deletions(-) diff --git a/src/main/java/com/modoospace/space/controller/SpaceController.java b/src/main/java/com/modoospace/space/controller/SpaceController.java index ea927f3..5b29310 100644 --- a/src/main/java/com/modoospace/space/controller/SpaceController.java +++ b/src/main/java/com/modoospace/space/controller/SpaceController.java @@ -1,25 +1,21 @@ package com.modoospace.space.controller; -import com.modoospace.config.auth.LoginEmail; +import com.modoospace.config.auth.aop.CheckLogin; +import com.modoospace.config.auth.resolver.LoginMember; +import com.modoospace.member.domain.Member; import com.modoospace.space.controller.dto.space.SpaceCreateUpdateRequest; import com.modoospace.space.controller.dto.space.SpaceDetailResponse; import com.modoospace.space.controller.dto.space.SpaceResponse; import com.modoospace.space.controller.dto.space.SpaceSearchRequest; import com.modoospace.space.sevice.SpaceService; -import java.net.URI; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -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 org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; @RequiredArgsConstructor @RestController @@ -28,17 +24,18 @@ public class SpaceController { private final SpaceService spaceService; + @CheckLogin @PostMapping("/category/{categoryId}") public ResponseEntity create(@PathVariable Long categoryId, - @RequestBody @Valid SpaceCreateUpdateRequest createRequest, - @LoginEmail String loginEmail) { - Long spaceId = spaceService.createSpace(categoryId, createRequest, loginEmail); + @RequestBody @Valid SpaceCreateUpdateRequest createRequest, + @LoginMember Member loginMember) { + Long spaceId = spaceService.createSpace(categoryId, createRequest, loginMember); return ResponseEntity.created(URI.create("/api/v1/spaces/" + spaceId)).build(); } @GetMapping() public ResponseEntity> search(SpaceSearchRequest searchRequest, - Pageable pageable) { + Pageable pageable) { searchRequest.updateTimeRange(); Page spaces = spaceService.searchSpace(searchRequest, pageable); return ResponseEntity.ok().body(spaces); @@ -46,7 +43,7 @@ public ResponseEntity> search(SpaceSearchRequest searchReque @GetMapping("/query") public ResponseEntity> searchQuery(SpaceSearchRequest searchRequest, - Pageable pageable) { + Pageable pageable) { searchRequest.updateTimeRange(); Page spaces = spaceService.searchSpaceQuery(searchRequest, pageable); return ResponseEntity.ok().body(spaces); @@ -58,18 +55,20 @@ public ResponseEntity find(@PathVariable Long spaceId) { return ResponseEntity.ok().body(space); } + @CheckLogin @PutMapping("/{spaceId}") public ResponseEntity update(@PathVariable Long spaceId, - @RequestBody @Valid SpaceCreateUpdateRequest updateRequest, - @LoginEmail String loginEmail) { - spaceService.updateSpace(spaceId, updateRequest, loginEmail); + @RequestBody @Valid SpaceCreateUpdateRequest updateRequest, + @LoginMember Member loginMember) { + spaceService.updateSpace(spaceId, updateRequest, loginMember); return ResponseEntity.noContent().build(); } + @CheckLogin @DeleteMapping("/{spaceId}") public ResponseEntity delete(@PathVariable Long spaceId, - @LoginEmail String loginEmail) { - spaceService.deleteSpace(spaceId, loginEmail); + @LoginMember Member loginMember) { + spaceService.deleteSpace(spaceId, loginMember); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/modoospace/space/sevice/SpaceService.java b/src/main/java/com/modoospace/space/sevice/SpaceService.java index 8e8652f..2a461d8 100644 --- a/src/main/java/com/modoospace/space/sevice/SpaceService.java +++ b/src/main/java/com/modoospace/space/sevice/SpaceService.java @@ -2,17 +2,11 @@ import com.modoospace.common.exception.NotFoundEntityException; import com.modoospace.member.domain.Member; -import com.modoospace.member.service.MemberService; import com.modoospace.space.controller.dto.space.SpaceCreateUpdateRequest; import com.modoospace.space.controller.dto.space.SpaceDetailResponse; import com.modoospace.space.controller.dto.space.SpaceResponse; import com.modoospace.space.controller.dto.space.SpaceSearchRequest; -import com.modoospace.space.domain.Category; -import com.modoospace.space.domain.CategoryRepository; -import com.modoospace.space.domain.Space; -import com.modoospace.space.domain.SpaceIndex; -import com.modoospace.space.domain.SpaceIndexRepository; -import com.modoospace.space.domain.SpaceRepository; +import com.modoospace.space.domain.*; import com.modoospace.space.repository.SpaceQueryRepository; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; @@ -25,7 +19,6 @@ @Service public class SpaceService { - private final MemberService memberService; private final SpaceRepository spaceRepository; private final CategoryRepository categoryRepository; private final SpaceQueryRepository spaceQueryRepository; @@ -34,11 +27,10 @@ public class SpaceService { @Transactional @CacheEvict(value = "findSpaceId") public Long createSpace(Long categoryId, SpaceCreateUpdateRequest createRequest, - String loginEmail) { - Member host = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Category category = findCategoryById(categoryId); - Space space = createRequest.toEntity(category, host); + Space space = createRequest.toEntity(category, loginMember); spaceRepository.save(space); spaceIndexRepository.save(SpaceIndex.of(space)); @@ -66,8 +58,7 @@ public SpaceDetailResponse findSpace(Long spaceId) { @Transactional @CacheEvict(value = "findSpaceId") public void updateSpace(Long spaceId, SpaceCreateUpdateRequest updateRequest, - String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + Member loginMember) { Space space = findSpaceById(spaceId); space.verifyManagementPermission(loginMember); @@ -78,8 +69,7 @@ public void updateSpace(Long spaceId, SpaceCreateUpdateRequest updateRequest, @Transactional @CacheEvict(value = "findSpaceId") - public void deleteSpace(Long spaceId, String loginEmail) { - Member loginMember = memberService.findMemberByEmail(loginEmail); + public void deleteSpace(Long spaceId, Member loginMember) { Space space = findSpaceById(spaceId); space.verifyDeletePermission(loginMember); @@ -89,11 +79,11 @@ public void deleteSpace(Long spaceId, String loginEmail) { private Space findSpaceById(Long spaceId) { return spaceRepository.findById(spaceId) - .orElseThrow(() -> new NotFoundEntityException("공간", spaceId)); + .orElseThrow(() -> new NotFoundEntityException("공간", spaceId)); } private Category findCategoryById(Long categoryId) { return categoryRepository.findById(categoryId) - .orElseThrow(() -> new NotFoundEntityException("카테고리", categoryId)); + .orElseThrow(() -> new NotFoundEntityException("카테고리", categoryId)); } } diff --git a/src/test/java/com/modoospace/space/sevice/SpaceServiceTest.java b/src/test/java/com/modoospace/space/sevice/SpaceServiceTest.java index 07cdc42..370cde5 100644 --- a/src/test/java/com/modoospace/space/sevice/SpaceServiceTest.java +++ b/src/test/java/com/modoospace/space/sevice/SpaceServiceTest.java @@ -1,7 +1,6 @@ package com.modoospace.space.sevice; import com.modoospace.AbstractIntegrationContainerBaseTest; -import com.modoospace.common.exception.NotFoundEntityException; import com.modoospace.common.exception.PermissionDeniedException; import com.modoospace.member.domain.Member; import com.modoospace.member.domain.MemberRepository; @@ -15,8 +14,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -41,6 +38,9 @@ class SpaceServiceTest extends AbstractIntegrationContainerBaseTest { private Member hostMember; private Member visitorMember; + + private Member adminMember; + private AddressCreateUpdateRequest createAddress; private Category category; @@ -58,15 +58,15 @@ public void setUp() { .role(Role.VISITOR) .build(); - Member adminMember = Member.builder() + adminMember = Member.builder() .email("admin@email") .name("admin") .role(Role.ADMIN) .build(); - memberRepository.save(hostMember); - memberRepository.save(visitorMember); - memberRepository.save(adminMember); + hostMember = memberRepository.save(hostMember); + visitorMember = memberRepository.save(visitorMember); + adminMember = memberRepository.save(adminMember); createAddress = AddressCreateUpdateRequest.builder() .depthFirst("depthFirst") @@ -85,7 +85,7 @@ public void createSpace_IfHost() { SpaceCreateUpdateRequest createRequest = new SpaceCreateUpdateRequest( "공간이름", "설명", createAddress); Long spaceId = spaceService.createSpace(category.getId(), createRequest, - hostMember.getEmail()); + hostMember); SpaceDetailResponse retSpaceResponse = spaceService.findSpace(spaceId); assertAll( @@ -102,23 +102,35 @@ public void createSpace_IfHost() { } @DisplayName("로그인한 멤버가 호스트가 아닐 경우 공간 등록 시 예외를 던진다.") - @ParameterizedTest - @ValueSource(strings = {"admin@email", "visitor@email"}) - public void createSpace_throwException_IfNotHost(String email) { + @Test + public void createSpace_throwException_IfNotHost() { SpaceCreateUpdateRequest createRequest = new SpaceCreateUpdateRequest( "공간이름", "설명", createAddress); - assertThatThrownBy(() -> spaceService.createSpace(category.getId(), createRequest, email)) + + assertThatThrownBy(() -> spaceService.createSpace(category.getId(), createRequest, adminMember)) + .isInstanceOf(PermissionDeniedException.class); + assertThatThrownBy(() -> spaceService.createSpace(category.getId(), createRequest, visitorMember)) .isInstanceOf(PermissionDeniedException.class); } - @DisplayName("공간의 주인/관리자만이 공간을 수정할 수 있다.") - @ParameterizedTest - @ValueSource(strings = {"host@email", "admin@email"}) - public void updateSpace(String email) { + + @DisplayName("공간의 주인은 공간을 수정할 수 있다.") + @Test + public void updateSpace_byHost() { + updateSpace(hostMember); + } + + @DisplayName("관리자는 공간을 수정할 수 있다.") + @Test + public void updateSpace_byAdmin() { + updateSpace(adminMember); + } + + private void updateSpace(Member loginMember) { SpaceCreateUpdateRequest createRequest = new SpaceCreateUpdateRequest( "공간이름", "설명", createAddress); Long spaceId = spaceService.createSpace(category.getId(), createRequest, - hostMember.getEmail()); + hostMember); AddressCreateUpdateRequest updateAddress = AddressCreateUpdateRequest.builder() .depthFirst("시도") .depthSecond("구") @@ -128,7 +140,7 @@ public void updateSpace(String email) { SpaceCreateUpdateRequest updateRequest = new SpaceCreateUpdateRequest("업데이트공간", "업데이트설명", updateAddress); - spaceService.updateSpace(spaceId, updateRequest, email); + spaceService.updateSpace(spaceId, updateRequest, loginMember); SpaceDetailResponse retSpaceResponse = spaceService.findSpace(spaceId); assertAll( @@ -149,30 +161,35 @@ public void updateSpace_throwException_IfAdminMemberOrOwnSpace() { SpaceCreateUpdateRequest createRequest = new SpaceCreateUpdateRequest( "공간이름", "설명", createAddress); Long spaceId = spaceService.createSpace(category.getId(), createRequest, - hostMember.getEmail()); + hostMember); SpaceCreateUpdateRequest updateRequest = new SpaceCreateUpdateRequest( "업데이트공간", "업데이트설명", createAddress); - assertAll( - () -> assertThatThrownBy( - () -> spaceService.updateSpace(spaceId, updateRequest, "notMember@Email")) - .isInstanceOf(NotFoundEntityException.class), - () -> assertThatThrownBy( - () -> spaceService.updateSpace(spaceId, updateRequest, visitorMember.getEmail())) - .isInstanceOf(PermissionDeniedException.class) - ); + + assertThatThrownBy( + () -> spaceService.updateSpace(spaceId, updateRequest, visitorMember)) + .isInstanceOf(PermissionDeniedException.class); + } + + @DisplayName("공간의 주인은 공간을 삭제할 수 있다.") + @Test + public void deleteSpace_byHost() { + deleteSpace(hostMember); } - @DisplayName("공간의 주인/관리자만이 공간을 삭제할 수 있다.") - @ParameterizedTest - @ValueSource(strings = {"host@email", "admin@email"}) - public void deleteSpace(String email) { + @DisplayName("관리자는 공간을 삭제할 수 있다.") + @Test + public void deleteSpace_byAdmin() { + deleteSpace(adminMember); + } + + private void deleteSpace(Member loginMember) { SpaceCreateUpdateRequest createRequest = new SpaceCreateUpdateRequest( "공간이름", "설명", createAddress); Long spaceId = spaceService.createSpace(category.getId(), createRequest, - hostMember.getEmail()); + hostMember); - spaceService.deleteSpace(spaceId, email); + spaceService.deleteSpace(spaceId, loginMember); assertThat(spaceRepository.existsById(spaceId)).isFalse(); } @@ -183,14 +200,10 @@ public void deleteSpace_throwException_IfAdminMemberOrOwnSpace() { SpaceCreateUpdateRequest createRequest = new SpaceCreateUpdateRequest( "공간이름", "설명", createAddress); Long spaceId = spaceService.createSpace(category.getId(), createRequest, - hostMember.getEmail()); + hostMember); - assertAll( - () -> assertThatThrownBy(() -> spaceService.deleteSpace(spaceId, "notMember@Email")) - .isInstanceOf(NotFoundEntityException.class), - () -> assertThatThrownBy( - () -> spaceService.deleteSpace(spaceId, visitorMember.getEmail())) - .isInstanceOf(PermissionDeniedException.class) - ); + assertThatThrownBy( + () -> spaceService.deleteSpace(spaceId, visitorMember)) + .isInstanceOf(PermissionDeniedException.class); } } From 9f2307b49d4df75f19ebeb814aec7eca6bfb42b6 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:15:03 +0900 Subject: [PATCH 11/14] =?UTF-8?q?docs:=20ReadMe=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bfad227..c1aac76 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ > ❗️ 단 호스트의 승인이 있어야 사용이 가능합니다. ### 프로젝트 목표 -- 국내 [SpaceCloud](https://www.spacecloud.kr/) 같은 공간대여 플랫폼을 구현하였습니다. -- 비즈니스 로직을 객체에게 최대한 위임하여 Service Layer에서 객체가 서로 협력하여 사용자 요청을 수행할 수 있도록 아키텍처를 구성하였습니다. +- 국내 [SpaceCloud](https://www.spacecloud.kr/)를 모티브로 공간대여 플랫폼을 구현하였습니다. +- 비즈니스 로직을 객체에게 최대한 위임하여 Service Layer에서 객체가 서로 협력하여 요청을 수행할 수 있도록 아키텍처를 구성하였습니다. - 해당 프로젝트에서는 Mock없는 테스트를 지향하며 Domain 단위테스트, Service 통합테스트를 수행하여 TestCoverage 80%를 달성하였습니다. - 단순 기능만 구현한 것이 아닌, 성능 테스트를 통해 높은 트래픽을 가정한 상황에서도 안정적인 서비스를 유지할 수 있도록 지속적으로 서버 구조를 개선 중입니다. @@ -21,5 +21,6 @@ ### 주요 기술 Issue - [CI/CD를 구축해보자1 - NCP서버 생성 및 Docker로 어플리케이션 배포하기](https://velog.io/@gjwjdghk123/CI-CD1) - [CI/CD를 구축해보자2 - JaCoCo와 GitHub Actions으로 CI/CD구축해보기](https://velog.io/@gjwjdghk123/CI-CD2) +- [ObjectOptimisticLockingFailureException과 고아객체(Orphan) 그리고 한방 쿼리](https://velog.io/@gjwjdghk123/ObjectOptimisticLockingFailureException) - [nGrinder를 이용한 성능 테스트 및 성능 개선(ElasticSearch, Redis)](https://velog.io/@gjwjdghk123/nGrinder%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%84%B1%EB%8A%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%8F-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0ElasticSearch-Redis) - [ElasticSearch TimeOutException 해결과정](https://velog.io/@gjwjdghk123/ElasticSearch-TimeOutException-%ED%95%B4%EA%B2%B0%EA%B3%BC%EC%A0%95) \ No newline at end of file From 0696c8dd045c9efc5941e2cc66023451488abbb9 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:25:12 +0900 Subject: [PATCH 12/14] =?UTF-8?q?refactor:=20Session=EC=97=90=20Email?= =?UTF-8?q?=EB=A7=8C=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - name은 저장할 필요가 없음. 캐시 메모리 낭비. Related: #64 --- .../java/com/modoospace/MainController.java | 7 +++---- .../config/auth/CustomOAuth2UserService.java | 6 +----- .../config/auth/aop/CheckLoginAspect.java | 5 ++--- .../config/auth/dto/SessionMember.java | 19 ------------------- .../resolver/LoginMemberArgumentResolver.java | 5 ++--- .../controller/MockDataControllerTest.java | 3 +-- 6 files changed, 9 insertions(+), 36 deletions(-) delete mode 100644 src/main/java/com/modoospace/config/auth/dto/SessionMember.java diff --git a/src/main/java/com/modoospace/MainController.java b/src/main/java/com/modoospace/MainController.java index 1fb6640..090eaf7 100644 --- a/src/main/java/com/modoospace/MainController.java +++ b/src/main/java/com/modoospace/MainController.java @@ -1,6 +1,5 @@ package com.modoospace; -import com.modoospace.config.auth.dto.SessionMember; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -14,9 +13,9 @@ public class MainController { @GetMapping({"", "/"}) public String index(Model model, HttpSession session) { - SessionMember member = (SessionMember) session.getAttribute("member"); - if (member != null) { - model.addAttribute("userName", member.getEmail()); + String email = (String) session.getAttribute("member"); + if (email != null) { + model.addAttribute("userName", email); } return "index"; } diff --git a/src/main/java/com/modoospace/config/auth/CustomOAuth2UserService.java b/src/main/java/com/modoospace/config/auth/CustomOAuth2UserService.java index c239381..2ff3dac 100644 --- a/src/main/java/com/modoospace/config/auth/CustomOAuth2UserService.java +++ b/src/main/java/com/modoospace/config/auth/CustomOAuth2UserService.java @@ -1,7 +1,6 @@ package com.modoospace.config.auth; import com.modoospace.config.auth.dto.OAuthAttributes; -import com.modoospace.config.auth.dto.SessionMember; import com.modoospace.member.domain.Member; import com.modoospace.member.domain.MemberRepository; import com.modoospace.member.repository.MemberCacheRepository; @@ -40,11 +39,8 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic OAuthAttributes attributes = OAuthAttributes .of(registrationId, userNameAttributeName, oAuth2User.getAttributes()); - //4. SessionUser : 세션에 사용자 정보를 저장하기 위한 Dto클래스 - // 왜 Member를 사용하지않고 SessionMember를 사용 ? Member 클래스가 엔티티이기 때문. - // 엔티티 클래스를 직렬화한다면, 의존관계를 갖는 다른 엔티티들까지 직렬화할 가능성이 있어 성능이 느려질 수 있다. Member member = saveOrUpdate(attributes); - httpSession.setAttribute("member", new SessionMember(member)); + httpSession.setAttribute("member", member.getEmail()); return new DefaultOAuth2User( Collections.singleton(member.createGrantedAuthority()), diff --git a/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java b/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java index b93bc94..f77eea7 100644 --- a/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java +++ b/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java @@ -1,7 +1,6 @@ package com.modoospace.config.auth.aop; import com.modoospace.common.exception.PermissionDeniedException; -import com.modoospace.config.auth.dto.SessionMember; import lombok.RequiredArgsConstructor; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @@ -20,9 +19,9 @@ public class CheckLoginAspect { @Before("@annotation(com.modoospace.config.auth.aop.CheckLogin)") public void checkLogin() throws HttpClientErrorException { - SessionMember member = (SessionMember) httpSession.getAttribute("member"); + String email = (String) httpSession.getAttribute("member"); - if (member == null) { + if (email == null) { throw new PermissionDeniedException(); } } diff --git a/src/main/java/com/modoospace/config/auth/dto/SessionMember.java b/src/main/java/com/modoospace/config/auth/dto/SessionMember.java deleted file mode 100644 index 4fe7533..0000000 --- a/src/main/java/com/modoospace/config/auth/dto/SessionMember.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.modoospace.config.auth.dto; - -import com.modoospace.member.domain.Member; -import java.io.Serializable; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class SessionMember implements Serializable { - - private String name; - private String email; - - public SessionMember(Member member) { - this.name = member.getName(); - this.email = member.getEmail(); - } -} diff --git a/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java b/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java index 0237c97..2546fd3 100644 --- a/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java +++ b/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java @@ -1,7 +1,6 @@ package com.modoospace.config.auth.resolver; import com.modoospace.common.exception.PermissionDeniedException; -import com.modoospace.config.auth.dto.SessionMember; import com.modoospace.member.domain.Member; import com.modoospace.member.service.MemberService; import lombok.RequiredArgsConstructor; @@ -36,8 +35,8 @@ public boolean supportsParameter(MethodParameter parameter) { public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { try { - SessionMember sessionMember = (SessionMember) httpSession.getAttribute("member"); - return memberService.findMemberByEmail(sessionMember.getEmail()); + String email = (String) httpSession.getAttribute("member"); + return memberService.findMemberByEmail(email); } catch (RuntimeException e) { throw new PermissionDeniedException(); } diff --git a/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java b/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java index 2f11c4b..0fe5103 100644 --- a/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java +++ b/src/test/java/com/modoospace/mockData/controller/MockDataControllerTest.java @@ -2,7 +2,6 @@ import com.modoospace.AbstractIntegrationContainerBaseTest; import com.modoospace.common.exception.EmptyResponseException; -import com.modoospace.config.auth.dto.SessionMember; import com.modoospace.member.domain.Member; import com.modoospace.member.domain.MemberRepository; import com.modoospace.member.domain.Role; @@ -54,7 +53,7 @@ public void setUp() { .role(Role.HOST) .build(); member = memberRepository.save(member); - httpSession.setAttribute("member", new SessionMember(member)); + httpSession.setAttribute("member", member.getEmail()); Category category = new Category("스터디룸"); categoryRepository.save(category); From 27db61220619601afe1e54f77ba23176ea2d34d1 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:36:02 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feature:=20=EB=B9=84=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?Exception=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- .../com/modoospace/common/GlobalExceptionHandler.java | 5 +++++ .../common/exception/UnAuthenticatedException.java | 10 ++++++++++ .../modoospace/config/auth/SecurityConfiguration.java | 1 - .../modoospace/config/auth/aop/CheckLoginAspect.java | 4 ++-- .../auth/resolver/LoginMemberArgumentResolver.java | 4 ++-- .../config/elacticsearch/RestClientConfig.java | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/modoospace/common/exception/UnAuthenticatedException.java diff --git a/src/main/java/com/modoospace/common/GlobalExceptionHandler.java b/src/main/java/com/modoospace/common/GlobalExceptionHandler.java index 66e5538..110a2ca 100644 --- a/src/main/java/com/modoospace/common/GlobalExceptionHandler.java +++ b/src/main/java/com/modoospace/common/GlobalExceptionHandler.java @@ -44,6 +44,11 @@ public ResponseEntity handlePermissionDeniedException(PermissionDeniedEx return new ResponseEntity<>(exception.getMessage(), HttpStatus.FORBIDDEN); } + @ExceptionHandler(UnAuthenticatedException.class) + public ResponseEntity handleUnAuthenticatedException(UnAuthenticatedException exception) { + return new ResponseEntity<>(exception.getMessage(), HttpStatus.UNAUTHORIZED); + } + @ExceptionHandler(NotFoundEntityException.class) public ResponseEntity handleNotFoundEntityException(NotFoundEntityException exception) { return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND); diff --git a/src/main/java/com/modoospace/common/exception/UnAuthenticatedException.java b/src/main/java/com/modoospace/common/exception/UnAuthenticatedException.java new file mode 100644 index 0000000..eabf070 --- /dev/null +++ b/src/main/java/com/modoospace/common/exception/UnAuthenticatedException.java @@ -0,0 +1,10 @@ +package com.modoospace.common.exception; + +public class UnAuthenticatedException extends RuntimeException { + + private static final String MESSAGE = "로그인이 필요합니다."; + + public UnAuthenticatedException() { + super(MESSAGE); + } +} diff --git a/src/main/java/com/modoospace/config/auth/SecurityConfiguration.java b/src/main/java/com/modoospace/config/auth/SecurityConfiguration.java index 923a383..5870c01 100644 --- a/src/main/java/com/modoospace/config/auth/SecurityConfiguration.java +++ b/src/main/java/com/modoospace/config/auth/SecurityConfiguration.java @@ -26,7 +26,6 @@ protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/api/v1/facilities/*/schedules/**", "/api/v1/visitors/reservations/facilities/*/availability/**").permitAll() .antMatchers(HttpMethod.POST, "/api/v1/alarms/send/**").permitAll() -// .antMatchers(HttpMethod.POST, "/api/v1/space").hasRole(Role.HOST.name()) .antMatchers("/api/v1/admin/**").hasRole(Role.ADMIN.name()) .anyRequest().authenticated() ) diff --git a/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java b/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java index f77eea7..27c70bc 100644 --- a/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java +++ b/src/main/java/com/modoospace/config/auth/aop/CheckLoginAspect.java @@ -1,6 +1,6 @@ package com.modoospace.config.auth.aop; -import com.modoospace.common.exception.PermissionDeniedException; +import com.modoospace.common.exception.UnAuthenticatedException; import lombok.RequiredArgsConstructor; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @@ -22,7 +22,7 @@ public void checkLogin() throws HttpClientErrorException { String email = (String) httpSession.getAttribute("member"); if (email == null) { - throw new PermissionDeniedException(); + throw new UnAuthenticatedException(); } } } diff --git a/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java b/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java index 2546fd3..0494356 100644 --- a/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java +++ b/src/main/java/com/modoospace/config/auth/resolver/LoginMemberArgumentResolver.java @@ -1,6 +1,6 @@ package com.modoospace.config.auth.resolver; -import com.modoospace.common.exception.PermissionDeniedException; +import com.modoospace.common.exception.UnAuthenticatedException; import com.modoospace.member.domain.Member; import com.modoospace.member.service.MemberService; import lombok.RequiredArgsConstructor; @@ -38,7 +38,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m String email = (String) httpSession.getAttribute("member"); return memberService.findMemberByEmail(email); } catch (RuntimeException e) { - throw new PermissionDeniedException(); + throw new UnAuthenticatedException(); } } } diff --git a/src/main/java/com/modoospace/config/elacticsearch/RestClientConfig.java b/src/main/java/com/modoospace/config/elacticsearch/RestClientConfig.java index 217c9d4..66cbad9 100644 --- a/src/main/java/com/modoospace/config/elacticsearch/RestClientConfig.java +++ b/src/main/java/com/modoospace/config/elacticsearch/RestClientConfig.java @@ -36,7 +36,7 @@ public RestHighLevelClient elasticsearchClient() { httpClientBuilder .setDefaultCredentialsProvider(credentialsProvider) .setMaxConnTotal(100) // 전체 최대 연결 수를 100개로 설정 - .setMaxConnPerRoute(50) // 단일 라우트(호스트) 당 최대 연결 수 -> 단일 node이므로 50개가 최대임. + .setMaxConnPerRoute(50) // 단일 라우트(호스트) 당 최대 연결 수 ); return new RestHighLevelClient(builder); } From 1863d940412638fc49f940d9cd471b3af0dde09a Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 27 Mar 2024 03:37:41 +0900 Subject: [PATCH 14/14] =?UTF-8?q?refactor:=20=EB=B3=80=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #64 --- src/main/java/com/modoospace/config/WebConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/modoospace/config/WebConfig.java b/src/main/java/com/modoospace/config/WebConfig.java index 529213c..dd56453 100644 --- a/src/main/java/com/modoospace/config/WebConfig.java +++ b/src/main/java/com/modoospace/config/WebConfig.java @@ -12,11 +12,11 @@ @Configuration public class WebConfig implements WebMvcConfigurer { - private final LoginMemberArgumentResolver loginEmailArgumentResolver; + private final LoginMemberArgumentResolver loginMemberArgumentResolver; @Override public void addArgumentResolvers(List resolvers) { - resolvers.add(loginEmailArgumentResolver); + resolvers.add(loginMemberArgumentResolver); } @Override