mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 21:49:25 +08:00
fix(migration): permissions issue (#6177)
* fix(migration): permissions issue * feat: add new migration
This commit is contained in:
parent
1c1b9a3fe6
commit
17541f94d1
@ -0,0 +1,111 @@
|
|||||||
|
import { MockServer, createMockServer } from '@nocobase/test';
|
||||||
|
import Migration, { getIds, schemaToRoutes } from '../migrations/2024122912211-transform-menu-schema-to-routes';
|
||||||
|
|
||||||
|
describe('transform-menu-schema-to-routes', () => {
|
||||||
|
let app: MockServer;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await createMockServer({
|
||||||
|
plugins: ['nocobase'],
|
||||||
|
});
|
||||||
|
await app.version.update('1.5.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('migration', () => {
|
||||||
|
test('should skip if desktop routes already exist', async () => {
|
||||||
|
const desktopRoutes = app.db.getRepository('desktopRoutes');
|
||||||
|
await desktopRoutes.create({
|
||||||
|
type: 'page',
|
||||||
|
title: 'Test Page',
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
const migration = new Migration({
|
||||||
|
db: app.db,
|
||||||
|
app: app,
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
await migration.up();
|
||||||
|
const count = await desktopRoutes.count();
|
||||||
|
expect(count).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('schemaToRoutes', () => {
|
||||||
|
test('should transform group menu item', async () => {
|
||||||
|
const schema = {
|
||||||
|
properties: {
|
||||||
|
group1: {
|
||||||
|
'x-component': 'Menu.SubMenu',
|
||||||
|
title: 'Group 1',
|
||||||
|
'x-uid': 'group-1',
|
||||||
|
'x-component-props': {
|
||||||
|
icon: 'GroupIcon',
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const routes = await schemaToRoutes(schema, app.db.getRepository('uiSchemas'));
|
||||||
|
expect(routes[0]).toMatchObject({
|
||||||
|
type: 'group',
|
||||||
|
title: 'Group 1',
|
||||||
|
icon: 'GroupIcon',
|
||||||
|
schemaUid: 'group-1',
|
||||||
|
hideInMenu: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should transform link menu item', async () => {
|
||||||
|
const schema = {
|
||||||
|
properties: {
|
||||||
|
link1: {
|
||||||
|
'x-component': 'Menu.URL',
|
||||||
|
title: 'Link 1',
|
||||||
|
'x-uid': 'link-1',
|
||||||
|
'x-component-props': {
|
||||||
|
icon: 'LinkIcon',
|
||||||
|
href: 'https://example.com',
|
||||||
|
params: { foo: 'bar' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const routes = await schemaToRoutes(schema, app.db.getRepository('uiSchemas'));
|
||||||
|
expect(routes[0]).toMatchObject({
|
||||||
|
type: 'link',
|
||||||
|
title: 'Link 1',
|
||||||
|
icon: 'LinkIcon',
|
||||||
|
options: {
|
||||||
|
href: 'https://example.com',
|
||||||
|
params: { foo: 'bar' },
|
||||||
|
},
|
||||||
|
schemaUid: 'link-1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getIds', () => {
|
||||||
|
test('should correctly identify ids to add and remove', () => {
|
||||||
|
const desktopRoutes = [
|
||||||
|
{ id: 1, type: 'page', menuSchemaUid: 'page-1' },
|
||||||
|
{ id: 2, type: 'page', menuSchemaUid: 'page-2' },
|
||||||
|
{ id: 3, type: 'tabs', parentId: 1 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const menuUiSchemas = [
|
||||||
|
{ 'x-uid': 'page-1' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { needRemoveIds, needAddIds } = getIds(desktopRoutes, menuUiSchemas);
|
||||||
|
expect(needRemoveIds).toContain(2);
|
||||||
|
expect(needAddIds).toContain(1);
|
||||||
|
expect(needAddIds).toContain(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -35,24 +35,30 @@ export default class extends Migration {
|
|||||||
// 2. 将旧版的权限配置,转换为新版的权限配置
|
// 2. 将旧版的权限配置,转换为新版的权限配置
|
||||||
|
|
||||||
const roles = await rolesRepository.find({
|
const roles = await rolesRepository.find({
|
||||||
appends: ['desktopRoutes', 'menuUiSchemas'],
|
appends: ['menuUiSchemas'],
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
const allDesktopRoutes = await desktopRoutes.find({ transaction });
|
||||||
|
|
||||||
for (const role of roles) {
|
for (const role of roles) {
|
||||||
const menuUiSchemas = role.menuUiSchemas || [];
|
const menuUiSchemas = role.menuUiSchemas || [];
|
||||||
const desktopRoutes = role.desktopRoutes || [];
|
const { needRemoveIds, needAddIds } = getIds(allDesktopRoutes, menuUiSchemas);
|
||||||
const needRemoveIds = getNeedRemoveIds(desktopRoutes, menuUiSchemas);
|
|
||||||
|
|
||||||
if (needRemoveIds.length === 0) {
|
if (needRemoveIds.length > 0) {
|
||||||
continue;
|
// @ts-ignore
|
||||||
|
await this.db.getRepository('roles.desktopRoutes', role.name).remove({
|
||||||
|
tk: needRemoveIds,
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
if (needAddIds.length > 0) {
|
||||||
await this.db.getRepository('roles.desktopRoutes', role.name).remove({
|
// @ts-ignore
|
||||||
tk: needRemoveIds,
|
await this.db.getRepository('roles.desktopRoutes', role.name).add({
|
||||||
transaction,
|
tk: needAddIds,
|
||||||
});
|
transaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,9 +176,9 @@ export async function schemaToRoutes(schema: any, uiSchemas: any) {
|
|||||||
return Promise.all(result);
|
return Promise.all(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNeedRemoveIds(desktopRoutes: any[], menuUiSchemas: any[]) {
|
export function getIds(desktopRoutes: any[], menuUiSchemas: any[]) {
|
||||||
const uidList = menuUiSchemas.map((item) => item['x-uid']);
|
const uidList = menuUiSchemas.map((item) => item['x-uid']);
|
||||||
return desktopRoutes
|
const needRemoveIds = desktopRoutes
|
||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
// 之前是不支持配置 tab 的权限的,所以所有的 tab 都不会存在于旧版的 menuUiSchemas 中
|
// 之前是不支持配置 tab 的权限的,所以所有的 tab 都不会存在于旧版的 menuUiSchemas 中
|
||||||
if (item.type === 'tabs') {
|
if (item.type === 'tabs') {
|
||||||
@ -189,4 +195,7 @@ function getNeedRemoveIds(desktopRoutes: any[], menuUiSchemas: any[]) {
|
|||||||
return !uidList.includes(item?.schemaUid);
|
return !uidList.includes(item?.schemaUid);
|
||||||
})
|
})
|
||||||
.map((item) => item?.id);
|
.map((item) => item?.id);
|
||||||
|
const needAddIds = desktopRoutes.map((item) => item?.id).filter((id) => !needRemoveIds.includes(id));
|
||||||
|
|
||||||
|
return { needRemoveIds, needAddIds };
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Migration } from '@nocobase/server';
|
||||||
|
|
||||||
|
export default class extends Migration {
|
||||||
|
appVersion = '<1.6.0';
|
||||||
|
async up() {
|
||||||
|
const desktopRoutes = this.db.getRepository('desktopRoutes');
|
||||||
|
const count = await desktopRoutes.count();
|
||||||
|
if (!count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rolesRepository = this.db.getRepository('roles');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.db.sequelize.transaction(async (transaction) => {
|
||||||
|
const roles = await rolesRepository.find({
|
||||||
|
appends: ['menuUiSchemas'],
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
const allDesktopRoutes = await desktopRoutes.find({ transaction });
|
||||||
|
|
||||||
|
for (const role of roles) {
|
||||||
|
const menuUiSchemas = role.menuUiSchemas || [];
|
||||||
|
const { needAddIds } = getIds(allDesktopRoutes, menuUiSchemas);
|
||||||
|
|
||||||
|
if (needAddIds.length > 0) {
|
||||||
|
// @ts-ignore
|
||||||
|
await this.db.getRepository('roles.desktopRoutes', role.name).add({
|
||||||
|
tk: needAddIds,
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Migration failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIds(desktopRoutes: any[], menuUiSchemas: any[]) {
|
||||||
|
const uidList = menuUiSchemas.map((item) => item['x-uid']);
|
||||||
|
const needRemoveIds = desktopRoutes
|
||||||
|
.filter((item) => {
|
||||||
|
// 之前是不支持配置 tab 的权限的,所以所有的 tab 都不会存在于旧版的 menuUiSchemas 中
|
||||||
|
if (item.type === 'tabs') {
|
||||||
|
// tab 的父节点就是一个 page
|
||||||
|
const page = desktopRoutes.find((route) => route?.id === item?.parentId);
|
||||||
|
// tab 要不要过滤掉,和它的父节点(page)有关
|
||||||
|
return !uidList.includes(page?.menuSchemaUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.type === 'page') {
|
||||||
|
return !uidList.includes(item?.menuSchemaUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !uidList.includes(item?.schemaUid);
|
||||||
|
})
|
||||||
|
.map((item) => item?.id);
|
||||||
|
const needAddIds = desktopRoutes.map((item) => item?.id).filter((id) => !needRemoveIds.includes(id));
|
||||||
|
|
||||||
|
return { needRemoveIds, needAddIds };
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user