diff --git a/src/main/java/flipnote/group/adapter/in/web/MemberController.java b/src/main/java/flipnote/group/adapter/in/web/MemberController.java index 1e69012..2c0573f 100644 --- a/src/main/java/flipnote/group/adapter/in/web/MemberController.java +++ b/src/main/java/flipnote/group/adapter/in/web/MemberController.java @@ -1,7 +1,9 @@ package flipnote.group.adapter.in.web; 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.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestHeader; @@ -41,7 +43,4 @@ public ResponseEntity findGroupMembers( return ResponseEntity.ok(res); } - //todo 하위 권한 수정 - - //todo 그룹 멤버 추방 } diff --git a/src/main/java/flipnote/group/adapter/in/web/PermissionController.java b/src/main/java/flipnote/group/adapter/in/web/PermissionController.java new file mode 100644 index 0000000..e10dcde --- /dev/null +++ b/src/main/java/flipnote/group/adapter/in/web/PermissionController.java @@ -0,0 +1,49 @@ +package flipnote.group.adapter.in.web; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import flipnote.group.api.dto.request.AddPermissionRequestDto; +import flipnote.group.api.dto.response.AddPermissionResponseDto; +import flipnote.group.application.port.in.AddPermissionUseCase; +import flipnote.group.application.port.in.command.AddPermissionCommand; +import flipnote.group.application.port.in.result.AddPermissionResult; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/v1/groups/{groupId}") +public class PermissionController { + + private final AddPermissionUseCase addPermissionUseCase; + + /** + * 하위 권한 추가 + */ + @PostMapping("/permissions") + public ResponseEntity addDownPermission( + @RequestHeader("X-USER-ID") Long userId, + @PathVariable("groupId") Long groupId, + @Valid @RequestBody AddPermissionRequestDto req) { + + AddPermissionCommand cmd = new AddPermissionCommand(userId, groupId, req.changeRole(), req.permission()); + + AddPermissionResult result = addPermissionUseCase.addPermission(cmd); + + AddPermissionResponseDto res = AddPermissionResponseDto.from(result); + + return ResponseEntity.ok(res); + } + + + //todo 그룹 멤버 추방 + + //todo 특정 그룹의 내 권한 확인 +} diff --git a/src/main/java/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java b/src/main/java/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java index 7088ac5..cbb048f 100644 --- a/src/main/java/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java +++ b/src/main/java/flipnote/group/adapter/out/persistence/GroupRoleRepositoryAdapter.java @@ -3,10 +3,12 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.springframework.stereotype.Repository; +import flipnote.group.adapter.out.entity.GroupMemberEntity; import flipnote.group.adapter.out.entity.PermissionEntity; import flipnote.group.adapter.out.entity.RoleEntity; import flipnote.group.application.port.out.GroupRoleRepositoryPort; @@ -87,13 +89,14 @@ public RoleEntity create(Long groupId) { */ @Override public boolean checkRole(Long userId, Long groupId, GroupMemberRole groupMemberRole) { - RoleEntity roleEntity = groupRoleRepository.findByGroupIdAndRole(groupId, groupMemberRole); - + RoleEntity roleEntity = groupRoleRepository.findByGroupIdAndRole(groupId, groupMemberRole).orElseThrow( + () -> new IllegalArgumentException("not exist role") + ); return groupMemberRepository.existsByUserIdAndRole_Id(userId, roleEntity.getId()); } /** - * 권한 체킁 + * 권한 체크 * @param userId * @param groupId * @param permission @@ -104,8 +107,63 @@ public boolean checkPermission(Long userId, Long groupId, GroupPermission permis return groupRolePermissionRepository.existsUserInGroupPermission(groupId, userId, permission); } + /** + * 권한 추가 + * @param groupId + * @param role + * @param permission + */ + @Override + public List addPermission(Long groupId, GroupMemberRole role, GroupPermission permission) { + + RoleEntity roleEntity = groupRoleRepository.findByGroupIdAndRole(groupId, role).orElseThrow( + () -> new IllegalArgumentException("not exist role") + ); + + PermissionEntity permissionEntity = PermissionEntity.builder() + .groupRoleId(roleEntity.getId()) + .permission(permission) + .build(); + + groupRolePermissionRepository.save(permissionEntity); + + List permissions = groupRolePermissionRepository.findAllByGroupRoleId(roleEntity.getId()); + + return permissions.stream() + .map(PermissionEntity::getPermission) + .toList(); + } + + /** + * 역할에 권한 체크 + * @param role + * @param groupId + * @param permission + * @return + */ + @Override + public boolean existPermission(GroupMemberRole role, Long groupId, GroupPermission permission) { + + RoleEntity roleEntity = groupRoleRepository.findByGroupIdAndRole(groupId, role).orElseThrow( + () -> new IllegalArgumentException("not exist role") + ); + + return groupRolePermissionRepository.existsByGroupRoleIdAndPermission(roleEntity.getId(), permission); + } + @Override public RoleEntity findByIdAndRole(Long id, GroupMemberRole groupMemberRole) { - return groupRoleRepository.findByGroupIdAndRole(id, groupMemberRole); + return groupRoleRepository.findByGroupIdAndRole(id, groupMemberRole).orElseThrow( + () -> new IllegalArgumentException("not exist role") + ); + } + + @Override + public GroupMemberRole findRole(Long userId, Long groupId) { + GroupMemberEntity groupMember = groupMemberRepository.findByGroupIdAndUserId(groupId, userId).orElseThrow( + () -> new IllegalArgumentException("not exists member") + ); + + return groupMember.getRole().getRole(); } } diff --git a/src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java b/src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java new file mode 100644 index 0000000..bd4b4af --- /dev/null +++ b/src/main/java/flipnote/group/api/dto/request/AddPermissionRequestDto.java @@ -0,0 +1,10 @@ +package flipnote.group.api.dto.request; + +import flipnote.group.domain.model.member.GroupMemberRole; +import flipnote.group.domain.model.permission.GroupPermission; + +public record AddPermissionRequestDto( + GroupMemberRole changeRole, + GroupPermission permission +) { +} diff --git a/src/main/java/flipnote/group/api/dto/response/AddPermissionResponseDto.java b/src/main/java/flipnote/group/api/dto/response/AddPermissionResponseDto.java new file mode 100644 index 0000000..843f20b --- /dev/null +++ b/src/main/java/flipnote/group/api/dto/response/AddPermissionResponseDto.java @@ -0,0 +1,17 @@ +package flipnote.group.api.dto.response; + +import java.util.List; + +import flipnote.group.application.port.in.result.AddPermissionResult; +import flipnote.group.domain.model.member.GroupMemberRole; +import flipnote.group.domain.model.permission.GroupPermission; + +public record AddPermissionResponseDto( + GroupMemberRole role, + List permissions +) { + + public static AddPermissionResponseDto from(AddPermissionResult result) { + return new AddPermissionResponseDto(result.role(), result.groupPermissions()); + } +} diff --git a/src/main/java/flipnote/group/application/port/in/AddPermissionUseCase.java b/src/main/java/flipnote/group/application/port/in/AddPermissionUseCase.java new file mode 100644 index 0000000..5972e27 --- /dev/null +++ b/src/main/java/flipnote/group/application/port/in/AddPermissionUseCase.java @@ -0,0 +1,8 @@ +package flipnote.group.application.port.in; + +import flipnote.group.application.port.in.command.AddPermissionCommand; +import flipnote.group.application.port.in.result.AddPermissionResult; + +public interface AddPermissionUseCase { + AddPermissionResult addPermission(AddPermissionCommand cmd); +} diff --git a/src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java b/src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java new file mode 100644 index 0000000..e1aac53 --- /dev/null +++ b/src/main/java/flipnote/group/application/port/in/command/AddPermissionCommand.java @@ -0,0 +1,12 @@ +package flipnote.group.application.port.in.command; + +import flipnote.group.domain.model.member.GroupMemberRole; +import flipnote.group.domain.model.permission.GroupPermission; + +public record AddPermissionCommand( + Long userId, + Long groupId, + GroupMemberRole changeRole, + GroupPermission permission) { + +} diff --git a/src/main/java/flipnote/group/application/port/in/result/AddPermissionResult.java b/src/main/java/flipnote/group/application/port/in/result/AddPermissionResult.java new file mode 100644 index 0000000..9ede24c --- /dev/null +++ b/src/main/java/flipnote/group/application/port/in/result/AddPermissionResult.java @@ -0,0 +1,15 @@ +package flipnote.group.application.port.in.result; + +import java.util.List; + +import flipnote.group.domain.model.member.GroupMemberRole; +import flipnote.group.domain.model.permission.GroupPermission; + +public record AddPermissionResult( + List groupPermissions, + GroupMemberRole role +) { + public static AddPermissionResult of(List groupPermissions, GroupMemberRole role) { + return new AddPermissionResult(groupPermissions, role); + } +} diff --git a/src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java b/src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java index a4799fe..b58433c 100644 --- a/src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java +++ b/src/main/java/flipnote/group/application/port/out/GroupRoleRepositoryPort.java @@ -1,5 +1,7 @@ package flipnote.group.application.port.out; +import java.util.List; + import flipnote.group.adapter.out.entity.RoleEntity; import flipnote.group.domain.model.member.GroupMemberRole; import flipnote.group.domain.model.permission.GroupPermission; @@ -11,5 +13,11 @@ public interface GroupRoleRepositoryPort { boolean checkPermission(Long userId, Long groupId, GroupPermission permission); + List addPermission(Long groupId, GroupMemberRole role, GroupPermission permission); + + boolean existPermission(GroupMemberRole groupMemberRole, Long aLong, GroupPermission permission); + RoleEntity findByIdAndRole(Long id, GroupMemberRole groupMemberRole); + + GroupMemberRole findRole(Long userId, Long groupId); } diff --git a/src/main/java/flipnote/group/application/service/AddPermissionService.java b/src/main/java/flipnote/group/application/service/AddPermissionService.java new file mode 100644 index 0000000..4884ab6 --- /dev/null +++ b/src/main/java/flipnote/group/application/service/AddPermissionService.java @@ -0,0 +1,56 @@ +package flipnote.group.application.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import flipnote.group.application.port.in.AddPermissionUseCase; +import flipnote.group.application.port.in.command.AddPermissionCommand; +import flipnote.group.application.port.in.result.AddPermissionResult; +import flipnote.group.application.port.out.GroupRoleRepositoryPort; +import flipnote.group.domain.model.member.GroupMemberRole; +import flipnote.group.domain.model.permission.GroupPermission; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AddPermissionService implements AddPermissionUseCase { + + private final GroupRoleRepositoryPort groupRoleRepository; + + /** + * 권한 추가 + * @param cmd + * @return + */ + @Override + @Transactional + public AddPermissionResult addPermission(AddPermissionCommand cmd) { + + GroupMemberRole role = groupRoleRepository.findRole(cmd.userId(), cmd.groupId()); + + //호스트의 권한이 있는지 + boolean existHostPermission = groupRoleRepository.checkPermission(cmd.userId(), cmd.groupId(), cmd.permission()); + + if(!existHostPermission) { + throw new IllegalArgumentException("host not exist permission"); + } + + //권한이 낮을 경우 + if(!role.isHigherThan(cmd.changeRole())) { + throw new IllegalArgumentException("host lower than changeRole"); + } + + boolean existPermission = groupRoleRepository.existPermission(cmd.changeRole(), cmd.groupId(), cmd.permission()); + + if(existPermission) { + throw new IllegalArgumentException("already exist permission"); + } + + List groupPermissions = groupRoleRepository.addPermission(cmd.groupId(), cmd.changeRole(), + cmd.permission()); + + return AddPermissionResult.of(groupPermissions, cmd.changeRole()); + } +} diff --git a/src/main/java/flipnote/group/domain/model/member/GroupMemberRole.java b/src/main/java/flipnote/group/domain/model/member/GroupMemberRole.java index e707111..deae380 100644 --- a/src/main/java/flipnote/group/domain/model/member/GroupMemberRole.java +++ b/src/main/java/flipnote/group/domain/model/member/GroupMemberRole.java @@ -1,5 +1,29 @@ package flipnote.group.domain.model.member; public enum GroupMemberRole { - OWNER, HEAD_MANAGER, MANAGER, MEMBER + + OWNER(4), + HEAD_MANAGER(3), + MANAGER(2), + MEMBER(1); + + private final int priority; + + GroupMemberRole(int priority) { + this.priority = priority; + } + + public int getPriority() { + return priority; + } + + //권한 초과 + public boolean isHigherThan(GroupMemberRole other) { + return this.priority > other.priority; + } + + //권한 이상 + public boolean isAtLeast(GroupMemberRole other) { + return this.priority >= other.priority; + } } diff --git a/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java b/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java index 8a59ea6..1e7ba7e 100644 --- a/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java +++ b/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupMemberRepository.java @@ -11,8 +11,6 @@ public interface GroupMemberRepository extends JpaRepository { - boolean existsByUserIdAndRole_Id(Long userId, Long roleId); - boolean existsByGroupIdAndUserId(Long groupId, Long userId); @Query(""" @@ -24,4 +22,6 @@ public interface GroupMemberRepository List findAllByGroupId(Long groupId); Optional findByGroupIdAndUserId(Long groupId, Long userId); + + boolean existsByUserIdAndRole_Id(Long userId, Long id); } diff --git a/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java b/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java index f34e9a3..a0d411f 100644 --- a/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java +++ b/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRolePermissionRepository.java @@ -1,10 +1,16 @@ package flipnote.group.infrastructure.persistence.jpa; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import flipnote.group.adapter.out.entity.PermissionEntity; +import flipnote.group.domain.model.permission.GroupPermission; import flipnote.group.infrastructure.persistence.querydsl.GroupRolePermissionCustom; public interface GroupRolePermissionRepository extends JpaRepository, GroupRolePermissionCustom { + boolean existsByGroupRoleIdAndPermission(Long id, GroupPermission permission); + + List findAllByGroupRoleId(Long id); } diff --git a/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRoleRepository.java b/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRoleRepository.java index 7f774b5..1996b3b 100644 --- a/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRoleRepository.java +++ b/src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRoleRepository.java @@ -1,11 +1,13 @@ package flipnote.group.infrastructure.persistence.jpa; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; import flipnote.group.adapter.out.entity.RoleEntity; import flipnote.group.domain.model.member.GroupMemberRole; public interface GroupRoleRepository extends JpaRepository { - RoleEntity findByGroupIdAndRole(Long groupId, GroupMemberRole groupMemberRole); + Optional findByGroupIdAndRole(Long groupId, GroupMemberRole groupMemberRole); }