From 5572bf3fcb4b0092a1c852f2c8613bc9005fefba Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Feb 2023 23:57:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=20PermissionService=20?= =?UTF-8?q?=E7=9A=84=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/PermissionController.java | 4 +- .../system/dal/redis/RedisKeyConstants.java | 16 +- .../service/permission/PermissionService.java | 50 +- .../permission/PermissionServiceImpl.java | 143 ++--- .../service/permission/RoleServiceImpl.java | 3 + .../permission/PermissionServiceTest.java | 492 ++++++++++-------- 6 files changed, 407 insertions(+), 301 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java index f6408cf1dc..91f5d4266f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java @@ -37,9 +37,9 @@ public class PermissionController { @Operation(summary = "获得角色拥有的菜单编号") @Parameter(name = "roleId", description = "角色编号", required = true) - @GetMapping("/list-role-resources") + @GetMapping("/list-role-menus") @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") - public CommonResult> listRoleMenus(Long roleId) { + public CommonResult> getRoleMenuList(Long roleId) { return success(permissionService.getRoleMenuListByRoleId(roleId)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java index 49559370d8..16862fa841 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java @@ -26,6 +26,14 @@ public interface RedisKeyConstants { "social_auth_state:%s", // 参数为 state STRING, String.class, Duration.ofHours(24)); // 值为 state + /** + * 指定部门的所有子部门编号数组的缓存 + * + * KEY 格式:dept_children_ids::{id} + * 数据类型:String 子部门编号集合 + */ + String DEPT_CHILDREN_ID_LIST = "dept_children_ids"; + /** * 角色的缓存 * @@ -50,14 +58,6 @@ public interface RedisKeyConstants { */ String MENU_ROLE_ID_LIST = "menu_role_ids"; - /** - * 指定部门的所有子部门编号数组的缓存 - * - * KEY 格式:dept_children_ids::{id} - * 数据类型:String 子部门编号集合 - */ - String DEPT_CHILDREN_ID_LIST = "dept_children_ids"; - /** * 拥有权限对应的菜单编号数组的缓存 * diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java index 933e3cbff4..792618778d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java @@ -33,6 +33,16 @@ public interface PermissionService { */ boolean hasAnyRoles(Long userId, String... roles); + // ========== 角色-菜单的相关方法 ========== + + /** + * 设置角色菜单 + * + * @param roleId 角色编号 + * @param menuIds 菜单编号集合 + */ + void assignRoleMenu(Long roleId, Set menuIds); + /** * 处理角色删除时,删除关联授权数据 * @@ -47,15 +57,6 @@ public interface PermissionService { */ void processMenuDeleted(Long menuId); - /** - * 处理用户删除是,删除关联授权数据 - * - * @param userId 用户编号 - */ - void processUserDeleted(Long userId); - - // ========== 角色-菜单的相关方法 ========== - /** * 获得角色拥有的菜单编号集合 * @@ -84,6 +85,21 @@ public interface PermissionService { // ========== 用户-角色的相关方法 ========== + /** + * 设置用户角色 + * + * @param userId 角色编号 + * @param roleIds 角色编号集合 + */ + void assignUserRole(Long userId, Set roleIds); + + /** + * 处理用户删除时,删除关联授权数据 + * + * @param userId 用户编号 + */ + void processUserDeleted(Long userId); + /** * 获得拥有多个角色的用户编号集合 * @@ -92,14 +108,6 @@ public interface PermissionService { */ Set getUserRoleIdListByRoleId(Collection roleIds); - /** - * 设置角色菜单 - * - * @param roleId 角色编号 - * @param menuIds 菜单编号集合 - */ - void assignRoleMenu(Long roleId, Set menuIds); - /** * 获得用户拥有的角色编号集合 * @@ -116,14 +124,6 @@ public interface PermissionService { */ Set getUserRoleIdListByUserIdFromCache(Long userId); - /** - * 设置用户角色 - * - * @param userId 角色编号 - * @param roleIds 角色编号集合 - */ - void assignUserRole(Long userId, Set roleIds); - // ========== 用户-部门的相关方法 ========== /** diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java index b342d2211d..81bfcfc1fb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java @@ -18,18 +18,19 @@ import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.module.system.service.dept.DeptService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.function.Supplier; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @@ -99,7 +100,7 @@ public class PermissionServiceImpl implements PermissionService { // 判断是否有权限 Set roleIds = convertSet(roles, RoleDO::getId); for (Long menuId : menuIds) { - // 拥有该角色的菜单编号数组 + // 获得拥有该菜单的角色编号集合 Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId); // 如果有交集,说明有权限 if (CollUtil.containsAny(menuRoleIds, roleIds)) { @@ -127,8 +128,59 @@ public class PermissionServiceImpl implements PermissionService { return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); } + // ========== 角色-菜单的相关方法 ========== + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 + public void assignRoleMenu(Long roleId, Set menuIds) { + // 获得角色拥有菜单编号 + Set dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); + // 计算新增和删除的菜单编号 + Collection createMenuIds = CollUtil.subtract(menuIds, dbMenuIds); + Collection deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIds); + // 执行新增和删除。对于已经授权的菜单,不用做任何处理 + if (CollUtil.isNotEmpty(createMenuIds)) { + roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { + RoleMenuDO entity = new RoleMenuDO(); + entity.setRoleId(roleId); + entity.setMenuId(menuId); + return entity; + })); + } + if (CollUtil.isNotEmpty(deleteMenuIds)) { + roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + @Caching(evict = { + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true), // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 menu 缓存们 + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 user 缓存们 + }) + public void processRoleDeleted(Long roleId) { + // 标记删除 UserRole + userRoleMapper.deleteListByRoleId(roleId); + // 标记删除 RoleMenu + roleMenuMapper.deleteListByRoleId(roleId); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") + public void processMenuDeleted(Long menuId) { + roleMenuMapper.deleteListByMenuId(menuId); + } + @Override public Set getRoleMenuListByRoleId(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Collections.emptySet(); + } + // 如果是管理员的情况下,获取全部菜单编号 if (roleService.hasAnySuperAdmin(roleIds)) { return convertSet(menuService.getMenuList(), MenuDO::getId); @@ -143,28 +195,38 @@ public class PermissionServiceImpl implements PermissionService { return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId); } + // ========== 用户-角色的相关方法 ========== + @Override -// @Transactional(rollbackFor = Exception.class) // TODO 芋艿:不能使用 MySQL 事务 - public void assignRoleMenu(Long roleId, Set menuIds) { - // 获得角色拥有菜单编号 - Set dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); - // 计算新增和删除的菜单编号 - Collection createMenuIds = CollUtil.subtract(menuIds, dbMenuIds); - Collection deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIds); - // 执行新增和删除。对于已经授权的菜单,不用做任何处理 - if (!CollectionUtil.isEmpty(createMenuIds)) { - roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { - RoleMenuDO entity = new RoleMenuDO(); + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public void assignUserRole(Long userId, Set roleIds) { + // 获得角色拥有角色编号 + Set dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId), + UserRoleDO::getRoleId); + // 计算新增和删除的角色编号 + Collection createRoleIds = CollUtil.subtract(roleIds, dbRoleIds); + Collection deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIds); + // 执行新增和删除。对于已经授权的角色,不用做任何处理 + if (!CollectionUtil.isEmpty(createRoleIds)) { + userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleIds, roleId -> { + UserRoleDO entity = new UserRoleDO(); + entity.setUserId(userId); entity.setRoleId(roleId); - entity.setMenuId(menuId); return entity; })); } if (!CollectionUtil.isEmpty(deleteMenuIds)) { - roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); + userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); } } + @Override + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public void processUserDeleted(Long userId) { + userRoleMapper.deleteListByUserId(userId); + } + @Override public Set getUserRoleIdListByUserId(Long userId) { return convertSet(userRoleMapper.selectListByUserId(userId), UserRoleDO::getRoleId); @@ -187,7 +249,8 @@ public class PermissionServiceImpl implements PermissionService { * @param userId 用户编号 * @return 用户拥有的角色 */ - private List getEnableUserRoleListByUserIdFromCache(Long userId) { + @VisibleForTesting + List getEnableUserRoleListByUserIdFromCache(Long userId) { // 获得用户拥有的角色编号 Set roleIds = getSelf().getUserRoleIdListByUserIdFromCache(userId); // 获得角色数组,并移除被禁用的 @@ -196,53 +259,13 @@ public class PermissionServiceImpl implements PermissionService { return roles; } - @Override - // @Transactional(rollbackFor = Exception.class) // TODO 芋艿:不能使用 MySQL 事务 - public void assignUserRole(Long userId, Set roleIds) { - // 获得角色拥有角色编号 - Set dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId), - UserRoleDO::getRoleId); - // 计算新增和删除的角色编号 - Collection createRoleIds = CollUtil.subtract(roleIds, dbRoleIds); - Collection deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIds); - // 执行新增和删除。对于已经授权的角色,不用做任何处理 - if (!CollectionUtil.isEmpty(createRoleIds)) { - userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleIds, roleId -> { - UserRoleDO entity = new UserRoleDO(); - entity.setUserId(userId); - entity.setRoleId(roleId); - return entity; - })); - } - if (!CollectionUtil.isEmpty(deleteMenuIds)) { - userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); - } - } + // ========== 用户-部门的相关方法 ========== @Override public void assignRoleDataScope(Long roleId, Integer dataScope, Set dataScopeDeptIds) { roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds); } - @Override - @Transactional(rollbackFor = Exception.class) - public void processRoleDeleted(Long roleId) { - // 标记删除 UserRole - userRoleMapper.deleteListByRoleId(roleId); - // 标记删除 RoleMenu - roleMenuMapper.deleteListByRoleId(roleId); - } - - @Override - public void processMenuDeleted(Long menuId) { - roleMenuMapper.deleteListByMenuId(menuId); - } - - @Override - public void processUserDeleted(Long userId) { - userRoleMapper.deleteListByUserId(userId); - } - @Override @DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题 public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java index 30c624219b..4c0669403e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java @@ -189,6 +189,9 @@ public class RoleServiceImpl implements RoleService { @Override public List getRoleList(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return Collections.emptyList(); + } return roleMapper.selectBatchIds(ids); } diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java index f3160c000f..442abd7415 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.system.service.permission; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; @@ -25,7 +24,6 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Set; import static cn.hutool.core.collection.ListUtil.toList; @@ -126,56 +124,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { } } - @Test - public void testGetUserRoleIdsFromCache() { - // 准备参数 - Long userId = 1L; - Collection roleStatuses = singleton(CommonStatusEnum.ENABLE.getStatus()); - // mock 方法 TODO - Map> userRoleCache = MapUtil.>builder() - .put(1L, asSet(10L, 20L)).build(); -// permissionService.setUserRoleCache(userRoleCache); - RoleDO roleDO01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(roleService.getRoleFromCache(eq(10L))).thenReturn(roleDO01); - RoleDO roleDO02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); - when(roleService.getRoleFromCache(eq(20L))).thenReturn(roleDO02); - - // 调用 todo -// Set roleIds = permissionService.getUserRoleIdsFromCache(userId, roleStatuses); - // 断言 todo -// assertEquals(asSet(10L), roleIds); - } - - @Test - public void testGetRoleMenuIds_superAdmin() { - // 准备参数 - Long roleId = 100L; - // mock 方法 - when(roleService.hasAnySuperAdmin(eq(singleton(100L)))).thenReturn(true); - List menuList = singletonList(randomPojo(MenuDO.class).setId(1L)); - when(menuService.getMenuList()).thenReturn(menuList); - - // 调用 - Set menuIds = permissionService.getRoleMenuListByRoleId(roleId); - // 断言 - assertEquals(singleton(1L), menuIds); - } - - @Test - public void testGetRoleMenuIds_normal() { - // 准备参数 - Long roleId = 100L; - // mock 数据 - RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); - roleMenuMapper.insert(roleMenu01); - RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(2L); - roleMenuMapper.insert(roleMenu02); - - // 调用 - Set menuIds = permissionService.getRoleMenuListByRoleId(roleId); - // 断言 - assertEquals(asSet(1L, 2L), menuIds); - } + // ========== 角色-菜单的相关方法 ========== @Test public void testAssignRoleMenu() { @@ -199,73 +148,6 @@ public class PermissionServiceTest extends BaseDbUnitTest { assertEquals(300L, roleMenuList.get(1).getMenuId()); } - @Test - public void testAssignUserRole() { - // 准备参数 - Long userId = 1L; - Set roleIds = asSet(200L, 300L); - // mock 数据 - UserRoleDO userRole01 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(100L); - userRoleMapper.insert(userRole01); - UserRoleDO userRole02 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(200L); - userRoleMapper.insert(userRole02); - - // 调用 - permissionService.assignUserRole(userId, roleIds); - // 断言 - List userRoleDOList = userRoleMapper.selectList(); - assertEquals(2, userRoleDOList.size()); - assertEquals(1L, userRoleDOList.get(0).getUserId()); - assertEquals(200L, userRoleDOList.get(0).getRoleId()); - assertEquals(1L, userRoleDOList.get(1).getUserId()); - assertEquals(300L, userRoleDOList.get(1).getRoleId()); - } - - @Test - public void testGetUserRoleIdListByUserId() { - // 准备参数 - Long userId = 1L; - // mock 数据 - UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); - userRoleMapper.insert(userRoleDO01); - UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); - userRoleMapper.insert(roleMenuDO02); - - // 调用 - Set result = permissionService.getUserRoleIdListByUserId(userId); - // 断言 - assertEquals(asSet(10L, 20L), result); - } - - @Test - public void testGetUserRoleIdListByRoleIds() { - // 准备参数 - Collection roleIds = asSet(10L, 20L); - // mock 数据 - UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); - userRoleMapper.insert(userRoleDO01); - UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(2L).setRoleId(20L)); - userRoleMapper.insert(roleMenuDO02); - - // 调用 - Set result = permissionService.getUserRoleIdListByRoleId(roleIds); - // 断言 - assertEquals(asSet(1L, 2L), result); - } - - @Test - public void testAssignRoleDataScope() { - // 准备参数 - Long roleId = 1L; - Integer dataScope = 2; - Set dataScopeDeptIds = asSet(10L, 20L); - - // 调用 - permissionService.assignRoleDataScope(roleId, dataScope, dataScopeDeptIds); - // 断言 - verify(roleService).updateRoleDataScope(eq(roleId), eq(dataScope), eq(dataScopeDeptIds)); - } - @Test public void testProcessRoleDeleted() { // 准备参数 @@ -311,6 +193,77 @@ public class PermissionServiceTest extends BaseDbUnitTest { assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); } + @Test + public void testGetRoleMenuIds_superAdmin() { + // 准备参数 + Long roleId = 100L; + // mock 方法 + when(roleService.hasAnySuperAdmin(eq(singleton(100L)))).thenReturn(true); + List menuList = singletonList(randomPojo(MenuDO.class).setId(1L)); + when(menuService.getMenuList()).thenReturn(menuList); + + // 调用 + Set menuIds = permissionService.getRoleMenuListByRoleId(roleId); + // 断言 + assertEquals(singleton(1L), menuIds); + } + + @Test + public void testGetRoleMenuIds_normal() { + // 准备参数 + Long roleId = 100L; + // mock 数据 + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); + roleMenuMapper.insert(roleMenu01); + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(2L); + roleMenuMapper.insert(roleMenu02); + + // 调用 + Set menuIds = permissionService.getRoleMenuListByRoleId(roleId); + // 断言 + assertEquals(asSet(1L, 2L), menuIds); + } + + @Test + public void testGetMenuRoleIdListByMenuIdFromCache() { + // 准备参数 + Long menuId = 1L; + // mock 数据 + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); + roleMenuMapper.insert(roleMenu01); + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(200L).setMenuId(1L); + roleMenuMapper.insert(roleMenu02); + + // 调用 + Set roleIds = permissionService.getMenuRoleIdListByMenuIdFromCache(menuId); + // 断言 + assertEquals(asSet(100L, 200L), roleIds); + } + + // ========== 用户-角色的相关方法 ========== + + @Test + public void testAssignUserRole() { + // 准备参数 + Long userId = 1L; + Set roleIds = asSet(200L, 300L); + // mock 数据 + UserRoleDO userRole01 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(100L); + userRoleMapper.insert(userRole01); + UserRoleDO userRole02 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(200L); + userRoleMapper.insert(userRole02); + + // 调用 + permissionService.assignUserRole(userId, roleIds); + // 断言 + List userRoleDOList = userRoleMapper.selectList(); + assertEquals(2, userRoleDOList.size()); + assertEquals(1L, userRoleDOList.get(0).getUserId()); + assertEquals(200L, userRoleDOList.get(0).getRoleId()); + assertEquals(1L, userRoleDOList.get(1).getUserId()); + assertEquals(300L, userRoleDOList.get(1).getRoleId()); + } + @Test public void testProcessUserDeleted() { // 准备参数 @@ -330,118 +283,245 @@ public class PermissionServiceTest extends BaseDbUnitTest { } @Test - public void testGetDeptDataPermission_All() { + public void testGetUserRoleIdListByUserId() { // 准备参数 Long userId = 1L; - // mock 用户的角色编号 TODO -// permissionService.setUserRoleCache(MapUtil.>builder().put(1L, asSet(2L)).build()); - // mock 获得用户的角色 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + Set result = permissionService.getUserRoleIdListByUserId(userId); // 断言 - assertTrue(result.getAll()); - assertFalse(result.getSelf()); - assertTrue(CollUtil.isEmpty(result.getDeptIds())); + assertEquals(asSet(10L, 20L), result); + } + + @Test + public void testGetUserRoleIdListByUserIdFromCache() { + // 准备参数 + Long userId = 1L; + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByUserIdFromCache(userId); + // 断言 + assertEquals(asSet(10L, 20L), result); + } + + @Test + public void testGetUserRoleIdsFromCache() { + // 准备参数 + Long userId = 1L; + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByUserIdFromCache(userId); + // 断言 + assertEquals(asSet(10L, 20L), result); + } + + @Test + public void testGetUserRoleIdListByRoleId() { + // 准备参数 + Collection roleIds = asSet(10L, 20L); + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(2L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByRoleId(roleIds); + // 断言 + assertEquals(asSet(1L, 2L), result); + } + + @Test + public void testGetEnableUserRoleListByUserIdFromCache() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户登录的角色 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(200L)); + RoleDO role01 = randomPojo(RoleDO.class, o -> o.setId(100L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + RoleDO role02 = randomPojo(RoleDO.class, o -> o.setId(200L) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(asSet(100L, 200L)))) + .thenReturn(toList(role01, role02)); + + // 调用 + List result = permissionService.getEnableUserRoleListByUserIdFromCache(userId); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(role01, result.get(0)); + } + } + + // ========== 用户-部门的相关方法 ========== + + @Test + public void testAssignRoleDataScope() { + // 准备参数 + Long roleId = 1L; + Integer dataScope = 2; + Set dataScopeDeptIds = asSet(10L, 20L); + + // 调用 + permissionService.assignRoleDataScope(roleId, dataScope, dataScopeDeptIds); + // 断言 + verify(roleService).updateRoleDataScope(eq(roleId), eq(dataScope), eq(dataScopeDeptIds)); + } + + @Test + public void testGetDeptDataPermission_All() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertTrue(result.getAll()); + assertFalse(result.getSelf()); + assertTrue(CollUtil.isEmpty(result.getDeptIds())); + } } @Test public void testGetDeptDataPermission_DeptCustom() { - // 准备参数 - Long userId = 1L; - // mock 用户的角色编号 TODO -// permissionService.setUserRoleCache(MapUtil.>builder().put(1L, asSet(2L)).build()); - // mock 获得用户的角色 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); - // mock 部门的返回 - when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); - // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); - // 断言 - assertFalse(result.getAll()); - assertFalse(result.getSelf()); - assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size()); - assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds())); - assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), + null, null); // 最后返回 null 的目的,看看会不会重复调用 + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertFalse(result.getSelf()); + assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size()); + assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds())); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + } } @Test public void testGetDeptDataPermission_DeptOnly() { - // 准备参数 - Long userId = 1L; - // mock 用户的角色编号 TODO -// permissionService.setUserRoleCache(MapUtil.>builder().put(1L, asSet(2L)).build()); - // mock 获得用户的角色 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); - // mock 部门的返回 - when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); - // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); - // 断言 - assertFalse(result.getAll()); - assertFalse(result.getSelf()); - assertEquals(1, result.getDeptIds().size()); - assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), + null, null); // 最后返回 null 的目的,看看会不会重复调用 + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertFalse(result.getSelf()); + assertEquals(1, result.getDeptIds().size()); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + } } @Test public void testGetDeptDataPermission_DeptAndChild() { - // 准备参数 - Long userId = 1L; - // mock 用户的角色编号 TODO -// permissionService.setUserRoleCache(MapUtil.>builder().put(1L, asSet(2L)).build()); - // mock 获得用户的角色 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); - // mock 部门的返回 - when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 - // mock 方法(部门)TODO - DeptDO deptDO = randomPojo(DeptDO.class); - when(deptService.getChildDeptIdListFromCache(eq(3L))) - .thenReturn(singleton(deptDO.getId())); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); - // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); - // 断言 - assertFalse(result.getAll()); - assertFalse(result.getSelf()); - assertEquals(2, result.getDeptIds().size()); - assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId())); - assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), + null, null); // 最后返回 null 的目的,看看会不会重复调用 + // mock 方法(部门) + DeptDO deptDO = randomPojo(DeptDO.class); + when(deptService.getChildDeptIdListFromCache(eq(3L))).thenReturn(singleton(deptDO.getId())); + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertFalse(result.getSelf()); + assertEquals(2, result.getDeptIds().size()); + assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId())); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + } } @Test public void testGetDeptDataPermission_Self() { - // 准备参数 - Long userId = 1L; - // mock 用户的角色编号 TODO -// permissionService.setUserRoleCache(MapUtil.>builder().put(1L, asSet(2L)).build()); - // mock 获得用户的角色 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); - // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); - // 断言 - assertFalse(result.getAll()); - assertTrue(result.getSelf()); - assertTrue(CollUtil.isEmpty(result.getDeptIds())); + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertTrue(result.getSelf()); + assertTrue(CollUtil.isEmpty(result.getDeptIds())); + } } }