fix: ensure blocks are displayed under pages when setting role menu permissions

This commit is contained in:
aaaaaajie 2025-06-23 22:59:13 +08:00
parent a0181b58b1
commit 2aef273284
2 changed files with 121 additions and 3 deletions

View File

@ -167,6 +167,103 @@ describe('desktopRoutes:listAccessible', () => {
expect(response.body.data[0].title).toBe('page4');
expect(response.body.data[0].children.length).toBe(2);
});
it.only('should test role permissions and route visibility with group and tabs', async () => {
// 1. 定义一个表
await db.getCollection('collections').repository.create({
values: {
name: 'testTable',
title: 'Test Table',
fields: [
{
type: 'string',
name: 'name',
interface: 'input',
},
],
},
});
// 2. 定义一个角色
const customRole = await db.getRepository('roles').create({
values: { name: 'customRole', title: 'Custom Role' },
});
// 3. 给该角色设置主数据源 action 权限所有人可见
await db.getRepository('rolesResourcesActions').create({
values: {
roleName: customRole.name,
resourceName: 'testTable',
actionName: '*',
strategy: {
actions: ['create', 'view', 'update', 'destroy'],
},
},
});
// 4. 添加1个分组和2个子tab路由a,b
const groupRoute = await db.getRepository('desktopRoutes').create({
values: {
type: 'group',
title: 'testGroup',
},
});
const [routeA, routeB] = await db.getRepository('desktopRoutes').create({
values: [
{ type: 'tab', title: 'routeA', parentId: groupRoute.id },
{ type: 'tab', title: 'routeB', parentId: groupRoute.id },
],
});
// 使用 root 角色配置权限
const rootUser = await db.getRepository('users').create({
values: { roles: ['root'] },
});
const rootAgent = await app.agent().login(rootUser);
// 清除默认权限
await rootAgent.resource('roles.desktopRoutes', customRole.name).remove({
values: [1, 2, 3, 4, 5, 6, groupRoute.id, routeA.id, routeB.id],
});
// 5. 设置其中一个路由a可见
await rootAgent.resource('roles.desktopRoutes', customRole.name).add({
values: [groupRoute.id, routeA.id],
});
// 创建测试用户
const testUser = await db.getRepository('users').create({
values: { roles: [customRole.name] },
});
const testAgent = await app.agent().login(testUser);
// 验证只有routeA可见
let response = await testAgent.resource('desktopRoutes').listAccessible();
expect(response.status).toBe(200);
expect(response.body.data.length).toBe(1);
expect(response.body.data[0].title).toBe('testGroup');
expect(response.body.data[0].children.length).toBe(1);
expect(response.body.data[0].children[0].title).toBe('routeA');
// 6. 设置所有路由可见
await rootAgent.resource('roles.desktopRoutes', customRole.name).add({
values: [routeB.id],
});
// 7. 访问desktopRoutes:listAccessible API
response = await testAgent.resource('desktopRoutes').listAccessible();
// 8. 断言API结果a,b都有children
expect(response.status).toBe(200);
expect(response.body.data.length).toBe(1);
expect(response.body.data[0].title).toBe('testGroup');
expect(response.body.data[0].children.length).toBe(2);
const childTitles = response.body.data[0].children.map(child => child.title);
expect(childTitles).toContain('routeA');
expect(childTitles).toContain('routeB');
});
});
describe('desktopRoutes', async () => {

View File

@ -7,7 +7,7 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Model, Transaction } from '@nocobase/database';
import { Model, MultipleRelationRepository, Transaction } from '@nocobase/database';
import PluginLocalizationServer from '@nocobase/plugin-localization';
import { Plugin } from '@nocobase/server';
import { tval } from '@nocobase/utils';
@ -34,7 +34,7 @@ async function getLang(ctx) {
}
export class PluginClientServer extends Plugin {
async beforeLoad() {}
async beforeLoad() { }
async install() {
const uiSchemas = this.db.getRepository<any>('uiSchemas');
@ -216,7 +216,7 @@ export class PluginClientServer extends Plugin {
const tabIds = tabs.map((x) => x.get('id'));
const where = { desktopRouteId: tabIds, roleName };
if (action === 'create') {
const exists = await repository.find({ where });
const exists = await repository.find({ where, transaction });
const modelsByRouteId = _.keyBy(exists, (x) => x.get('desktopRouteId'));
const createModels = tabs
.map((x) => !modelsByRouteId[x.get('id')] && { desktopRouteId: x.get('id'), roleName })
@ -282,6 +282,27 @@ export class PluginClientServer extends Plugin {
await next();
});
this.app.resourceManager.registerActionHandler('roles.desktopRoutes:set', async (ctx, next) => {
let { values } = ctx.action.params;
if (values.length) {
const instances = await this.app.db.getRepository('desktopRoutes').find({
filter: {
$or: [
{ id: { $in: values } },
{ parentId: { $in: values } }
]
}
});
values = instances.map((instance) => instance.get('id'));
};
const { resourceName, sourceId } = ctx.action;
const repository = this.app.db.getRepository<MultipleRelationRepository>(resourceName, sourceId)
await repository['set'](values);
ctx.status = 200;
await next();
});
}
registerLocalizationSource() {