feat(permission): 新增对象权限API接口及实现
- 定义ObjectPermissionApi接口提供对象作用域权限查询功能 - 实现ObjectPermissionApiImpl提供角色权限查询和转换逻辑 - 添加ObjectMenuRespDTO、ObjectRoleRespDTO和ObjectRolePermissionRespDTO数据传输对象 - 实现按角色ID、角色编码查询对象作用域角色及权限的功能 - 提供获取对象作用域角色菜单与权限聚合结果的方法 - 添加完整单元测试覆盖对象权限API的主要业务场景
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
package com.njcn.rdms.module.project.service.product;
|
||||
|
||||
import com.njcn.rdms.framework.common.exception.ServiceException;
|
||||
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import com.njcn.rdms.module.project.controller.admin.product.vo.member.ProductMemberRespVO;
|
||||
import com.njcn.rdms.module.project.controller.admin.product.vo.member.ProductMemberSaveReqVO;
|
||||
import com.njcn.rdms.module.project.controller.admin.product.vo.member.ProductMemberUpdateReqVO;
|
||||
import com.njcn.rdms.module.project.dal.dataobject.audit.BizAuditLogDO;
|
||||
import com.njcn.rdms.module.project.dal.dataobject.member.UserObjectRoleDO;
|
||||
import com.njcn.rdms.module.project.dal.dataobject.product.ProductDO;
|
||||
import com.njcn.rdms.module.project.dal.mysql.audit.BizAuditLogMapper;
|
||||
import com.njcn.rdms.module.project.dal.mysql.member.UserObjectRoleMapper;
|
||||
import com.njcn.rdms.module.project.dal.mysql.product.ProductMapper;
|
||||
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
|
||||
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
||||
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class ProductMemberServiceImplTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private ProductMemberServiceImpl productMemberService;
|
||||
@Mock
|
||||
private ProductMapper productMapper;
|
||||
@Mock
|
||||
private UserObjectRoleMapper userObjectRoleMapper;
|
||||
@Mock
|
||||
private ObjectPermissionApi objectPermissionApi;
|
||||
@Mock
|
||||
private BizAuditLogMapper bizAuditLogMapper;
|
||||
@Mock
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@Test
|
||||
void getProductMemberList_shouldFillRoleNameAndRoleCodeFromObjectPermissionApi() {
|
||||
Long productId = 1001L;
|
||||
ProductDO product = createProduct(productId, 2001L);
|
||||
UserObjectRoleDO manager = createMember(9001L, productId, 2001L, 3101L, 0);
|
||||
UserObjectRoleDO member = createMember(9002L, productId, 2002L, 3102L, 0);
|
||||
when(productMapper.selectById(productId)).thenReturn(product);
|
||||
when(userObjectRoleMapper.selectListByObject("product", productId)).thenReturn(List.of(manager, member));
|
||||
when(objectPermissionApi.getObjectRoleList(Set.of(3101L, 3102L), "object", "product"))
|
||||
.thenReturn(success(List.of(
|
||||
createRole(3101L, "product_manager", "产品经理"),
|
||||
createRole(3102L, "product_member", "产品成员")
|
||||
)));
|
||||
when(adminUserApi.getUserMap(Set.of(2001L, 2002L))).thenReturn(Map.of(
|
||||
2001L, createUser("经理甲"),
|
||||
2002L, createUser("成员乙")
|
||||
));
|
||||
|
||||
List<ProductMemberRespVO> respVOList = productMemberService.getProductMemberList(productId);
|
||||
|
||||
assertEquals(2, respVOList.size());
|
||||
assertEquals("产品经理", respVOList.get(0).getRoleName());
|
||||
assertEquals("product_manager", respVOList.get(0).getRoleCode());
|
||||
assertEquals(Boolean.TRUE, respVOList.get(0).getManagerFlag());
|
||||
assertEquals("产品成员", respVOList.get(1).getRoleName());
|
||||
assertEquals("product_member", respVOList.get(1).getRoleCode());
|
||||
assertFalse(respVOList.get(1).getManagerFlag());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createProductMember_whenRoleSummaryMissing_shouldThrowRoleInvalid() {
|
||||
Long productId = 1002L;
|
||||
ProductMemberSaveReqVO reqVO = new ProductMemberSaveReqVO();
|
||||
reqVO.setUserId(2003L);
|
||||
reqVO.setRoleId(3999L);
|
||||
when(productMapper.selectById(productId)).thenReturn(createProduct(productId, 2001L));
|
||||
when(objectPermissionApi.getObjectRoleById(3999L, "object", "product")).thenReturn(success(null));
|
||||
|
||||
ServiceException ex = assertThrows(ServiceException.class,
|
||||
() -> productMemberService.createProductMember(productId, reqVO));
|
||||
|
||||
assertEquals(ErrorCodeConstants.PRODUCT_MEMBER_ROLE_INVALID.getCode(), ex.getCode());
|
||||
verify(userObjectRoleMapper, never()).selectByObjectAndUserId(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateProductMember_whenPreviousManagerRoleCodeStillManager_shouldThrowException() {
|
||||
Long productId = 1003L;
|
||||
Long memberId = 9003L;
|
||||
Long currentManagerUserId = 2001L;
|
||||
Long targetManagerRoleId = 3201L;
|
||||
Long previousManagerRoleId = 3202L;
|
||||
ProductMemberUpdateReqVO reqVO = new ProductMemberUpdateReqVO();
|
||||
reqVO.setRoleId(targetManagerRoleId);
|
||||
reqVO.setPreviousManagerUserId(currentManagerUserId);
|
||||
reqVO.setPreviousManagerRoleId(previousManagerRoleId);
|
||||
reqVO.setReason("角色交接");
|
||||
|
||||
ProductDO product = createProduct(productId, currentManagerUserId);
|
||||
UserObjectRoleDO member = createMember(memberId, productId, 2002L, 3203L, 0);
|
||||
when(productMapper.selectById(productId)).thenReturn(product);
|
||||
when(userObjectRoleMapper.selectByIdAndObject(memberId, "product", productId)).thenReturn(member);
|
||||
when(objectPermissionApi.getObjectRoleById(targetManagerRoleId, "object", "product"))
|
||||
.thenReturn(success(createRole(targetManagerRoleId, "product_manager", "产品经理")));
|
||||
when(objectPermissionApi.getObjectRoleById(previousManagerRoleId, "object", "product"))
|
||||
.thenReturn(success(createRole(previousManagerRoleId, "product_manager", "产品经理")));
|
||||
|
||||
ServiceException ex = assertThrows(ServiceException.class,
|
||||
() -> productMemberService.updateProductMember(productId, memberId, reqVO));
|
||||
|
||||
assertEquals(ErrorCodeConstants.PRODUCT_MANAGER_TRANSFER_ROLE_INVALID.getCode(), ex.getCode());
|
||||
verify(userObjectRoleMapper).updateById(member);
|
||||
verify(productMapper, never()).updateById(any(ProductDO.class));
|
||||
verify(bizAuditLogMapper, never()).insert(any(BizAuditLogDO.class));
|
||||
}
|
||||
|
||||
private ProductDO createProduct(Long productId, Long managerUserId) {
|
||||
ProductDO product = new ProductDO();
|
||||
product.setId(productId);
|
||||
product.setManagerUserId(managerUserId);
|
||||
product.setStatusCode("active");
|
||||
product.setName("测试产品");
|
||||
product.setCode("CNPD2026001");
|
||||
return product;
|
||||
}
|
||||
|
||||
private UserObjectRoleDO createMember(Long memberId, Long productId, Long userId, Long roleId, Integer status) {
|
||||
UserObjectRoleDO member = new UserObjectRoleDO();
|
||||
member.setId(memberId);
|
||||
member.setObjectType("product");
|
||||
member.setObjectId(productId);
|
||||
member.setUserId(userId);
|
||||
member.setRoleId(roleId);
|
||||
member.setStatus(status);
|
||||
member.setJoinedTime(LocalDateTime.now());
|
||||
return member;
|
||||
}
|
||||
|
||||
private ObjectRoleRespDTO createRole(Long roleId, String roleCode, String roleName) {
|
||||
ObjectRoleRespDTO role = new ObjectRoleRespDTO();
|
||||
role.setId(roleId);
|
||||
role.setCode(roleCode);
|
||||
role.setName(roleName);
|
||||
role.setScopeType("object");
|
||||
role.setObjectType("product");
|
||||
return role;
|
||||
}
|
||||
|
||||
private AdminUserRespDTO createUser(String nickname) {
|
||||
AdminUserRespDTO user = new AdminUserRespDTO();
|
||||
user.setNickname(nickname);
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.njcn.rdms.module.system.api.permission;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.framework.common.util.collection.CollectionUtils;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRolePermissionRespDTO;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
|
||||
import com.njcn.rdms.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 对象权限")
|
||||
public interface ObjectPermissionApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/permission/object";
|
||||
|
||||
@GetMapping(PREFIX + "/role-by-id")
|
||||
@Operation(summary = "按角色 ID 查询对象作用域角色摘要")
|
||||
@Parameter(name = "roleId", description = "角色 ID", example = "1024", required = true)
|
||||
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
|
||||
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
|
||||
CommonResult<ObjectRoleRespDTO> getObjectRoleById(@RequestParam("roleId") Long roleId,
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
@GetMapping(PREFIX + "/role-by-code")
|
||||
@Operation(summary = "按角色编码查询对象作用域角色摘要")
|
||||
@Parameter(name = "roleCode", description = "角色编码", example = "product_manager", required = true)
|
||||
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
|
||||
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
|
||||
CommonResult<ObjectRoleRespDTO> getObjectRoleByCode(@RequestParam("roleCode") String roleCode,
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
@GetMapping(PREFIX + "/role-list")
|
||||
@Operation(summary = "按角色 ID 批量查询对象作用域角色摘要")
|
||||
@Parameter(name = "roleIds", description = "角色 ID 集合", example = "1,2", required = true)
|
||||
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
|
||||
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
|
||||
CommonResult<List<ObjectRoleRespDTO>> getObjectRoleList(@RequestParam("roleIds") Collection<Long> roleIds,
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
@GetMapping(PREFIX + "/permissions")
|
||||
@Operation(summary = "查询对象作用域角色权限集合")
|
||||
@Parameter(name = "roleId", description = "角色 ID", example = "1024", required = true)
|
||||
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
|
||||
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
|
||||
CommonResult<Set<String>> getObjectRolePermissions(@RequestParam("roleId") Long roleId,
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
@GetMapping(PREFIX + "/role-permission-detail")
|
||||
@Operation(summary = "查询对象作用域角色菜单与权限聚合结果")
|
||||
@Parameter(name = "roleId", description = "角色 ID", example = "1024", required = true)
|
||||
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
|
||||
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
|
||||
CommonResult<ObjectRolePermissionRespDTO> getObjectRolePermissionDetail(@RequestParam("roleId") Long roleId,
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
/**
|
||||
* 按角色 ID 返回对象作用域角色摘要映射,便于业务模块批量对齐本地成员数据。
|
||||
*
|
||||
* @param roleIds 角色 ID 集合
|
||||
* @param scopeType 权限作用域类型
|
||||
* @param objectType 对象类型
|
||||
* @return 角色摘要映射
|
||||
*/
|
||||
default Map<Long, ObjectRoleRespDTO> getObjectRoleMap(Collection<Long> roleIds, String scopeType, String objectType) {
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
List<ObjectRoleRespDTO> roles = getObjectRoleList(roleIds, scopeType, objectType).getCheckedData();
|
||||
return CollectionUtils.convertMap(roles, ObjectRoleRespDTO::getId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.rdms.module.system.api.permission.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "RPC 服务 - 对象作用域菜单 Response DTO")
|
||||
@Data
|
||||
public class ObjectMenuRespDTO {
|
||||
|
||||
@Schema(description = "菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品设置")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "权限标识", example = "project:product:update")
|
||||
private String permission;
|
||||
|
||||
@Schema(description = "菜单类型;允许返回目录、菜单、按钮,业务侧可按 type 再拆分导航或按钮", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "显示排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "路由路径", example = "/project/product/detail")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "菜单图标", example = "ep:box")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean visible;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.njcn.rdms.module.system.api.permission.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "RPC 服务 - 对象作用域角色权限聚合 Response DTO")
|
||||
@Data
|
||||
public class ObjectRolePermissionRespDTO {
|
||||
|
||||
@Schema(description = "当前查询 roleId 对应的角色摘要,不表示登录态上下文里的当前用户角色")
|
||||
private ObjectRoleRespDTO currentRole;
|
||||
|
||||
@ArraySchema(schema = @Schema(description = "当前查询角色在指定 scopeType/objectType 下可消费的已启用菜单资源明细;允许包含目录、菜单、按钮,业务侧可按 type 再拆分导航或按钮"))
|
||||
private List<ObjectMenuRespDTO> menus;
|
||||
|
||||
@ArraySchema(schema = @Schema(description = "基于同一批有效菜单资源归一化提取出的权限标识集合,供对象权限校验直接消费", example = "project:product:query"))
|
||||
private Set<String> permissions;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.njcn.rdms.module.system.api.permission.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "RPC 服务 - 对象作用域角色摘要 Response DTO")
|
||||
@Data
|
||||
public class ObjectRoleRespDTO {
|
||||
|
||||
@Schema(description = "角色 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "product_manager")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品经理")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "权限作用域类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "object")
|
||||
private String scopeType;
|
||||
|
||||
@Schema(description = "对象类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "product")
|
||||
private String objectType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.njcn.rdms.module.system.api.permission;
|
||||
|
||||
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectMenuRespDTO;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRolePermissionRespDTO;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.njcn.rdms.module.system.service.permission.PermissionService;
|
||||
import com.njcn.rdms.module.system.service.permission.RoleService;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
@Primary
|
||||
@Hidden
|
||||
public class ObjectPermissionApiImpl implements ObjectPermissionApi {
|
||||
|
||||
@Resource
|
||||
private RoleService roleService;
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Override
|
||||
public CommonResult<ObjectRoleRespDTO> getObjectRoleById(Long roleId, String scopeType, String objectType) {
|
||||
return success(convertRole(roleService.getRole(roleId, scopeType, objectType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<ObjectRoleRespDTO> getObjectRoleByCode(String roleCode, String scopeType, String objectType) {
|
||||
return success(convertRole(roleService.getRoleByCode(roleCode, scopeType, objectType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ObjectRoleRespDTO>> getObjectRoleList(Collection<Long> roleIds, String scopeType, String objectType) {
|
||||
List<RoleDO> roles = roleService.getRoleList(roleIds, scopeType, objectType);
|
||||
return success(roles.stream().map(this::convertRole).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Set<String>> getObjectRolePermissions(Long roleId, String scopeType, String objectType) {
|
||||
RoleDO role = getEnabledScopedRole(roleId, scopeType, objectType);
|
||||
if (role == null) {
|
||||
return success(Collections.emptySet());
|
||||
}
|
||||
return success(new LinkedHashSet<>(permissionService.getScopedPermissionsByRoleId(roleId, scopeType, objectType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<ObjectRolePermissionRespDTO> getObjectRolePermissionDetail(Long roleId, String scopeType, String objectType) {
|
||||
RoleDO role = getEnabledScopedRole(roleId, scopeType, objectType);
|
||||
if (role == null) {
|
||||
return success(emptyPermissionDetail());
|
||||
}
|
||||
|
||||
ObjectRolePermissionRespDTO detail = new ObjectRolePermissionRespDTO();
|
||||
detail.setCurrentRole(convertRole(role));
|
||||
detail.setMenus(permissionService.getScopedMenusByRoleId(roleId, scopeType, objectType)
|
||||
.stream()
|
||||
.map(this::convertMenu)
|
||||
.toList());
|
||||
detail.setPermissions(new LinkedHashSet<>(
|
||||
permissionService.getScopedPermissionsByRoleId(roleId, scopeType, objectType)));
|
||||
return success(detail);
|
||||
}
|
||||
|
||||
private ObjectRolePermissionRespDTO emptyPermissionDetail() {
|
||||
ObjectRolePermissionRespDTO detail = new ObjectRolePermissionRespDTO();
|
||||
detail.setCurrentRole(null);
|
||||
detail.setMenus(Collections.emptyList());
|
||||
detail.setPermissions(Collections.emptySet());
|
||||
return detail;
|
||||
}
|
||||
|
||||
private RoleDO getEnabledScopedRole(Long roleId, String scopeType, String objectType) {
|
||||
RoleDO role = roleService.getRole(roleId, scopeType, objectType);
|
||||
if (role == null || !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) {
|
||||
return null;
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
private ObjectRoleRespDTO convertRole(RoleDO role) {
|
||||
if (role == null) {
|
||||
return null;
|
||||
}
|
||||
ObjectRoleRespDTO dto = new ObjectRoleRespDTO();
|
||||
dto.setId(role.getId());
|
||||
dto.setCode(role.getCode());
|
||||
dto.setName(role.getName());
|
||||
dto.setScopeType(role.getScopeType());
|
||||
dto.setObjectType(role.getObjectType());
|
||||
return dto;
|
||||
}
|
||||
|
||||
private ObjectMenuRespDTO convertMenu(MenuDO menu) {
|
||||
ObjectMenuRespDTO dto = new ObjectMenuRespDTO();
|
||||
dto.setId(menu.getId());
|
||||
dto.setName(menu.getName());
|
||||
dto.setPermission(menu.getPermission());
|
||||
dto.setType(menu.getType());
|
||||
dto.setSort(menu.getSort());
|
||||
dto.setPath(menu.getPath());
|
||||
dto.setIcon(menu.getIcon());
|
||||
dto.setVisible(menu.getVisible());
|
||||
return dto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
package com.njcn.rdms.module.system.api.permission;
|
||||
|
||||
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectMenuRespDTO;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRolePermissionRespDTO;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.MenuMapper;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMapper;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMenuMapper;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.UserRoleMapper;
|
||||
import com.njcn.rdms.module.system.service.permission.MenuServiceImpl;
|
||||
import com.njcn.rdms.module.system.service.permission.PermissionService;
|
||||
import com.njcn.rdms.module.system.service.permission.PermissionServiceImpl;
|
||||
import com.njcn.rdms.module.system.service.permission.RoleService;
|
||||
import com.njcn.rdms.module.system.service.permission.RoleServiceImpl;
|
||||
import com.njcn.rdms.module.system.service.user.AdminUserService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class ObjectPermissionApiImplTest extends BaseMockitoUnitTest {
|
||||
|
||||
private static final String OBJECT_SCOPE = "object";
|
||||
private static final String PRODUCT_OBJECT = "product";
|
||||
private static final String GLOBAL_SCOPE = "global";
|
||||
private static final String GLOBAL_OBJECT = "";
|
||||
|
||||
@Mock
|
||||
private RoleService roleService;
|
||||
@Mock
|
||||
private PermissionService permissionService;
|
||||
@Mock
|
||||
private RoleMapper roleMapper;
|
||||
@Mock
|
||||
private RoleMenuMapper roleMenuMapper;
|
||||
@Mock
|
||||
private MenuMapper menuMapper;
|
||||
@Mock
|
||||
private UserRoleMapper userRoleMapper;
|
||||
@Mock
|
||||
private AdminUserService userService;
|
||||
|
||||
@InjectMocks
|
||||
private ObjectPermissionApiImpl objectPermissionApi;
|
||||
|
||||
@Test
|
||||
void getObjectRoleById_whenRoleExistsAndEnabled_thenReturnRoleSummary() {
|
||||
RoleDO role = buildRole(101L, "qa_owner", "QA Owner", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
role.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
when(roleService.getRole(101L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
|
||||
CommonResult<ObjectRoleRespDTO> result =
|
||||
objectPermissionApi.getObjectRoleById(101L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
ObjectRoleRespDTO data = result.getCheckedData();
|
||||
assertNotNull(data);
|
||||
assertEquals(101L, data.getId());
|
||||
assertEquals("qa_owner", data.getCode());
|
||||
assertEquals("QA Owner", data.getName());
|
||||
assertEquals(OBJECT_SCOPE, data.getScopeType());
|
||||
assertEquals(PRODUCT_OBJECT, data.getObjectType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRoleById_whenRoleMissing_thenReturnNull() {
|
||||
when(roleService.getRole(404L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(null);
|
||||
|
||||
CommonResult<ObjectRoleRespDTO> result =
|
||||
objectPermissionApi.getObjectRoleById(404L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertNull(result.getCheckedData());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRoleByCode_whenRoleExists_thenReturnProductManagerRole() {
|
||||
RoleDO role = buildRole(102L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
when(roleService.getRoleByCode("product_manager", OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
|
||||
CommonResult<ObjectRoleRespDTO> result =
|
||||
objectPermissionApi.getObjectRoleByCode("product_manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
ObjectRoleRespDTO data = result.getCheckedData();
|
||||
assertNotNull(data);
|
||||
assertEquals(102L, data.getId());
|
||||
assertEquals("product_manager", data.getCode());
|
||||
assertEquals("Product Manager", data.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRoleList_shouldFilterScopedRolesThroughRoleServiceImpl() {
|
||||
RoleServiceImpl realRoleService = createRoleServiceImpl();
|
||||
ObjectPermissionApiImpl realApi = createObjectPermissionApi(realRoleService, permissionService);
|
||||
Map<Long, RoleDO> roleStore = new LinkedHashMap<>();
|
||||
roleStore.put(201L, buildRole(201L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT));
|
||||
roleStore.put(202L, buildRole(202L, "global_admin", "Global Admin", GLOBAL_SCOPE, GLOBAL_OBJECT));
|
||||
roleStore.put(203L, buildRole(203L, "project_manager", "Project Manager", OBJECT_SCOPE, "project"));
|
||||
roleStore.put(204L, buildRole(204L, "product_tester", "Product Tester", OBJECT_SCOPE, PRODUCT_OBJECT));
|
||||
when(roleMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(roleStore, invocation.getArgument(0)));
|
||||
|
||||
CommonResult<List<ObjectRoleRespDTO>> result =
|
||||
realApi.getObjectRoleList(List.of(201L, 202L, 203L, 204L), OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
List<ObjectRoleRespDTO> data = result.getCheckedData();
|
||||
assertEquals(List.of(201L, 204L), data.stream().map(ObjectRoleRespDTO::getId).toList());
|
||||
assertEquals(List.of("product_manager", "product_tester"),
|
||||
data.stream().map(ObjectRoleRespDTO::getCode).toList());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRolePermissions_whenRoleMissing_thenReturnEmptySet() {
|
||||
when(roleService.getRole(303L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(null);
|
||||
|
||||
CommonResult<Set<String>> result =
|
||||
objectPermissionApi.getObjectRolePermissions(303L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertTrue(result.getCheckedData().isEmpty());
|
||||
verifyNoInteractions(permissionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRolePermissions_whenRoleDisabled_thenReturnEmptySet() {
|
||||
RoleDO role = buildRole(304L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
role.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
when(roleService.getRole(304L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
|
||||
CommonResult<Set<String>> result =
|
||||
objectPermissionApi.getObjectRolePermissions(304L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertTrue(result.getCheckedData().isEmpty());
|
||||
verifyNoInteractions(permissionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void permissionServiceImpl_getScopedPermissionsByRoleId_shouldExtractButtonPermissionFromEffectiveMenus() {
|
||||
MenuServiceImpl realMenuService = createMenuServiceImpl();
|
||||
PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
|
||||
RoleDO role = buildRole(301L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
MenuDO menu = buildMenu(3011L, "Product Setting", null, 2, 10, "/product/setting",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO button = buildMenu(3012L, "Save", "project:product:update", 3, 20, null,
|
||||
3011L, CommonStatusEnum.ENABLE.getStatus());
|
||||
Map<Long, MenuDO> menuStore = menuStore(menu, button);
|
||||
when(roleService.getRole(301L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
when(roleService.getRoleList(Collections.singleton(301L), OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(List.of(role));
|
||||
when(roleMenuMapper.selectListByRoleId(Collections.singleton(301L)))
|
||||
.thenReturn(List.of(buildRoleMenu(301L, 3011L), buildRoleMenu(301L, 3012L)));
|
||||
when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));
|
||||
|
||||
Set<String> permissions = realPermissionService.getScopedPermissionsByRoleId(301L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertEquals(Set.of("project:product:update"), permissions);
|
||||
}
|
||||
|
||||
@Test
|
||||
void permissionServiceImpl_getScopedMenusAndPermissionsByRoleId_shouldReturnEmptyResultsWhenRoleIsDisabled() {
|
||||
MenuServiceImpl realMenuService = createMenuServiceImpl();
|
||||
PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
|
||||
RoleDO disabledRole = buildRole(305L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
disabledRole.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
when(roleService.getRole(305L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(disabledRole);
|
||||
|
||||
List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(305L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
Set<String> permissions = realPermissionService.getScopedPermissionsByRoleId(305L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertTrue(menus.isEmpty());
|
||||
assertTrue(permissions.isEmpty());
|
||||
verifyNoInteractions(roleMenuMapper, menuMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
void permissionServiceImpl_getScopedMenusAndPermissionsByRoleId_shouldIgnoreMenusOutsideRequestedScopeAndObject() {
|
||||
MenuServiceImpl realMenuService = createMenuServiceImpl();
|
||||
PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
|
||||
RoleDO role = buildRole(3051L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
MenuDO directory = buildMenu(30511L, "Product", null, 1, 1, "/product",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO scopedButton = buildMenu(30512L, "Save", "project:product:update", 3, 10, null,
|
||||
30511L, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO globalButton = buildMenu(30513L, "Global Export", "system:global:export", 3, 20, null,
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus(), GLOBAL_SCOPE, GLOBAL_OBJECT);
|
||||
MenuDO otherObjectButton = buildMenu(30514L, "Project Publish", "project:project:publish", 3, 30, null,
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus(), OBJECT_SCOPE, "project");
|
||||
Map<Long, MenuDO> menuStore = menuStore(directory, scopedButton, globalButton, otherObjectButton);
|
||||
when(roleService.getRole(3051L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
when(roleService.getRoleList(Collections.singleton(3051L), OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(List.of(role));
|
||||
when(roleMenuMapper.selectListByRoleId(Collections.singleton(3051L)))
|
||||
.thenReturn(List.of(buildRoleMenu(3051L, 30511L), buildRoleMenu(3051L, 30512L),
|
||||
buildRoleMenu(3051L, 30513L),
|
||||
buildRoleMenu(3051L, 30514L)));
|
||||
when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));
|
||||
|
||||
List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(3051L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
Set<String> permissions = realPermissionService.getScopedPermissionsByRoleId(3051L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertEquals(Set.of(30511L, 30512L),
|
||||
menus.stream().map(MenuDO::getId).collect(LinkedHashSet::new, Set::add, Set::addAll));
|
||||
assertEquals(Set.of("project:product:update"), permissions);
|
||||
}
|
||||
|
||||
@Test
|
||||
void permissionServiceImpl_getRoleMenuListByRoleIdScopedCollection_shouldExcludeDisabledRoles() {
|
||||
MenuServiceImpl realMenuService = createMenuServiceImpl();
|
||||
PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
|
||||
RoleDO enabledRole = buildRole(306L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
RoleDO disabledRole = buildRole(307L, "product_viewer", "Product Viewer", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
disabledRole.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
MenuDO enabledMenu = buildMenu(3061L, "Enabled Menu", null, 2, 10, "/product/enabled",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO disabledRoleMenu = buildMenu(3071L, "Disabled Role Menu", null, 2, 20, "/product/disabled-role",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
Map<Long, MenuDO> menuStore = menuStore(enabledMenu, disabledRoleMenu);
|
||||
when(roleService.getRoleList(List.of(306L, 307L), OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(List.of(enabledRole, disabledRole));
|
||||
when(roleMenuMapper.selectListByRoleId(org.mockito.ArgumentMatchers.<Collection<Long>>any())).thenAnswer(invocation -> {
|
||||
Collection<Long> roleIds = invocation.getArgument(0);
|
||||
List<RoleMenuDO> results = new ArrayList<>();
|
||||
if (roleIds.contains(306L)) {
|
||||
results.add(buildRoleMenu(306L, 3061L));
|
||||
}
|
||||
if (roleIds.contains(307L)) {
|
||||
results.add(buildRoleMenu(307L, 3071L));
|
||||
}
|
||||
return results;
|
||||
});
|
||||
when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));
|
||||
|
||||
Set<Long> menuIds = realPermissionService.getRoleMenuListByRoleId(List.of(306L, 307L), OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertEquals(Set.of(3061L), menuIds);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRolePermissionDetail_whenRoleMissing_thenReturnEmptyDetail() {
|
||||
when(roleService.getRole(401L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(null);
|
||||
|
||||
CommonResult<ObjectRolePermissionRespDTO> result =
|
||||
objectPermissionApi.getObjectRolePermissionDetail(401L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
ObjectRolePermissionRespDTO detail = result.getCheckedData();
|
||||
assertNotNull(detail);
|
||||
assertNull(detail.getCurrentRole());
|
||||
assertTrue(detail.getMenus().isEmpty());
|
||||
assertTrue(detail.getPermissions().isEmpty());
|
||||
verifyNoInteractions(permissionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRolePermissionDetail_whenRoleDisabled_thenReturnEmptyDetail() {
|
||||
RoleDO role = buildRole(405L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
role.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
when(roleService.getRole(405L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
|
||||
CommonResult<ObjectRolePermissionRespDTO> result =
|
||||
objectPermissionApi.getObjectRolePermissionDetail(405L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
ObjectRolePermissionRespDTO detail = result.getCheckedData();
|
||||
assertNotNull(detail);
|
||||
assertNull(detail.getCurrentRole());
|
||||
assertTrue(detail.getMenus().isEmpty());
|
||||
assertTrue(detail.getPermissions().isEmpty());
|
||||
verifyNoInteractions(permissionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getObjectRolePermissionDetail_shouldAggregateRoleMenusAndPermissions() {
|
||||
RoleDO role = buildRole(402L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
MenuDO directory = buildMenu(11L, "Product", null, 1, 1, "/product",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO menu = buildMenu(12L, "Product Setting", null, 2, 10, "/product/setting",
|
||||
11L, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO button = buildMenu(13L, "Save", "project:product:update", 3, 20, null,
|
||||
12L, CommonStatusEnum.ENABLE.getStatus());
|
||||
Set<String> permissions = new LinkedHashSet<>(Set.of("project:product:update"));
|
||||
when(roleService.getRole(402L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
when(permissionService.getScopedMenusByRoleId(402L, OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(List.of(directory, menu, button));
|
||||
when(permissionService.getScopedPermissionsByRoleId(402L, OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(permissions);
|
||||
|
||||
CommonResult<ObjectRolePermissionRespDTO> result =
|
||||
objectPermissionApi.getObjectRolePermissionDetail(402L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
ObjectRolePermissionRespDTO detail = result.getCheckedData();
|
||||
assertNotNull(detail.getCurrentRole());
|
||||
assertEquals(3, detail.getMenus().size());
|
||||
assertEquals(List.of(11L, 12L, 13L), detail.getMenus().stream().map(ObjectMenuRespDTO::getId).toList());
|
||||
assertEquals(permissions, detail.getPermissions());
|
||||
}
|
||||
|
||||
@Test
|
||||
void permissionServiceImpl_getScopedMenusByRoleId_shouldExcludeDisabledMenus() {
|
||||
MenuServiceImpl realMenuService = createMenuServiceImpl();
|
||||
PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
|
||||
RoleDO role = buildRole(403L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
MenuDO enabledMenu = buildMenu(21L, "Enabled Menu", null, 2, 10, "/product/setting",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO disabledMenu = buildMenu(22L, "Disabled Menu", null, 2, 20, "/product/disabled",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.DISABLE.getStatus());
|
||||
Map<Long, MenuDO> menuStore = menuStore(enabledMenu, disabledMenu);
|
||||
when(roleService.getRole(403L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
when(roleService.getRoleList(Collections.singleton(403L), OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(List.of(role));
|
||||
when(roleMenuMapper.selectListByRoleId(Collections.singleton(403L)))
|
||||
.thenReturn(List.of(buildRoleMenu(403L, 21L), buildRoleMenu(403L, 22L)));
|
||||
when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));
|
||||
|
||||
List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(403L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
List<Long> menuIds = menus.stream().map(MenuDO::getId).toList();
|
||||
assertEquals(List.of(21L), menuIds);
|
||||
assertFalse(menuIds.contains(22L));
|
||||
}
|
||||
|
||||
void permissionServiceImpl_getScopedMenusByRoleId_shouldKeepAncestorMenusAfterExpandedRoleMenuAssignments() {
|
||||
MenuServiceImpl realMenuService = createMenuServiceImpl();
|
||||
PermissionServiceImpl realPermissionService = createPermissionServiceImpl(roleService, realMenuService);
|
||||
RoleDO role = buildRole(404L, "product_manager", "Product Manager", OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
MenuDO directory = buildMenu(31L, "Product", null, 1, 1, "/product",
|
||||
MenuDO.ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO childMenu = buildMenu(32L, "Product Setting", null, 2, 10, "/product/setting",
|
||||
31L, CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuDO button = buildMenu(33L, "Save", "project:product:update", 3, 20, null,
|
||||
32L, CommonStatusEnum.ENABLE.getStatus());
|
||||
Map<Long, MenuDO> menuStore = menuStore(directory, childMenu, button);
|
||||
List<RoleMenuDO> persistedRoleMenus = new ArrayList<>();
|
||||
when(roleService.getRole(404L)).thenReturn(role);
|
||||
when(roleService.getRole(404L, OBJECT_SCOPE, PRODUCT_OBJECT)).thenReturn(role);
|
||||
when(roleService.getRoleList(Collections.singleton(404L), OBJECT_SCOPE, PRODUCT_OBJECT))
|
||||
.thenReturn(List.of(role));
|
||||
when(roleMenuMapper.selectListByRoleId(404L)).thenReturn(Collections.emptyList());
|
||||
doAnswer(invocation -> {
|
||||
persistedRoleMenus.clear();
|
||||
persistedRoleMenus.addAll(invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(roleMenuMapper).insertBatch(any());
|
||||
when(roleMenuMapper.selectListByRoleId(Collections.singleton(404L)))
|
||||
.thenAnswer(invocation -> new ArrayList<>(persistedRoleMenus));
|
||||
when(menuMapper.selectByIds(any())).thenAnswer(invocation -> selectValues(menuStore, invocation.getArgument(0)));
|
||||
|
||||
realPermissionService.assignRoleMenu(404L, Set.of(32L, 33L));
|
||||
List<MenuDO> menus = realPermissionService.getScopedMenusByRoleId(404L, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
|
||||
assertEquals(Set.of(31L, 32L, 33L), menus.stream().map(MenuDO::getId).collect(LinkedHashSet::new, Set::add, Set::addAll));
|
||||
assertEquals(Set.of("Product", "Product Setting", "Save"),
|
||||
menus.stream().map(MenuDO::getName).collect(LinkedHashSet::new, Set::add, Set::addAll));
|
||||
}
|
||||
|
||||
private RoleServiceImpl createRoleServiceImpl() {
|
||||
RoleServiceImpl roleServiceImpl = new RoleServiceImpl();
|
||||
ReflectionTestUtils.setField(roleServiceImpl, "permissionService", permissionService);
|
||||
ReflectionTestUtils.setField(roleServiceImpl, "roleMapper", roleMapper);
|
||||
ReflectionTestUtils.setField(roleServiceImpl, "userRoleMapper", userRoleMapper);
|
||||
return roleServiceImpl;
|
||||
}
|
||||
|
||||
private MenuServiceImpl createMenuServiceImpl() {
|
||||
MenuServiceImpl menuServiceImpl = new MenuServiceImpl();
|
||||
ReflectionTestUtils.setField(menuServiceImpl, "menuMapper", menuMapper);
|
||||
ReflectionTestUtils.setField(menuServiceImpl, "permissionService", permissionService);
|
||||
return menuServiceImpl;
|
||||
}
|
||||
|
||||
private PermissionServiceImpl createPermissionServiceImpl(RoleService roleServiceDependency,
|
||||
MenuServiceImpl menuServiceDependency) {
|
||||
PermissionServiceImpl permissionServiceImpl = new PermissionServiceImpl();
|
||||
ReflectionTestUtils.setField(permissionServiceImpl, "roleMenuMapper", roleMenuMapper);
|
||||
ReflectionTestUtils.setField(permissionServiceImpl, "userRoleMapper", userRoleMapper);
|
||||
ReflectionTestUtils.setField(permissionServiceImpl, "roleService", roleServiceDependency);
|
||||
ReflectionTestUtils.setField(permissionServiceImpl, "menuService", menuServiceDependency);
|
||||
ReflectionTestUtils.setField(permissionServiceImpl, "userService", userService);
|
||||
return permissionServiceImpl;
|
||||
}
|
||||
|
||||
private ObjectPermissionApiImpl createObjectPermissionApi(RoleService roleServiceDependency,
|
||||
PermissionService permissionServiceDependency) {
|
||||
ObjectPermissionApiImpl api = new ObjectPermissionApiImpl();
|
||||
ReflectionTestUtils.setField(api, "roleService", roleServiceDependency);
|
||||
ReflectionTestUtils.setField(api, "permissionService", permissionServiceDependency);
|
||||
return api;
|
||||
}
|
||||
|
||||
private static RoleDO buildRole(Long id, String code, String name, String scopeType, String objectType) {
|
||||
RoleDO role = new RoleDO();
|
||||
role.setId(id);
|
||||
role.setCode(code);
|
||||
role.setName(name);
|
||||
role.setScopeType(scopeType);
|
||||
role.setObjectType(objectType);
|
||||
role.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return role;
|
||||
}
|
||||
|
||||
private static MenuDO buildMenu(Long id, String name, String permission, Integer type, Integer sort, String path,
|
||||
Long parentId, Integer status) {
|
||||
return buildMenu(id, name, permission, type, sort, path, parentId, status, OBJECT_SCOPE, PRODUCT_OBJECT);
|
||||
}
|
||||
|
||||
private static MenuDO buildMenu(Long id, String name, String permission, Integer type, Integer sort, String path,
|
||||
Long parentId, Integer status, String scopeType, String objectType) {
|
||||
MenuDO menu = new MenuDO();
|
||||
menu.setId(id);
|
||||
menu.setName(name);
|
||||
menu.setPermission(permission);
|
||||
menu.setType(type);
|
||||
menu.setSort(sort);
|
||||
menu.setPath(path);
|
||||
menu.setParentId(parentId);
|
||||
menu.setStatus(status);
|
||||
menu.setVisible(Boolean.TRUE);
|
||||
menu.setScopeType(scopeType);
|
||||
menu.setObjectType(objectType);
|
||||
return menu;
|
||||
}
|
||||
|
||||
private static RoleMenuDO buildRoleMenu(Long roleId, Long menuId) {
|
||||
RoleMenuDO roleMenu = new RoleMenuDO();
|
||||
roleMenu.setRoleId(roleId);
|
||||
roleMenu.setMenuId(menuId);
|
||||
return roleMenu;
|
||||
}
|
||||
|
||||
private static <T> List<T> selectValues(Map<Long, T> store, Collection<Long> ids) {
|
||||
return ids.stream()
|
||||
.map(store::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
|
||||
}
|
||||
|
||||
private static Map<Long, MenuDO> menuStore(MenuDO... menus) {
|
||||
Map<Long, MenuDO> results = new LinkedHashMap<>();
|
||||
for (MenuDO menu : menus) {
|
||||
results.put(menu.getId(), menu);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user