align(用户菜单授权): 创建/编辑用户菜单权限补齐前端客户端(app)菜单并按类型分区落库
用户管理菜单权限此前只含后台 admin(单类型):前端授权树/回显仅拉 menuType=admin, 后端 replaceDirectPermissions 也固定用 ADMIN 作用域写。现改为同时覆盖 后台(admin)+前端客户端(app): - 前端 user-menu-auth 节点携带 type,api 并行拉取 admin/app 两类可授权树与已授权 id 合并去重,树内两类根并存(账号与权限/视频/前端工具/运营工具/后勤工具等) - 后端 PermissionMenuService 新增 resolveMenuTypes(按 id 解析类型);AdminUserService create/update 把勾选 id 拆 admin/app 分区整树替换(internal 不纳入) - 前端 1556 测试全绿 + build 通过;后端单测(AdminUserServiceTest/PermissionMenuServiceTest/Controller/PermissionMenuResolveTypeTest) EXIT 0 - 本地 E2E:创建用户写入 admin=7+app=3 → 按类型回读 admin[7]/app[3],删除正常
This commit is contained in:
+29
-2
@@ -230,11 +230,38 @@ public class AdminUserService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户管理授权树现在同时展示并勾选 后台(admin) + 前端客户端(app) 菜单:
|
||||
* 把勾选 id 按类型拆分后分区整树替换(internal 类型不在树里,出现即按无效处理)。
|
||||
*/
|
||||
private void replaceDirectPermissions(AdminUserEntity operator, Long userId, List<Long> columnIds) {
|
||||
List<Long> raw = columnIds == null ? List.of() : columnIds;
|
||||
Map<Long, String> typeById = permissionMenuService.resolveMenuTypes(raw);
|
||||
List<Long> adminIds = new ArrayList<>();
|
||||
List<Long> appIds = new ArrayList<>();
|
||||
for (Long id : raw) {
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
String type = typeById.getOrDefault(id, "");
|
||||
if (PermissionMenuService.MENU_TYPE_ADMIN.equals(type)) {
|
||||
adminIds.add(id);
|
||||
} else if (PermissionMenuService.MENU_TYPE_APP.equals(type)) {
|
||||
appIds.add(id);
|
||||
} else {
|
||||
throw new BusinessException("存在无效或不属于当前类型的菜单权限项");
|
||||
}
|
||||
}
|
||||
replaceDirectPermissionsByType(operator, userId, adminIds, PermissionMenuService.MENU_TYPE_ADMIN);
|
||||
replaceDirectPermissionsByType(operator, userId, appIds, PermissionMenuService.MENU_TYPE_APP);
|
||||
}
|
||||
|
||||
private void replaceDirectPermissionsByType(AdminUserEntity operator, Long userId, List<Long> columnIds,
|
||||
String menuType) {
|
||||
UserColumnPermissionUpdateRequest permissionRequest = new UserColumnPermissionUpdateRequest();
|
||||
permissionRequest.setColumnIds(columnIds == null ? List.of() : columnIds);
|
||||
permissionRequest.setColumnIds(columnIds);
|
||||
permissionMenuService.updateUserColumnPermissions(
|
||||
operator, userId, permissionRequest, PermissionMenuService.MENU_TYPE_APP);
|
||||
operator, userId, permissionRequest, menuType);
|
||||
}
|
||||
|
||||
public void deleteUser(AdminUserEntity currentUser, Long uid) {
|
||||
|
||||
+19
@@ -61,6 +61,25 @@ public class PermissionMenuService {
|
||||
return toItemVos(menus, menus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按菜单(column) id 解析所属类型;未知/无效 id 不在返回中。供用户创建/编辑把
|
||||
* 勾选的 后台(admin)+客户端(app) 菜单 id 拆分后分别落库。
|
||||
*/
|
||||
public Map<Long, String> resolveMenuTypes(List<Long> columnIds) {
|
||||
List<Long> ids = normalizeColumnIds(columnIds);
|
||||
if (ids.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
List<PermissionMenuEntity> rows = permissionMenuMapper.selectBatchIds(ids);
|
||||
Map<Long, String> typeById = new HashMap<>();
|
||||
for (PermissionMenuEntity row : rows) {
|
||||
if (row != null && row.getId() != null) {
|
||||
typeById.put(row.getId(), row.getMenuType() == null ? "" : row.getMenuType());
|
||||
}
|
||||
}
|
||||
return typeById;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public PermissionMenuItemVo create(PermissionMenuCreateRequest request) {
|
||||
return create(null, request);
|
||||
|
||||
+21
-6
@@ -13,6 +13,7 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -41,6 +42,8 @@ class AdminUserServiceTest {
|
||||
|
||||
when(authSupport.currentRole(operator)).thenReturn("admin");
|
||||
when(permissionService.hasAnyAdminMenu(eq(operator), any())).thenReturn(true);
|
||||
when(permissionService.resolveMenuTypes(List.of(11L, 12L)))
|
||||
.thenReturn(Map.of(11L, PermissionMenuService.MENU_TYPE_ADMIN, 12L, PermissionMenuService.MENU_TYPE_APP));
|
||||
when(passwordEncoder.hash("secret1")).thenReturn("hashed");
|
||||
when(userMapper.insert(any(AdminUserEntity.class))).thenAnswer(invocation -> {
|
||||
invocation.<AdminUserEntity>getArgument(0).setId(20L);
|
||||
@@ -50,11 +53,16 @@ class AdminUserServiceTest {
|
||||
Long createdId = service.createUser(operator, request);
|
||||
|
||||
assertThat(createdId).isEqualTo(20L);
|
||||
ArgumentCaptor<UserColumnPermissionUpdateRequest> permissions =
|
||||
ArgumentCaptor<UserColumnPermissionUpdateRequest> adminReq =
|
||||
ArgumentCaptor.forClass(UserColumnPermissionUpdateRequest.class);
|
||||
ArgumentCaptor<UserColumnPermissionUpdateRequest> appReq =
|
||||
ArgumentCaptor.forClass(UserColumnPermissionUpdateRequest.class);
|
||||
verify(permissionService).updateUserColumnPermissions(
|
||||
eq(operator), eq(20L), permissions.capture(), eq(PermissionMenuService.MENU_TYPE_APP));
|
||||
assertThat(permissions.getValue().getColumnIds()).containsExactly(11L, 12L);
|
||||
eq(operator), eq(20L), adminReq.capture(), eq(PermissionMenuService.MENU_TYPE_ADMIN));
|
||||
verify(permissionService).updateUserColumnPermissions(
|
||||
eq(operator), eq(20L), appReq.capture(), eq(PermissionMenuService.MENU_TYPE_APP));
|
||||
assertThat(adminReq.getValue().getColumnIds()).containsExactly(11L);
|
||||
assertThat(appReq.getValue().getColumnIds()).containsExactly(12L);
|
||||
assertThat(AdminUserService.class
|
||||
.getMethod("createUser", AdminUserEntity.class, AdminUserCreateRequest.class)
|
||||
.isAnnotationPresent(Transactional.class)).isTrue();
|
||||
@@ -75,16 +83,23 @@ class AdminUserServiceTest {
|
||||
|
||||
when(authSupport.currentRole(operator)).thenReturn("admin");
|
||||
when(permissionService.hasAnyAdminMenu(eq(operator), any())).thenReturn(true);
|
||||
when(permissionService.resolveMenuTypes(List.of(21L)))
|
||||
.thenReturn(Map.of(21L, PermissionMenuService.MENU_TYPE_APP));
|
||||
when(userMapper.selectById(20L)).thenReturn(target);
|
||||
|
||||
service.updateUser(operator, 20L, request);
|
||||
|
||||
verify(userMapper, never()).update(any(), any());
|
||||
ArgumentCaptor<UserColumnPermissionUpdateRequest> permissions =
|
||||
ArgumentCaptor<UserColumnPermissionUpdateRequest> adminReq =
|
||||
ArgumentCaptor.forClass(UserColumnPermissionUpdateRequest.class);
|
||||
ArgumentCaptor<UserColumnPermissionUpdateRequest> appReq =
|
||||
ArgumentCaptor.forClass(UserColumnPermissionUpdateRequest.class);
|
||||
verify(permissionService).updateUserColumnPermissions(
|
||||
eq(operator), eq(20L), permissions.capture(), eq(PermissionMenuService.MENU_TYPE_APP));
|
||||
assertThat(permissions.getValue().getColumnIds()).containsExactly(21L);
|
||||
eq(operator), eq(20L), adminReq.capture(), eq(PermissionMenuService.MENU_TYPE_ADMIN));
|
||||
verify(permissionService).updateUserColumnPermissions(
|
||||
eq(operator), eq(20L), appReq.capture(), eq(PermissionMenuService.MENU_TYPE_APP));
|
||||
assertThat(adminReq.getValue().getColumnIds()).isEmpty();
|
||||
assertThat(appReq.getValue().getColumnIds()).containsExactly(21L);
|
||||
assertThat(AdminUserService.class
|
||||
.getMethod("updateUser", AdminUserEntity.class, Long.class, AdminUserUpdateRequest.class)
|
||||
.isAnnotationPresent(Transactional.class)).isTrue();
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.nanri.aiimage.modules.permission.service;
|
||||
|
||||
import com.nanri.aiimage.modules.permission.mapper.AdminUserMapper;
|
||||
import com.nanri.aiimage.modules.permission.mapper.PermissionMenuMapper;
|
||||
import com.nanri.aiimage.modules.permission.mapper.UserColumnPermissionMapper;
|
||||
import com.nanri.aiimage.modules.permission.model.entity.PermissionMenuEntity;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class PermissionMenuResolveTypeTest {
|
||||
|
||||
@Test
|
||||
void resolveMenuTypesGroupsAdminAndAppByIdAndDropsUnknown() {
|
||||
PermissionMenuMapper menuMapper = mock(PermissionMenuMapper.class);
|
||||
PermissionMenuService service = new PermissionMenuService(
|
||||
menuMapper,
|
||||
mock(UserColumnPermissionMapper.class),
|
||||
mock(AdminUserMapper.class));
|
||||
when(menuMapper.selectBatchIds(any())).thenReturn(List.of(
|
||||
menu(1L, PermissionMenuService.MENU_TYPE_ADMIN),
|
||||
menu(2L, PermissionMenuService.MENU_TYPE_APP)));
|
||||
|
||||
Map<Long, String> typeById = service.resolveMenuTypes(List.of(1L, 2L, 3L));
|
||||
|
||||
assertThat(typeById)
|
||||
.containsEntry(1L, PermissionMenuService.MENU_TYPE_ADMIN)
|
||||
.containsEntry(2L, PermissionMenuService.MENU_TYPE_APP)
|
||||
.doesNotContainKey(3L);
|
||||
}
|
||||
|
||||
private PermissionMenuEntity menu(Long id, String type) {
|
||||
PermissionMenuEntity entity = new PermissionMenuEntity();
|
||||
entity.setId(id);
|
||||
entity.setMenuType(type);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user