From 9c0cf6bac544810f3a0755bc9e81781938883405 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 25 Sep 2023 15:53:13 +0900 Subject: [PATCH 1/5] =?UTF-8?q?refactor:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AdminCommandService.java | 37 ++----- .../admin/application/AdminQueryService.java | 24 +---- .../admin/dto/AdminMemberDetailResponse.java | 1 + .../admin/dto/AdminMemberResponse.java | 1 + .../admin/presentation/AdminController.java | 32 +++--- .../interceptor/AdminAuthInterceptor.java | 42 ++------ backend/src/main/resources/config | 2 +- .../mapbefine/admin/AdminIntegrationTest.java | 64 +++++------ .../application/AdminCommandServiceTest.java | 100 ++---------------- .../application/AdminQueryServiceTest.java | 44 +------- .../presentation/AdminControllerTest.java | 16 +-- .../mapbefine/common/IntegrationTest.java | 4 + backend/src/test/resources/application.yml | 2 + 13 files changed, 100 insertions(+), 269 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminCommandService.java index 0dfaf5184..273e7aee5 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminCommandService.java @@ -1,28 +1,25 @@ package com.mapbefine.mapbefine.admin.application; -import static com.mapbefine.mapbefine.permission.exception.PermissionErrorCode.PERMISSION_FORBIDDEN_BY_NOT_ADMIN; import static com.mapbefine.mapbefine.topic.exception.TopicErrorCode.TOPIC_NOT_FOUND; import com.mapbefine.mapbefine.atlas.domain.AtlasRepository; -import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.bookmark.domain.BookmarkRepository; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.Role; import com.mapbefine.mapbefine.member.domain.Status; import com.mapbefine.mapbefine.permission.domain.PermissionRepository; -import com.mapbefine.mapbefine.permission.exception.PermissionException.PermissionForbiddenException; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinImageRepository; import com.mapbefine.mapbefine.pin.domain.PinRepository; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; import com.mapbefine.mapbefine.topic.exception.TopicException; -import java.util.List; -import java.util.NoSuchElementException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.NoSuchElementException; + @Service @Transactional public class AdminCommandService { @@ -53,9 +50,7 @@ public AdminCommandService( this.bookmarkRepository = bookmarkRepository; } - public void blockMember(AuthMember authMember, Long memberId) { - validateAdminPermission(authMember); - + public void blockMember(Long memberId) { Member member = findMemberById(memberId); member.updateStatus(Status.BLOCKED); @@ -79,14 +74,6 @@ private Member findMemberById(Long id) { .orElseThrow(() -> new NoSuchElementException("findMemberByAuthMember; member not found; id=" + id)); } - private void validateAdminPermission(AuthMember authMember) { - if (authMember.isRole(Role.ADMIN)) { - return; - } - - throw new PermissionForbiddenException(PERMISSION_FORBIDDEN_BY_NOT_ADMIN); - } - private List extractPinIdsByMember(Member member) { return member.getCreatedPins() .stream() @@ -94,15 +81,11 @@ private List extractPinIdsByMember(Member member) { .toList(); } - public void deleteTopic(AuthMember authMember, Long topicId) { - validateAdminPermission(authMember); - + public void deleteTopic(Long topicId) { topicRepository.deleteById(topicId); } - public void deleteTopicImage(AuthMember authMember, Long topicId) { - validateAdminPermission(authMember); - + public void deleteTopicImage(Long topicId) { Topic topic = findTopicById(topicId); topic.removeImage(); } @@ -112,15 +95,11 @@ private Topic findTopicById(Long topicId) { .orElseThrow(() -> new TopicException.TopicNotFoundException(TOPIC_NOT_FOUND, List.of(topicId))); } - public void deletePin(AuthMember authMember, Long pinId) { - validateAdminPermission(authMember); - + public void deletePin(Long pinId) { pinRepository.deleteById(pinId); } - public void deletePinImage(AuthMember authMember, Long pinImageId) { - validateAdminPermission(authMember); - + public void deletePinImage(Long pinImageId) { pinImageRepository.deleteById(pinImageId); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminQueryService.java b/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminQueryService.java index f7ca346a9..2319c360b 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminQueryService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/admin/application/AdminQueryService.java @@ -2,19 +2,17 @@ import com.mapbefine.mapbefine.admin.dto.AdminMemberDetailResponse; import com.mapbefine.mapbefine.admin.dto.AdminMemberResponse; -import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.permission.exception.PermissionErrorCode; -import com.mapbefine.mapbefine.permission.exception.PermissionException.PermissionForbiddenException; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.topic.domain.Topic; -import java.util.List; -import java.util.NoSuchElementException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.NoSuchElementException; + @Service @Transactional(readOnly = true) public class AdminQueryService { @@ -25,9 +23,7 @@ public AdminQueryService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } - public List findAllMemberDetails(AuthMember authMember) { - validateAdminPermission(authMember); - + public List findAllMemberDetails() { List members = memberRepository.findAllByMemberInfoRole(Role.USER); return members.stream() @@ -40,17 +36,7 @@ private Member findMemberById(Long id) { .orElseThrow(() -> new NoSuchElementException("findMemberByAuthMember; member not found; id=" + id)); } - private void validateAdminPermission(AuthMember authMember) { - if (authMember.isRole(Role.ADMIN)) { - return; - } - - throw new PermissionForbiddenException(PermissionErrorCode.PERMISSION_FORBIDDEN_BY_NOT_ADMIN); - } - - public AdminMemberDetailResponse findMemberDetail(AuthMember authMember, Long memberId) { - validateAdminPermission(authMember); - + public AdminMemberDetailResponse findMemberDetail(Long memberId) { Member findMember = findMemberById(memberId); List topics = findMember.getCreatedTopics(); List pins = findMember.getCreatedPins(); diff --git a/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberDetailResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberDetailResponse.java index fbd5e04d9..8fd0ce7c7 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberDetailResponse.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberDetailResponse.java @@ -6,6 +6,7 @@ import com.mapbefine.mapbefine.pin.dto.response.PinResponse; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.dto.response.TopicResponse; + import java.time.LocalDateTime; import java.util.List; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberResponse.java index f041f8f17..20f55e4c2 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberResponse.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/admin/dto/AdminMemberResponse.java @@ -2,6 +2,7 @@ import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberInfo; + import java.time.LocalDateTime; public record AdminMemberResponse( diff --git a/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminController.java b/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminController.java index 2a34fec12..fb7533ce2 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminController.java @@ -4,8 +4,6 @@ import com.mapbefine.mapbefine.admin.application.AdminQueryService; import com.mapbefine.mapbefine.admin.dto.AdminMemberDetailResponse; import com.mapbefine.mapbefine.admin.dto.AdminMemberResponse; -import com.mapbefine.mapbefine.auth.domain.AuthMember; -import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,6 +11,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @RestController @RequestMapping("/admin") public class AdminController { @@ -27,50 +27,50 @@ public AdminController(AdminQueryService adminQueryService, AdminCommandService } @GetMapping("/members") - public ResponseEntity> findAllMembers(AuthMember authMember) { - List responses = adminQueryService.findAllMemberDetails(authMember); + public ResponseEntity> findAllMembers() { + List responses = adminQueryService.findAllMemberDetails(); return ResponseEntity.ok(responses); } @DeleteMapping("/members/{memberId}") - public ResponseEntity deleteMember(AuthMember authMember, @PathVariable Long memberId) { - adminCommandService.blockMember(authMember, memberId); + public ResponseEntity deleteMember(@PathVariable Long memberId) { + adminCommandService.blockMember(memberId); return ResponseEntity.noContent().build(); } @GetMapping("/members/{memberId}") - public ResponseEntity findMember(AuthMember authMember, @PathVariable Long memberId) { - AdminMemberDetailResponse response = adminQueryService.findMemberDetail(authMember, memberId); + public ResponseEntity findMember(@PathVariable Long memberId) { + AdminMemberDetailResponse response = adminQueryService.findMemberDetail(memberId); return ResponseEntity.ok(response); } @DeleteMapping("/topics/{topicId}") - public ResponseEntity deleteTopic(AuthMember authMember, @PathVariable Long topicId) { - adminCommandService.deleteTopic(authMember, topicId); + public ResponseEntity deleteTopic(@PathVariable Long topicId) { + adminCommandService.deleteTopic(topicId); return ResponseEntity.noContent().build(); } @DeleteMapping("/topics/{topicId}/images") - public ResponseEntity deleteTopicImage(AuthMember authMember, @PathVariable Long topicId) { - adminCommandService.deleteTopicImage(authMember, topicId); + public ResponseEntity deleteTopicImage(@PathVariable Long topicId) { + adminCommandService.deleteTopicImage(topicId); return ResponseEntity.noContent().build(); } @DeleteMapping("/pins/{pinId}") - public ResponseEntity deletePin(AuthMember authMember, @PathVariable Long pinId) { - adminCommandService.deletePin(authMember, pinId); + public ResponseEntity deletePin(@PathVariable Long pinId) { + adminCommandService.deletePin(pinId); return ResponseEntity.noContent().build(); } @DeleteMapping("/pins/images/{imageId}") - public ResponseEntity deletePinImage(AuthMember authMember, @PathVariable Long imageId) { - adminCommandService.deletePinImage(authMember, imageId); + public ResponseEntity deletePinImage(@PathVariable Long imageId) { + adminCommandService.deletePinImage(imageId); return ResponseEntity.noContent().build(); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AdminAuthInterceptor.java b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AdminAuthInterceptor.java index 7a7cb1bbd..5ce84076d 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AdminAuthInterceptor.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AdminAuthInterceptor.java @@ -1,14 +1,12 @@ package com.mapbefine.mapbefine.common.interceptor; -import com.mapbefine.mapbefine.auth.application.AuthService; -import com.mapbefine.mapbefine.auth.dto.AuthInfo; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; + import com.mapbefine.mapbefine.auth.exception.AuthErrorCode; import com.mapbefine.mapbefine.auth.exception.AuthException; -import com.mapbefine.mapbefine.auth.infrastructure.AuthorizationExtractor; -import com.mapbefine.mapbefine.auth.infrastructure.TokenProvider; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.util.Objects; +import org.springframework.beans.factory.annotation.Value; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; @@ -17,18 +15,12 @@ @Component public class AdminAuthInterceptor implements HandlerInterceptor { - private final AuthorizationExtractor authorizationExtractor; - private final AuthService authService; - private final TokenProvider tokenProvider; + private final String secretKey; public AdminAuthInterceptor( - AuthorizationExtractor authorizationExtractor, - AuthService authService, - TokenProvider tokenProvider + @Value("${security.admin.key}") String secretKey ) { - this.authorizationExtractor = authorizationExtractor; - this.authService = authService; - this.tokenProvider = tokenProvider; + this.secretKey = secretKey; } @Override @@ -41,29 +33,15 @@ public boolean preHandle( return true; } - Long memberId = extractMemberIdFromToken(request); - - validateAdmin(memberId); - request.setAttribute("memberId", memberId); - + String secretKey = request.getHeader(AUTHORIZATION); + validateAdmin(secretKey); return true; } - private Long extractMemberIdFromToken(HttpServletRequest request) { - AuthInfo authInfo = authorizationExtractor.extract(request); - if (Objects.isNull(authInfo)) { - return null; - } - tokenProvider.validateAccessToken(authInfo.accessToken()); - - return Long.parseLong(tokenProvider.getPayload(authInfo.accessToken())); - } - - private void validateAdmin(Long memberId) { - if (authService.isAdmin(memberId)) { + private void validateAdmin(String key) { + if (secretKey.equals(key)) { return; } - throw new AuthException.AuthForbiddenException(AuthErrorCode.FORBIDDEN_ADMIN_ACCESS); } diff --git a/backend/src/main/resources/config b/backend/src/main/resources/config index 8069c700c..26325f580 160000 --- a/backend/src/main/resources/config +++ b/backend/src/main/resources/config @@ -1 +1 @@ -Subproject commit 8069c700c69d2b46b52c34817d8d4f66fe8d70b1 +Subproject commit 26325f580ce413f6f6c028deb47425bd792ca4a8 diff --git a/backend/src/test/java/com/mapbefine/mapbefine/admin/AdminIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/admin/AdminIntegrationTest.java index c7d7c26f8..cd2f9b3a7 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/admin/AdminIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/admin/AdminIntegrationTest.java @@ -29,8 +29,12 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; class AdminIntegrationTest extends IntegrationTest { @@ -48,9 +52,10 @@ class AdminIntegrationTest extends IntegrationTest { @Autowired private PinImageRepository pinImageRepository; + @Value("${security.admin.key}") + private String secretKey; private Location location; - private Member admin; private Member member; private Topic topic; private Pin pin; @@ -58,7 +63,6 @@ class AdminIntegrationTest extends IntegrationTest { @BeforeEach void setup() { - admin = memberRepository.save(MemberFixture.create("Admin", "admin@naver.com", Role.ADMIN)); member = memberRepository.save(MemberFixture.create("member", "member@gmail.com", Role.USER)); topic = topicRepository.save(TopicFixture.createByName("topic", member)); location = locationRepository.save(LocationFixture.create()); @@ -67,7 +71,7 @@ void setup() { } @Test - @DisplayName("어드민일 경우, 회원을 전체 조회할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 회원을 전체 조회할 수 있다.") void findAllMembers_Success() { //given Member member1 = MemberFixture.create("member1", "member1@gmail.com", Role.USER); @@ -77,7 +81,7 @@ void findAllMembers_Success() { //when List response = given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .accept(MediaType.APPLICATION_JSON_VALUE) .when().get("/admin/members") .then().log().all() @@ -98,10 +102,10 @@ void findAllMembers_Success() { } @Test - @DisplayName("어드민이 아닐 경우, 회원을 전체 조회할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 회원을 전체 조회할 수 없다.") void findAllMembers_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .accept(MediaType.APPLICATION_JSON_VALUE) .when().get("/admin/members/" + member.getId()) .then().log().all() @@ -109,11 +113,11 @@ void findAllMembers_Fail() { } @Test - @DisplayName("어드민일 경우, 특정 회원의 상세 정보를 조회할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 특정 회원의 상세 정보를 조회할 수 있다.") void findMemberDetail_Success() { //given when AdminMemberDetailResponse response = given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .accept(MediaType.APPLICATION_JSON_VALUE) .when().get("/admin/members/" + member.getId()) .then().log().all() @@ -136,10 +140,10 @@ void findMemberDetail_Success() { } @Test - @DisplayName("어드민이 아닐 경우, 특정 회원의 상세 정보를 조회할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 특정 회원의 상세 정보를 조회할 수 없다.") void findMemberDetail_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .accept(MediaType.APPLICATION_JSON_VALUE) .when().get("/admin/members/" + member.getId()) .then().log().all() @@ -147,100 +151,100 @@ void findMemberDetail_Fail() { } @Test - @DisplayName("어드민일 경우, 특정 회원을 삭제(차단)할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 특정 회원을 삭제(차단)할 수 있다.") void deleteMember_Success() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .when().delete("/admin/members/" + member.getId()) .then().log().all() .statusCode(HttpStatus.NO_CONTENT.value()); } @Test - @DisplayName("어드민이 아닐 경우, 특정 회원을 삭제(차단)할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 특정 회원을 삭제(차단)할 수 없다.") void deleteMember_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .when().delete("/admin/members/" + member.getId()) .then().log().all() .statusCode(HttpStatus.FORBIDDEN.value()); } @Test - @DisplayName("어드민일 경우, 특정 토픽을 삭제할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 특정 토픽을 삭제할 수 있다.") void deleteTopic_Success() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .when().delete("/admin/topics/" + topic.getId()) .then().log().all() .statusCode(HttpStatus.NO_CONTENT.value()); } @Test - @DisplayName("어드민이 아닐 경우, 특정 토픽을 삭제할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 특정 토픽을 삭제할 수 없다.") void deleteTopic_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .when().delete("/admin/topics/" + topic.getId()) .then().log().all() .statusCode(HttpStatus.FORBIDDEN.value()); } @Test - @DisplayName("어드민일 경우, 특정 토픽 이미지를 삭제할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 특정 토픽 이미지를 삭제할 수 있다.") void deleteTopicImage_Success() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .when().delete("/admin/topics/" + topic.getId() + "/images") .then().log().all() .statusCode(HttpStatus.NO_CONTENT.value()); } @Test - @DisplayName("어드민이 아닐 경우, 특정 토픽 이미지를 삭제할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 특정 토픽 이미지를 삭제할 수 없다.") void deleteTopicImage_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .when().delete("/admin/topics/" + topic.getId() + "/images") .then().log().all() .statusCode(HttpStatus.FORBIDDEN.value()); } @Test - @DisplayName("어드민일 경우, 특정 핀을 삭제할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 특정 핀을 삭제할 수 있다.") void deletePin_Success() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .when().delete("/admin/pins/" + pin.getId()) .then().log().all() .statusCode(HttpStatus.NO_CONTENT.value()); } @Test - @DisplayName("어드민이 아닐 경우, 특정 핀을 삭제할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 특정 핀을 삭제할 수 없다.") void deletePin_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .when().delete("/admin/pins/" + pin.getId()) .then().log().all() .statusCode(HttpStatus.FORBIDDEN.value()); } @Test - @DisplayName("어드민일 경우, 특정 핀 이미지를 삭제할 수 있다.") + @DisplayName("어드민 시크릿 키로 요청할 경우, 특정 핀 이미지를 삭제할 수 있다.") void deletePinImage_Success() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(admin)) + .header(AUTHORIZATION, secretKey) .when().delete("/admin/pins/images/" + pinImage.getId()) .then().log().all() .statusCode(HttpStatus.NO_CONTENT.value()); } @Test - @DisplayName("어드민이 아닐 경우, 특정 핀 이미지를 삭제할 수 없다.") + @DisplayName("잘못된 시크릿 키로 요청할 경우, 특정 핀 이미지를 삭제할 수 없다.") void deletePinImage_Fail() { given().log().all() - .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeader(member)) + .header(AUTHORIZATION, "wrongKey") .when().delete("/admin/pins/images/" + pinImage.getId()) .then().log().all() .statusCode(HttpStatus.FORBIDDEN.value()); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminCommandServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminCommandServiceTest.java index 0f3dfcbaa..7aeab51d2 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminCommandServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminCommandServiceTest.java @@ -87,7 +87,6 @@ void setup() { @Test void blockMember_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); Bookmark bookmark = Bookmark.createWithAssociatedTopicAndMember(topic, member); Atlas atlas = Atlas.createWithAssociatedMember(topic, member); Permission permission = Permission.createPermissionAssociatedWithTopicAndMember(topic, member); @@ -107,7 +106,7 @@ void blockMember_Success() { }); //when - adminCommandService.blockMember(adminAuthMember, member.getId()); + adminCommandService.blockMember(member.getId()); //then Topic deletedTopic = topicRepository.findById(topic.getId()).get(); @@ -125,37 +124,14 @@ void blockMember_Success() { }); } - @DisplayName("Admin이 아닐 경우, Member를 차단(탈퇴시킬)할 수 없다.") - @Test - void blockMember_Fail() { - //given - AuthMember userAuthMember = MemberFixture.createUser(member); - Member otherMember = MemberFixture.create("otherMember", "otherMember@email.com", Role.USER); - memberRepository.save(otherMember); - - assertAll(() -> { - assertThat(member.getMemberInfo().getStatus()).isEqualTo(Status.NORMAL); - assertThat(topic.isDeleted()).isFalse(); - assertThat(pin.isDeleted()).isFalse(); - assertThat(pinImage.isDeleted()).isFalse(); - }); - - //when then - Long otherMemberId = otherMember.getId(); - assertThatThrownBy(() -> adminCommandService.blockMember(userAuthMember, otherMemberId)) - .isInstanceOf(PermissionForbiddenException.class); - } - @DisplayName("Admin은 토픽을 삭제시킬 수 있다.") @Test void deleteTopic_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); - assertThat(topic.isDeleted()).isFalse(); //when - adminCommandService.deleteTopic(adminAuthMember, topic.getId()); + adminCommandService.deleteTopic(topic.getId()); //then Topic deletedTopic = topicRepository.findById(topic.getId()).get(); @@ -163,25 +139,10 @@ void deleteTopic_Success() { assertThat(deletedTopic.isDeleted()).isTrue(); } - @DisplayName("Admin이 아닐 경우, 토픽을 삭제시킬 수 없다.") - @Test - void deleteTopic_Fail() { - //given - AuthMember userAuthMember = MemberFixture.createUser(member); - - assertThat(topic.isDeleted()).isFalse(); - - //when then - Long topicId = topic.getId(); - assertThatThrownBy(() -> adminCommandService.deleteTopic(userAuthMember, topicId)) - .isInstanceOf(PermissionForbiddenException.class); - } - @DisplayName("Admin은 토픽 이미지를 삭제할 수 있다.") @Test void deleteTopicImage_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); TopicInfo topicInfo = topic.getTopicInfo(); topic.updateTopicInfo(topicInfo.getName(), topicInfo.getDescription(), "https://imageUrl.png"); @@ -189,7 +150,7 @@ void deleteTopicImage_Success() { assertThat(topic.getTopicInfo().getImageUrl()).isEqualTo("https://imageUrl.png"); //when - adminCommandService.deleteTopicImage(adminAuthMember, topic.getId()); + adminCommandService.deleteTopicImage(topic.getId()); //then Topic imageDeletedTopic = topicRepository.findById(topic.getId()).get(); @@ -199,33 +160,14 @@ void deleteTopicImage_Success() { ); } - @DisplayName("Admin이 아닐 경우, 이미지를 삭제할 수 없다.") - @Test - void deleteTopicImage_Fail() { - //given - AuthMember userAuthMember = MemberFixture.createUser(member); - TopicInfo topicInfo = topic.getTopicInfo(); - - topic.updateTopicInfo(topicInfo.getName(), topicInfo.getDescription(), "https://imageUrl.png"); - - assertThat(topic.getTopicInfo().getImageUrl()).isEqualTo("https://imageUrl.png"); - - //when then - Long topicId = topic.getId(); - assertThatThrownBy(() -> adminCommandService.deleteTopicImage(userAuthMember, topicId)) - .isInstanceOf(PermissionForbiddenException.class); - } - @DisplayName("Admin은 핀을 삭제할 수 있다.") @Test void deletePin_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); - assertThat(pin.isDeleted()).isFalse(); //when - adminCommandService.deletePin(adminAuthMember, pin.getId()); + adminCommandService.deletePin(pin.getId()); //then Pin deletedPin = pinRepository.findById(pin.getId()).get(); @@ -233,30 +175,14 @@ void deletePin_Success() { assertThat(deletedPin.isDeleted()).isTrue(); } - @DisplayName("Admin이 아닐 경우, 핀을 삭제할 수 없다.") - @Test - void deletePin_Fail() { - //given - AuthMember userAuthMember = MemberFixture.createUser(member); - - assertThat(pin.isDeleted()).isFalse(); - - //when then - Long pinId = pin.getId(); - assertThatThrownBy(() -> adminCommandService.deletePin(userAuthMember, pinId)) - .isInstanceOf(PermissionForbiddenException.class); - } - @DisplayName("Admin인 경우, 핀 이미지를 삭제할 수 있다.") @Test void deletePinImage_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); - assertThat(pinImage.isDeleted()).isFalse(); //when - adminCommandService.deletePinImage(adminAuthMember, pinImage.getId()); + adminCommandService.deletePinImage(pinImage.getId()); //then PinImage deletedPinImage = pinImageRepository.findById(pinImage.getId()).get(); @@ -264,18 +190,4 @@ void deletePinImage_Success() { assertThat(deletedPinImage.isDeleted()).isTrue(); } - @DisplayName("Admin이 아닐 경우, 핀 이미지를 삭제할 수 없다.") - @Test - void deletePinImage_Fail() { - //given - AuthMember userAuthMember = MemberFixture.createUser(member); - - assertThat(pinImage.isDeleted()).isFalse(); - - //when then - Long pinImageId = pinImage.getId(); - assertThatThrownBy(() -> adminCommandService.deletePinImage(userAuthMember, pinImageId)) - .isInstanceOf(PermissionForbiddenException.class); - } - -} \ No newline at end of file +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminQueryServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminQueryServiceTest.java index 335991104..a50dd3f01 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminQueryServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/admin/application/AdminQueryServiceTest.java @@ -65,35 +65,17 @@ void setup() { @DisplayName("사용자와 관련된 세부(민감한 정보 포함) 정보를 모두 조회할 수 있다.") void findMemberDetail_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); + AdminMemberDetailResponse response = adminQueryService.findMemberDetail(member.getId()); - //when - AdminMemberDetailResponse response = adminQueryService.findMemberDetail(adminAuthMember, member.getId()); - - //then + //when //then assertThat(response).usingRecursiveComparison() .ignoringFields("updatedAt") .isEqualTo(AdminMemberDetailResponse.of(member, List.of(topic), List.of(pin))); } - - @Test - @DisplayName("Admin이 아닌 경우, 사용자와 관련된 세부(민감한 정보 포함) 정보를 모두 조회할 수 없다.") - void findMemberDetail_Fail() { - //given - AuthMember userAuthMember = MemberFixture.createUser(member); - - //when //then - Long memberId = member.getId(); - assertThatThrownBy(() -> adminQueryService.findMemberDetail(userAuthMember, memberId)) - .isInstanceOf(PermissionForbiddenException.class); - } - @Test @DisplayName("모든 사용자와 관련된 세부 정보를 모두 조회할 수 있다.") void findAllMemberDetails_Success() { //given - AuthMember adminAuthMember = MemberFixture.createUser(admin); - ArrayList members = new ArrayList<>(); members.add(member); for (int i = 0; i < 10; i++) { @@ -102,7 +84,7 @@ void findAllMemberDetails_Success() { } //when - List responses = adminQueryService.findAllMemberDetails(adminAuthMember); + List responses = adminQueryService.findAllMemberDetails(); //then List expected = members.stream() .map(AdminMemberResponse::from) @@ -114,22 +96,4 @@ void findAllMemberDetails_Success() { .isEqualTo(expected); } - @Test - @DisplayName("Admin이 아닌 경우 모든 사용자와 관련된 세부 정보를 모두 조회할 수 없다.") - void findAllMemberDetails_Fail() { - //given - AuthMember memberAuthMember = MemberFixture.createUser(member); - - ArrayList members = new ArrayList<>(); - members.add(member); - for (int i = 0; i < 10; i++) { - Member saveMember = MemberFixture.create("member" + i, "member" + i + "@email.com", Role.USER); - members.add(memberRepository.save(saveMember)); - } - - //when //then - assertThatThrownBy(() -> adminQueryService.findAllMemberDetails(memberAuthMember)) - .isInstanceOf(PermissionForbiddenException.class); - } - -} \ No newline at end of file +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/admin/presentation/AdminControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/admin/presentation/AdminControllerTest.java index edceb5d36..f46539b20 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/admin/presentation/AdminControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/admin/presentation/AdminControllerTest.java @@ -86,7 +86,7 @@ void findAllMemberDetails() throws Exception { new AdminMemberResponse(2L, "세인", "semin@naver.com", "https://semin.png", LocalDateTime.now()) ); - given(adminQueryService.findAllMemberDetails(any())).willReturn(response); + given(adminQueryService.findAllMemberDetails()).willReturn(response); mockMvc.perform( MockMvcRequestBuilders.get("/admin/members") @@ -107,7 +107,7 @@ void findMember() throws Exception { LocalDateTime.now() ); - given(adminQueryService.findMemberDetail(any(), any())).willReturn(response); + given(adminQueryService.findMemberDetail(any())).willReturn(response); mockMvc.perform( MockMvcRequestBuilders.get("/admin/members/1") @@ -118,7 +118,7 @@ void findMember() throws Exception { @DisplayName("멤버 차단(블랙리스트)") @Test void deleteMember() throws Exception { - doNothing().when(adminCommandService).blockMember(any(), any()); + doNothing().when(adminCommandService).blockMember(any()); mockMvc.perform( MockMvcRequestBuilders.delete("/admin/members/1") @@ -129,7 +129,7 @@ void deleteMember() throws Exception { @DisplayName("토픽 삭제") @Test void deleteTopic() throws Exception { - doNothing().when(adminCommandService).deleteTopic(any(), any()); + doNothing().when(adminCommandService).deleteTopic(any()); mockMvc.perform( MockMvcRequestBuilders.delete("/admin/topics/1") @@ -140,7 +140,7 @@ void deleteTopic() throws Exception { @DisplayName("토픽 이미지 삭제") @Test void deleteTopicImage() throws Exception { - doNothing().when(adminCommandService).deleteTopicImage(any(), any()); + doNothing().when(adminCommandService).deleteTopicImage(any()); mockMvc.perform( MockMvcRequestBuilders.delete("/admin/topics/1/images") @@ -151,7 +151,7 @@ void deleteTopicImage() throws Exception { @DisplayName("핀 삭제") @Test void deletePin() throws Exception { - doNothing().when(adminCommandService).deletePin(any(), any()); + doNothing().when(adminCommandService).deletePin(any()); mockMvc.perform( MockMvcRequestBuilders.delete("/admin/pins/1") @@ -162,11 +162,11 @@ void deletePin() throws Exception { @DisplayName("토픽 이미지 삭제") @Test void deletePinImage() throws Exception { - doNothing().when(adminCommandService).deletePinImage(any(), any()); + doNothing().when(adminCommandService).deletePinImage(any()); mockMvc.perform( MockMvcRequestBuilders.delete("/admin/pins/images/1") .header(AUTHORIZATION, testAuthHeaderProvider.createAuthHeaderById(1L)) ).andDo(restDocs.document()); } -} \ No newline at end of file +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java index e20e5caa6..67824d3be 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java @@ -7,7 +7,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Profile; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +@TestPropertySource(locations = "classpath:application.yml") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class IntegrationTest { diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index 4fd6070fd..1a62c66f0 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -40,3 +40,5 @@ security: secret-key: ${TEST_JWT_SECRET_KEY} access-expire-length: ${TEST_JWT_ACCESS_EXPIRE_LENGTH} refresh-expire-length: ${TEST_JWT_REFRESH_EXPIRE_LENGTH} + admin: + key: testkey From 3df08108956eadaad7a7777550e741c27ef2b18b Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 25 Sep 2023 15:55:23 +0900 Subject: [PATCH 2/5] =?UTF-8?q?docs:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20API?= =?UTF-8?q?=20=EB=AA=85=EC=84=B8=20=EB=B9=84=EA=B3=B5=EA=B0=9C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/docs/asciidoc/admin.adoc | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/backend/src/docs/asciidoc/admin.adoc b/backend/src/docs/asciidoc/admin.adoc index 3d2137c4e..64b338446 100644 --- a/backend/src/docs/asciidoc/admin.adoc +++ b/backend/src/docs/asciidoc/admin.adoc @@ -1,29 +1,29 @@ -== 관리자 기능 - -=== 전체 회원 조회 - -operation::admin-controller-test/find-all-member-details[snippets='http-request,http-response'] - -=== 회원 상세 조회 - -operation::admin-controller-test/find-member[snippets='http-request,http-response'] - -=== 회원 차단(삭제) - -operation::admin-controller-test/delete-member[snippets='http-request,http-response'] - -=== 토픽 삭제 - -operation::admin-controller-test/delete-topic[snippets='http-request,http-response'] - -=== 토픽 이미지 삭제 - -operation::admin-controller-test/delete-topic-image[snippets='http-request,http-response'] - -=== 핀 삭제 - -operation::admin-controller-test/delete-pin[snippets='http-request,http-response'] - -=== 핀 이미지 삭제 - -operation::admin-controller-test/delete-pin-image[snippets='http-request,http-response'] \ No newline at end of file +// == 관리자 기능 +// +// === 전체 회원 조회 +// +// operation::admin-controller-test/find-all-member-details[snippets='http-request,http-response'] +// +// === 회원 상세 조회 +// +// operation::admin-controller-test/find-member[snippets='http-request,http-response'] +// +// === 회원 차단(삭제) +// +// operation::admin-controller-test/delete-member[snippets='http-request,http-response'] +// +// === 토픽 삭제 +// +// operation::admin-controller-test/delete-topic[snippets='http-request,http-response'] +// +// === 토픽 이미지 삭제 +// +// operation::admin-controller-test/delete-topic-image[snippets='http-request,http-response'] +// +// === 핀 삭제 +// +// operation::admin-controller-test/delete-pin[snippets='http-request,http-response'] +// +// === 핀 이미지 삭제 +// +// operation::admin-controller-test/delete-pin-image[snippets='http-request,http-response'] From 05e395ebf921fb65b4b0fe749f70d172680c757f Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 25 Sep 2023 15:59:19 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A1=9C=EC=BB=AC=EB=A1=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 관리자 페이지 빌드 파일, 뷰 컨트롤러 삭제 --- .../presentation/AdminViewController.java | 17 -- .../src/main/resources/static/admin/bundle.js | 270 ------------------ .../main/resources/static/admin/bundle.js.map | 1 - .../main/resources/static/admin/index.html | 1 - 4 files changed, 289 deletions(-) delete mode 100644 backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminViewController.java delete mode 100644 backend/src/main/resources/static/admin/bundle.js delete mode 100644 backend/src/main/resources/static/admin/bundle.js.map delete mode 100644 backend/src/main/resources/static/admin/index.html diff --git a/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminViewController.java b/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminViewController.java deleted file mode 100644 index 15f416131..000000000 --- a/backend/src/main/java/com/mapbefine/mapbefine/admin/presentation/AdminViewController.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.mapbefine.mapbefine.admin.presentation; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@Controller -@RequestMapping("/admin") -public class AdminViewController { - - @GetMapping - public String home() { - - return "admin/index.html"; - } - -} diff --git a/backend/src/main/resources/static/admin/bundle.js b/backend/src/main/resources/static/admin/bundle.js deleted file mode 100644 index 78540f406..000000000 --- a/backend/src/main/resources/static/admin/bundle.js +++ /dev/null @@ -1,270 +0,0 @@ -/*! For license information please see bundle.js.LICENSE.txt */ -(()=>{var e,t,n={448:(e,t,n)=>{"use strict";var r=n(294),a=n(840);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n