-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: API를 통한 사용자 권한 관리 및 회원 정보 제공 완료 (#465)
Co-authored-by: GwanSik Kim <[email protected]>
- Loading branch information
Showing
17 changed files
with
312 additions
and
6 deletions.
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
.../api/domain/memberManagement/member/adapter/in/web/MemberRoleInfoRetrievalController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package page.clab.api.domain.memberManagement.member.adapter.in.web; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.security.access.prepost.PreAuthorize; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import page.clab.api.domain.memberManagement.member.application.dto.response.MemberRoleInfoResponseDto; | ||
import page.clab.api.domain.memberManagement.member.application.port.in.RetrieveMemberRoleInfoUseCase; | ||
import page.clab.api.domain.memberManagement.member.domain.Role; | ||
import page.clab.api.global.common.dto.ApiResponse; | ||
import page.clab.api.global.exception.InvalidColumnException; | ||
import page.clab.api.global.exception.SortingArgumentException; | ||
import page.clab.api.global.util.PageableUtils; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/members") | ||
@RequiredArgsConstructor | ||
@Tag(name = "Member Management - Member", description = "멤버") | ||
public class MemberRoleInfoRetrievalController { | ||
|
||
private final RetrieveMemberRoleInfoUseCase retrieveMemberRoleInfoUseCase; | ||
private final PageableUtils pageableUtils; | ||
|
||
@Operation(summary = "[A] 멤버 권한 조회", description = "ROLE_ADMIN 이상의 권한이 필요함<br>" + | ||
"3개의 파라미터를 자유롭게 조합하여 필터링 가능<br>" + | ||
"멤버 ID, 멤버 이름, 권한 중 하나라도 입력하지 않으면 전체 조회됨<br>" + | ||
"DTO의 필드명을 기준으로 정렬 가능하며, 정렬 방향은 오름차순(asc)과 내림차순(desc)이 가능함") | ||
@PreAuthorize("hasRole('ADMIN')") | ||
@GetMapping("/roles") | ||
public ApiResponse<List<MemberRoleInfoResponseDto>> retrieveMemberRoleInfo( | ||
@RequestParam(required = false) String memberId, | ||
@RequestParam(required = false) String memberName, | ||
@RequestParam(required = false) Role role, | ||
@RequestParam(name = "page", defaultValue = "0") int page, | ||
@RequestParam(name = "size", defaultValue = "20") int size, | ||
@RequestParam(name = "sortBy", defaultValue = "id") List<String> sortBy, | ||
@RequestParam(name = "sortDirection", defaultValue = "asc") List<String> sortDirection | ||
) throws InvalidColumnException, SortingArgumentException { | ||
Pageable pageable = pageableUtils.createPageable(page, size, sortBy, sortDirection, MemberRoleInfoResponseDto.class); | ||
List<MemberRoleInfoResponseDto> memberRoles = retrieveMemberRoleInfoUseCase.retrieveMemberRoleInfo(memberId, memberName, role, pageable); | ||
return ApiResponse.success(memberRoles); | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
...lab/api/domain/memberManagement/member/adapter/in/web/MemberRoleManagementController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package page.clab.api.domain.memberManagement.member.adapter.in.web; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.access.prepost.PreAuthorize; | ||
import org.springframework.web.bind.annotation.PatchMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import page.clab.api.domain.memberManagement.member.application.dto.request.ChangeMemberRoleRequest; | ||
import page.clab.api.domain.memberManagement.member.application.port.in.ManageMemberRoleUseCase; | ||
import page.clab.api.global.common.dto.ApiResponse; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/members") | ||
@RequiredArgsConstructor | ||
@Tag(name = "Member Management - Member", description = "멤버") | ||
public class MemberRoleManagementController { | ||
|
||
private final ManageMemberRoleUseCase manageMemberRoleUseCase; | ||
|
||
@Operation(summary = "[S] 멤버 권한 변경", description = "ROLE_SUPER 이상의 권한이 필요함<br>" + | ||
"권한 계층: SUPER > ADMIN > USER > GUEST<br>" + | ||
"GUEST 권한은 변경 불가능함") | ||
@PreAuthorize("hasRole('SUPER')") | ||
@PatchMapping("/{memberId}/roles") | ||
public ApiResponse<String> changeMemberRole( | ||
HttpServletRequest httpServletRequest, | ||
@PathVariable(name = "memberId") String memberId, | ||
@RequestBody ChangeMemberRoleRequest request | ||
) { | ||
String id = manageMemberRoleUseCase.changeMemberRole(httpServletRequest, memberId, request); | ||
return ApiResponse.success(id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
...b/api/domain/memberManagement/member/application/dto/request/ChangeMemberRoleRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package page.clab.api.domain.memberManagement.member.application.dto.request; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import page.clab.api.domain.memberManagement.member.domain.Role; | ||
|
||
@Getter | ||
@Setter | ||
public class ChangeMemberRoleRequest { | ||
|
||
@Schema(description = "변경할 멤버 권한", example = "USER") | ||
private Role role; | ||
} |
31 changes: 31 additions & 0 deletions
31
...pi/domain/memberManagement/member/application/dto/response/MemberRoleInfoResponseDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package page.clab.api.domain.memberManagement.member.application.dto.response; | ||
|
||
import lombok.Builder; | ||
import lombok.Getter; | ||
import page.clab.api.domain.memberManagement.member.domain.Member; | ||
import page.clab.api.domain.memberManagement.member.domain.Role; | ||
|
||
import java.util.List; | ||
|
||
@Getter | ||
@Builder | ||
public class MemberRoleInfoResponseDto { | ||
|
||
private String id; | ||
private String name; | ||
private Role role; | ||
|
||
public static List<MemberRoleInfoResponseDto> toDto(List<Member> members) { | ||
return members.stream() | ||
.map(MemberRoleInfoResponseDto::toDto) | ||
.toList(); | ||
} | ||
|
||
public static MemberRoleInfoResponseDto toDto(Member member) { | ||
return MemberRoleInfoResponseDto.builder() | ||
.id(member.getId()) | ||
.name(member.getName()) | ||
.role(member.getRole()) | ||
.build(); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
.../api/domain/memberManagement/member/application/exception/InvalidRoleChangeException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package page.clab.api.domain.memberManagement.member.application.exception; | ||
|
||
public class InvalidRoleChangeException extends RuntimeException { | ||
|
||
public InvalidRoleChangeException(String s) { | ||
super(s); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
.../clab/api/domain/memberManagement/member/application/port/in/ManageMemberRoleUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package page.clab.api.domain.memberManagement.member.application.port.in; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import page.clab.api.domain.memberManagement.member.application.dto.request.ChangeMemberRoleRequest; | ||
|
||
public interface ManageMemberRoleUseCase { | ||
String changeMemberRole(HttpServletRequest httpServletRequest, String memberId, ChangeMemberRoleRequest request); | ||
} |
11 changes: 11 additions & 0 deletions
11
...api/domain/memberManagement/member/application/port/in/RetrieveMemberRoleInfoUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package page.clab.api.domain.memberManagement.member.application.port.in; | ||
|
||
import org.springframework.data.domain.Pageable; | ||
import page.clab.api.domain.memberManagement.member.application.dto.response.MemberRoleInfoResponseDto; | ||
import page.clab.api.domain.memberManagement.member.domain.Role; | ||
|
||
import java.util.List; | ||
|
||
public interface RetrieveMemberRoleInfoUseCase { | ||
List<MemberRoleInfoResponseDto> retrieveMemberRoleInfo(String memberId, String memberName, Role role, Pageable pageable); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
...pi/domain/memberManagement/member/application/service/MemberRoleInfoRetrievalService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package page.clab.api.domain.memberManagement.member.application.service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import page.clab.api.domain.memberManagement.member.application.dto.response.MemberRoleInfoResponseDto; | ||
import page.clab.api.domain.memberManagement.member.application.port.in.RetrieveMemberRoleInfoUseCase; | ||
import page.clab.api.domain.memberManagement.member.application.port.out.RetrieveMemberPort; | ||
import page.clab.api.domain.memberManagement.member.domain.Member; | ||
import page.clab.api.domain.memberManagement.member.domain.Role; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class MemberRoleInfoRetrievalService implements RetrieveMemberRoleInfoUseCase { | ||
|
||
private final RetrieveMemberPort retrieveMemberPort; | ||
|
||
@Transactional(readOnly = true) | ||
@Override | ||
public List<MemberRoleInfoResponseDto> retrieveMemberRoleInfo(String memberId, String memberName, Role role, Pageable pageable) { | ||
List<Member> members = retrieveMemberPort.findMemberRoleInfoByConditions(memberId, memberName, role, pageable); | ||
return MemberRoleInfoResponseDto.toDto(members); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
...b/api/domain/memberManagement/member/application/service/MemberRoleManagementService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package page.clab.api.domain.memberManagement.member.application.service; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import page.clab.api.domain.memberManagement.member.application.dto.request.ChangeMemberRoleRequest; | ||
import page.clab.api.domain.memberManagement.member.application.exception.InvalidRoleChangeException; | ||
import page.clab.api.domain.memberManagement.member.application.port.in.ManageMemberRoleUseCase; | ||
import page.clab.api.domain.memberManagement.member.application.port.out.RetrieveMemberPort; | ||
import page.clab.api.domain.memberManagement.member.application.port.out.UpdateMemberPort; | ||
import page.clab.api.domain.memberManagement.member.domain.Member; | ||
import page.clab.api.domain.memberManagement.member.domain.Role; | ||
import page.clab.api.global.common.slack.application.SlackService; | ||
import page.clab.api.global.common.slack.domain.SecurityAlertType; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class MemberRoleManagementService implements ManageMemberRoleUseCase { | ||
|
||
private final RetrieveMemberPort retrieveMemberPort; | ||
private final UpdateMemberPort updateMemberPort; | ||
private final SlackService slackService; | ||
|
||
@Transactional | ||
@Override | ||
public String changeMemberRole(HttpServletRequest httpServletRequest, String memberId, ChangeMemberRoleRequest request) { | ||
Member member = retrieveMemberPort.findByIdOrThrow(memberId); | ||
|
||
Role oldRole = member.getRole(); | ||
Role newRole = request.getRole(); | ||
|
||
validateRoleChange(member, oldRole, newRole); | ||
member.changeRole(newRole); | ||
|
||
updateMemberPort.update(member); | ||
slackService.sendSecurityAlertNotification(httpServletRequest, SecurityAlertType.MEMBER_ROLE_CHANGED, | ||
String.format("[%s] %s: %s -> %s", | ||
member.getId(), member.getName(), oldRole, newRole)); | ||
return memberId; | ||
} | ||
|
||
private void validateRoleChange(Member member, Role oldRole, Role newRole) { | ||
// 기존 권한과 새 권한이 동일한지 확인 | ||
if (oldRole.equals(newRole)) { | ||
throw new InvalidRoleChangeException("기존 권한과 변경할 권한이 같습니다."); | ||
} | ||
// 멤버의 변경될 권한이 GUEST 인지 또는 변경되는 권한이 GUEST 인지 확인 | ||
if (member.isGuestRole() || newRole.isGuestRole()) { | ||
throw new InvalidRoleChangeException("GUEST 권한은 변경 불가능합니다."); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.