fix: postgres sort with appends issue (#198)
* fix: postgres sort with appends issue * fix: role menus api error * feat: add exists params in roles.collections api * refactor: remove uid field on uiSchemas table * test: toggle role menus * fix: plugin-acl test * feat: sync data to acl before app start * fix: mysql ui-schema sql compatibility * feat: writeRolesToACL in plugin-acl
This commit is contained in:
parent
7be30b5b95
commit
000587380b
@ -8,7 +8,7 @@ import {
|
||||
} from './multiple-relation-repository';
|
||||
import { CreateOptions, DestroyOptions, FindOptions, TK, TargetKey, UpdateOptions } from '../repository';
|
||||
import { transaction } from './relation-repository';
|
||||
import lodash from 'lodash';
|
||||
import lodash, { omit } from 'lodash';
|
||||
|
||||
interface IHasManyRepository<M extends Model> {
|
||||
find(options?: FindOptions): Promise<M>;
|
||||
@ -29,6 +29,25 @@ interface IHasManyRepository<M extends Model> {
|
||||
}
|
||||
|
||||
export class HasManyRepository extends MultipleRelationRepository implements IHasManyRepository<any> {
|
||||
async find(options?: FindOptions): Promise<any> {
|
||||
const targetRepository = this.targetCollection.repository;
|
||||
|
||||
const addFilter = {
|
||||
[this.association.foreignKey]: this.sourceKeyValue,
|
||||
};
|
||||
|
||||
if (options?.filterByTk) {
|
||||
addFilter[this.associationField.targetKey] = options.filterByTk;
|
||||
}
|
||||
|
||||
return await targetRepository.find({
|
||||
...omit(options, ['filterByTk']),
|
||||
filter: {
|
||||
$and: [options.filter || {}, addFilter],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@transaction((args, transaction) => {
|
||||
return {
|
||||
filterByTk: args[0],
|
||||
|
@ -44,7 +44,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
|
||||
if (findOptions.include && findOptions.include.length > 0) {
|
||||
const ids = (
|
||||
await sourceModel[getAccessor]({
|
||||
...findOptions,
|
||||
...omit(findOptions, 'order'),
|
||||
includeIgnoreAttributes: false,
|
||||
attributes: [this.targetKey()],
|
||||
group: `${this.targetModel.name}.${this.targetKey()}`,
|
||||
|
@ -207,6 +207,7 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
|
||||
async find(options?: FindOptions) {
|
||||
const model = this.collection.model;
|
||||
const transaction = await this.getTransaction(options);
|
||||
|
||||
const opts = {
|
||||
subQuery: false,
|
||||
...this.buildQueryOptions(options),
|
||||
@ -215,6 +216,7 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
|
||||
if (opts.include && opts.include.length > 0) {
|
||||
// @ts-ignore
|
||||
const primaryKeyField = model.primaryKeyField || model.primaryKeyAttribute;
|
||||
|
||||
const ids = (
|
||||
await model.findAll({
|
||||
...opts,
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import { Database } from '@nocobase/database';
|
||||
import { MockServer } from '@nocobase/test';
|
||||
import { prepareApp } from './prepare';
|
||||
import { changeMockRole, prepareApp } from './prepare';
|
||||
import { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
|
||||
|
||||
describe('acl', () => {
|
||||
let app: MockServer;
|
||||
let db: Database;
|
||||
let acl: ACL;
|
||||
|
||||
let uiSchemaRepository: UiSchemaRepository;
|
||||
|
||||
afterEach(async () => {
|
||||
await app.destroy();
|
||||
});
|
||||
@ -16,6 +19,8 @@ describe('acl', () => {
|
||||
app = await prepareApp();
|
||||
db = app.db;
|
||||
acl = app.acl;
|
||||
|
||||
uiSchemaRepository = db.getRepository('uiSchemas');
|
||||
});
|
||||
|
||||
it('should works with universal actions', async () => {
|
||||
@ -68,20 +73,20 @@ describe('acl', () => {
|
||||
});
|
||||
|
||||
it('should works with resources actions', async () => {
|
||||
await db.getRepository('roles').create({
|
||||
const role = await db.getRepository('roles').create({
|
||||
values: {
|
||||
name: 'admin',
|
||||
title: 'Admin User',
|
||||
allowConfigure: true,
|
||||
strategy: {
|
||||
actions: ['list'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const role = await db.getRepository('roles').findOne({
|
||||
filter: {
|
||||
name: 'admin',
|
||||
},
|
||||
});
|
||||
changeMockRole('admin');
|
||||
|
||||
// create c1 collection
|
||||
await db.getRepository('collections').create({
|
||||
values: {
|
||||
name: 'c1',
|
||||
@ -89,6 +94,7 @@ describe('acl', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// create c2 collection
|
||||
await db.getRepository('collections').create({
|
||||
values: {
|
||||
name: 'c2',
|
||||
@ -96,6 +102,7 @@ describe('acl', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// create c1 published scope
|
||||
await app
|
||||
.agent()
|
||||
.resource('rolesResourcesScopes')
|
||||
@ -111,11 +118,11 @@ describe('acl', () => {
|
||||
|
||||
const publishedScope = await db.getRepository('rolesResourcesScopes').findOne();
|
||||
|
||||
// set admin resources
|
||||
await app
|
||||
.agent()
|
||||
.resource('roles.resources')
|
||||
.resource('roles.resources', 'admin')
|
||||
.create({
|
||||
associatedIndex: role.get('name') as string,
|
||||
values: {
|
||||
name: 'c1',
|
||||
usingActionsConfig: true,
|
||||
@ -170,11 +177,11 @@ describe('acl', () => {
|
||||
appends: ['actions'],
|
||||
});
|
||||
|
||||
expect(response.statusCode).toEqual(200);
|
||||
|
||||
const actions = response.body.data[0].actions;
|
||||
const collectionName = response.body.data[0].name;
|
||||
|
||||
const viewActionId = actions.find((action) => action.name === 'view').id;
|
||||
|
||||
await app
|
||||
.agent()
|
||||
.resource('roles.resources', role.get('name'))
|
||||
@ -185,7 +192,6 @@ describe('acl', () => {
|
||||
usingActionsConfig: true,
|
||||
actions: [
|
||||
{
|
||||
id: viewActionId,
|
||||
name: 'view',
|
||||
fields: ['title', 'age'],
|
||||
},
|
||||
@ -434,4 +440,94 @@ describe('acl', () => {
|
||||
|
||||
expect(newAllowFields.includes('description')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should get role menus', async () => {
|
||||
const role = await db.getRepository('roles').create({
|
||||
values: {
|
||||
name: 'admin',
|
||||
title: 'Admin User',
|
||||
allowConfigure: true,
|
||||
strategy: {
|
||||
actions: ['view'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
changeMockRole('admin');
|
||||
|
||||
const menuResponse = await app.agent().resource('roles.menuUiSchemas', 'admin').list();
|
||||
|
||||
expect(menuResponse.statusCode).toEqual(200);
|
||||
});
|
||||
|
||||
it('should toggle role menus', async () => {
|
||||
const role = await db.getRepository('roles').create({
|
||||
values: {
|
||||
name: 'admin',
|
||||
title: 'Admin User',
|
||||
allowConfigure: true,
|
||||
strategy: {
|
||||
actions: ['*'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
changeMockRole('admin');
|
||||
|
||||
const schema = {
|
||||
'x-uid': 'test',
|
||||
};
|
||||
|
||||
await uiSchemaRepository.insert(schema);
|
||||
|
||||
const response = await app
|
||||
.agent()
|
||||
.resource('roles.menuUiSchemas', 'admin')
|
||||
.toggle({
|
||||
values: { tk: 'test' },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toEqual(200);
|
||||
});
|
||||
|
||||
it('should sync data to acl before app start', async () => {
|
||||
const role = await db.getRepository('roles').create({
|
||||
values: {
|
||||
name: 'admin',
|
||||
title: 'Admin User',
|
||||
allowConfigure: true,
|
||||
resources: [
|
||||
{
|
||||
name: 'posts',
|
||||
usingActionsConfig: true,
|
||||
actions: [
|
||||
{
|
||||
name: 'view',
|
||||
fields: ['title'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
hooks: false,
|
||||
});
|
||||
|
||||
expect(acl.getRole('admin')).toBeUndefined();
|
||||
|
||||
await app.start();
|
||||
|
||||
expect(acl.getRole('admin')).toBeDefined();
|
||||
|
||||
expect(
|
||||
acl.can({
|
||||
role: 'admin',
|
||||
resource: 'posts',
|
||||
action: 'view',
|
||||
}),
|
||||
).toMatchObject({
|
||||
role: 'admin',
|
||||
resource: 'posts',
|
||||
action: 'view',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -52,9 +52,8 @@ describe('role resource api', () => {
|
||||
// get collections list
|
||||
let response = await app
|
||||
.agent()
|
||||
.resource('roles.collections')
|
||||
.resource('roles.collections', 'admin')
|
||||
.list({
|
||||
associatedIndex: role.get('name') as string,
|
||||
sort: ['sort'],
|
||||
});
|
||||
|
||||
@ -65,20 +64,21 @@ describe('role resource api', () => {
|
||||
name: 'c1',
|
||||
title: 'table1',
|
||||
usingConfig: 'strategy',
|
||||
exists: false,
|
||||
},
|
||||
{
|
||||
name: 'c2',
|
||||
title: 'table2',
|
||||
usingConfig: 'strategy',
|
||||
exists: false,
|
||||
},
|
||||
]);
|
||||
|
||||
// set resource actions
|
||||
response = await app
|
||||
.agent()
|
||||
.resource('roles.resources')
|
||||
.resource('roles.resources', 'admin')
|
||||
.create({
|
||||
associatedIndex: role.get('name') as string,
|
||||
values: {
|
||||
name: 'c1',
|
||||
usingActionsConfig: true,
|
||||
|
@ -10,20 +10,28 @@ const roleCollectionsResource = {
|
||||
|
||||
const db: Database = ctx.db;
|
||||
const collectionRepository = db.getRepository('collections');
|
||||
|
||||
// all collections
|
||||
const collections = await collectionRepository.find();
|
||||
|
||||
// role collections
|
||||
const roleResources = await db.getRepository('rolesResources').find({
|
||||
filter: {
|
||||
roleName: role,
|
||||
usingActionsConfig: true,
|
||||
},
|
||||
});
|
||||
|
||||
// role collections
|
||||
const roleResourcesNames = roleResources.map((roleResource) => roleResource.get('name'));
|
||||
const roleResourceActionResourceNames = roleResources
|
||||
.filter((roleResources) => roleResources.get('usingActionsConfig'))
|
||||
.map((roleResources) => roleResources.get('name'));
|
||||
|
||||
ctx.body = collections
|
||||
.map((collection) => {
|
||||
const usingConfig: UsingConfigType = roleResourcesNames.includes(collection.get('name'))
|
||||
const exists = roleResourcesNames.includes(collection.get('name'));
|
||||
|
||||
const usingConfig: UsingConfigType = roleResourceActionResourceNames.includes(collection.get('name'))
|
||||
? 'resourceAction'
|
||||
: 'strategy';
|
||||
|
||||
@ -32,6 +40,7 @@ const roleCollectionsResource = {
|
||||
title: collection.get('title') as string,
|
||||
roleName: role,
|
||||
usingConfig,
|
||||
exists,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||
|
@ -3,6 +3,7 @@ import { CollectionOptions } from '@nocobase/database';
|
||||
export default {
|
||||
name: 'roles',
|
||||
autoGenId: false,
|
||||
model: 'RoleModel',
|
||||
fields: [
|
||||
{
|
||||
type: 'uid',
|
||||
@ -44,7 +45,6 @@ export default {
|
||||
type: 'belongsToMany',
|
||||
name: 'menuUiSchemas',
|
||||
target: 'uiSchemas',
|
||||
targetKey: 'uid',
|
||||
},
|
||||
{
|
||||
type: 'hasMany',
|
||||
|
21
packages/plugin-acl/src/model/RoleModel.ts
Normal file
21
packages/plugin-acl/src/model/RoleModel.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Model } from '@nocobase/database';
|
||||
import { ACL } from '@nocobase/acl';
|
||||
|
||||
export class RoleModel extends Model {
|
||||
writeToAcl(options: { acl: ACL }) {
|
||||
const { acl } = options;
|
||||
const roleName = this.get('name') as string;
|
||||
let role = acl.getRole(roleName);
|
||||
|
||||
if (!role) {
|
||||
role = acl.define({
|
||||
role: roleName,
|
||||
});
|
||||
}
|
||||
|
||||
role.setStrategy({
|
||||
...((this.get('strategy') as object) || {}),
|
||||
allowConfigure: this.get('allowConfigure') as boolean,
|
||||
});
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import { availableActionResource } from './actions/available-actions';
|
||||
import { roleCollectionsResource } from './actions/role-collections';
|
||||
import { RoleResourceActionModel } from './model/RoleResourceActionModel';
|
||||
import { RoleResourceModel } from './model/RoleResourceModel';
|
||||
import { RoleModel } from './model/RoleModel';
|
||||
|
||||
export interface AssociationFieldAction {
|
||||
associationActions: string[];
|
||||
@ -26,7 +27,6 @@ export class GrantHelper {
|
||||
}
|
||||
|
||||
export class PluginACL extends Plugin {
|
||||
|
||||
associationFieldsActions: AssociationFieldsActions = {};
|
||||
|
||||
grantHelper = new GrantHelper();
|
||||
@ -100,11 +100,23 @@ export class PluginACL extends Plugin {
|
||||
});
|
||||
}
|
||||
|
||||
async beforeLoad() {
|
||||
async writeRolesToACL() {
|
||||
const roles = (await this.app.db.getRepository('roles').find({
|
||||
appends: ['resources', 'resources.actions'],
|
||||
})) as RoleModel[];
|
||||
for (const role of roles) {
|
||||
role.writeToAcl({ acl: this.acl });
|
||||
for (const resource of role.get('resources') as RoleResourceModel[]) {
|
||||
await this.writeResourceToACL(resource, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async beforeLoad() {
|
||||
this.app.db.registerModels({
|
||||
RoleResourceActionModel,
|
||||
RoleResourceModel,
|
||||
RoleModel,
|
||||
});
|
||||
|
||||
this.registerAssociationFieldsActions();
|
||||
@ -114,18 +126,9 @@ export class PluginACL extends Plugin {
|
||||
|
||||
this.app.db.on('roles.afterSave', async (model, options) => {
|
||||
const { transaction } = options;
|
||||
const roleName = model.get('name');
|
||||
let role = this.acl.getRole(roleName);
|
||||
|
||||
if (!role) {
|
||||
role = this.acl.define({
|
||||
role: model.get('name'),
|
||||
});
|
||||
}
|
||||
|
||||
role.setStrategy({
|
||||
...(model.get('strategy') || {}),
|
||||
allowConfigure: model.get('allowConfigure'),
|
||||
model.writeToAcl({
|
||||
acl: this.acl,
|
||||
});
|
||||
|
||||
// model is default
|
||||
@ -229,6 +232,11 @@ export class PluginACL extends Plugin {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// sync database role data to acl
|
||||
this.app.on('beforeStart', async () => {
|
||||
await this.writeRolesToACL();
|
||||
});
|
||||
}
|
||||
|
||||
async load() {
|
||||
|
@ -0,0 +1,56 @@
|
||||
import { Database } from '@nocobase/database';
|
||||
import { mockServer, MockServer } from '@nocobase/test';
|
||||
import CollectionManagerPlugin from '@nocobase/plugin-collection-manager';
|
||||
import { UiSchemaStoragePlugin } from '@nocobase/plugin-ui-schema-storage';
|
||||
|
||||
describe('action test', () => {
|
||||
let db: Database;
|
||||
let app: MockServer;
|
||||
|
||||
beforeEach(async () => {
|
||||
app = mockServer();
|
||||
app.plugin(CollectionManagerPlugin);
|
||||
app.plugin(UiSchemaStoragePlugin);
|
||||
|
||||
db = app.db;
|
||||
await db.clean({ drop: true });
|
||||
await app.loadAndInstall();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.destroy();
|
||||
});
|
||||
it('should append uiSchema', async () => {
|
||||
await db.getRepository('collections').create({
|
||||
values: {
|
||||
name: 'posts',
|
||||
},
|
||||
});
|
||||
|
||||
await db.getRepository('fields').create({
|
||||
values: {
|
||||
name: 'title',
|
||||
collectionName: 'posts',
|
||||
type: 'string',
|
||||
uiSchema: {
|
||||
'x-uid': 'test',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
await db.getRepository('collections').load();
|
||||
await db.sync();
|
||||
|
||||
const response = await app
|
||||
.agent()
|
||||
.resource('collections.fields', 'posts')
|
||||
.list({
|
||||
pageSize: 5,
|
||||
appends: ['uiSchema'],
|
||||
sort: ['sort'],
|
||||
});
|
||||
|
||||
expect(response.statusCode).toEqual(200);
|
||||
});
|
||||
});
|
@ -70,7 +70,7 @@ describe('ui schema model', () => {
|
||||
properties: {
|
||||
child1: {
|
||||
title: 'child1',
|
||||
'x-uid': child1.get('uid'),
|
||||
'x-uid': child1.get('x-uid'),
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
@ -129,7 +129,7 @@ describe('ui schema model', () => {
|
||||
properties: {
|
||||
child1: {
|
||||
title: 'new-child1-title',
|
||||
'x-uid': child1.get('uid'),
|
||||
'x-uid': child1.get('x-uid'),
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
|
@ -56,7 +56,7 @@ describe('ui_schema repository', () => {
|
||||
// it should save in ui schema tables
|
||||
const testNode = await repository.findOne({
|
||||
filter: {
|
||||
uid: 'test',
|
||||
'x-uid': 'test',
|
||||
},
|
||||
});
|
||||
|
||||
@ -277,8 +277,8 @@ describe('ui_schema repository', () => {
|
||||
(
|
||||
await treePathCollection.repository.findOne({
|
||||
filter: {
|
||||
ancestor: root.get('uid'),
|
||||
descendant: a1.get('uid'),
|
||||
ancestor: root.get('x-uid'),
|
||||
descendant: a1.get('x-uid'),
|
||||
depth: 1,
|
||||
},
|
||||
})
|
||||
@ -289,8 +289,8 @@ describe('ui_schema repository', () => {
|
||||
(
|
||||
await treePathCollection.repository.findOne({
|
||||
filter: {
|
||||
ancestor: root.get('uid'),
|
||||
descendant: b1.get('uid'),
|
||||
ancestor: root.get('x-uid'),
|
||||
descendant: b1.get('x-uid'),
|
||||
depth: 1,
|
||||
},
|
||||
})
|
||||
@ -301,8 +301,8 @@ describe('ui_schema repository', () => {
|
||||
(
|
||||
await treePathCollection.repository.findOne({
|
||||
filter: {
|
||||
ancestor: b1.get('uid'),
|
||||
descendant: c1.get('uid'),
|
||||
ancestor: b1.get('x-uid'),
|
||||
descendant: c1.get('x-uid'),
|
||||
depth: 1,
|
||||
},
|
||||
})
|
||||
@ -313,8 +313,8 @@ describe('ui_schema repository', () => {
|
||||
(
|
||||
await treePathCollection.repository.findOne({
|
||||
filter: {
|
||||
ancestor: b1.get('uid'),
|
||||
descendant: d1.get('uid'),
|
||||
ancestor: b1.get('x-uid'),
|
||||
descendant: d1.get('x-uid'),
|
||||
depth: 1,
|
||||
},
|
||||
})
|
||||
@ -330,7 +330,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const results = await repository.getJsonSchema(rootNode.get('uid') as string);
|
||||
const results = await repository.getJsonSchema(rootNode.get('x-uid') as string);
|
||||
|
||||
expect(results).toMatchObject({
|
||||
type: 'object',
|
||||
@ -375,7 +375,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const results = await repository.getProperties(rootNode.get('uid') as string);
|
||||
const results = await repository.getProperties(rootNode.get('x-uid') as string);
|
||||
|
||||
expect(results).toMatchObject({
|
||||
type: 'object',
|
||||
@ -468,7 +468,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
rootUid = rootNode.get('uid') as string;
|
||||
rootUid = rootNode.get('x-uid') as string;
|
||||
});
|
||||
|
||||
it('should insertAfterBegin', async () => {
|
||||
@ -506,7 +506,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
await repository.insertBeforeBegin(b1Node.get('uid') as string, newNode);
|
||||
await repository.insertBeforeBegin(b1Node.get('x-uid') as string, newNode);
|
||||
|
||||
const schema = await repository.getJsonSchema(rootUid);
|
||||
expect(schema.properties['newNode']['x-index']).toEqual(2);
|
||||
@ -525,7 +525,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
await repository.insertAfterEnd(a1Node.get('uid') as string, newNode);
|
||||
await repository.insertAfterEnd(a1Node.get('x-uid') as string, newNode);
|
||||
|
||||
const schema = await repository.getJsonSchema(rootUid);
|
||||
expect(schema.properties['newNode']['x-index']).toEqual(2);
|
||||
@ -544,7 +544,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
await repository.insertAfterEnd(b1Node.get('uid') as string, newNode);
|
||||
await repository.insertAfterEnd(b1Node.get('x-uid') as string, newNode);
|
||||
|
||||
const schema = await repository.getJsonSchema(rootUid);
|
||||
expect(schema.properties['newNode']['x-index']).toEqual(3);
|
||||
@ -705,7 +705,7 @@ describe('ui_schema repository', () => {
|
||||
},
|
||||
});
|
||||
|
||||
rootUid = rootNode.get('uid') as string;
|
||||
rootUid = rootNode.get('x-uid') as string;
|
||||
});
|
||||
|
||||
it('should patch root ui schema', async () => {
|
||||
@ -924,6 +924,7 @@ describe('ui_schema repository', () => {
|
||||
});
|
||||
|
||||
const A = await repository.getJsonSchema('A');
|
||||
|
||||
expect(A).toEqual({
|
||||
properties: {
|
||||
E: {
|
||||
|
@ -12,13 +12,6 @@ export default {
|
||||
{
|
||||
type: 'uid',
|
||||
name: 'x-uid',
|
||||
field: 'uid',
|
||||
primaryKey: true,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'uid',
|
||||
field: 'uid',
|
||||
primaryKey: true,
|
||||
},
|
||||
{
|
||||
|
@ -38,6 +38,14 @@ export class UiSchemaRepository extends Repository {
|
||||
return model.tableName;
|
||||
}
|
||||
|
||||
sqlAdapter(sql: string) {
|
||||
if (this.database.sequelize.getDialect() === 'mysql') {
|
||||
return lodash.replace(sql, /"/g, '`');
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
static schemaToSingleNodes(schema: any, carry: SchemaNode[] = [], childOptions: ChildOptions = null): SchemaNode[] {
|
||||
const node = lodash.cloneDeep(
|
||||
lodash.isString(schema)
|
||||
@ -99,16 +107,16 @@ export class UiSchemaRepository extends Repository {
|
||||
const db = this.database;
|
||||
|
||||
const rawSql = `
|
||||
SELECT SchemaTable.uid as uid, SchemaTable.name as name, SchemaTable.schema as "schema",
|
||||
SELECT "SchemaTable"."x-uid" as "x-uid", "SchemaTable"."name" as "name", "SchemaTable"."schema" as "schema",
|
||||
TreePath.depth as depth,
|
||||
NodeInfo.type as type, NodeInfo.async as async, ParentPath.ancestor as parent, ParentPath.sort as sort
|
||||
FROM ${this.uiSchemaTreePathTableName} as TreePath
|
||||
LEFT JOIN ${this.uiSchemasTableName} as SchemaTable ON SchemaTable.uid = TreePath.descendant
|
||||
LEFT JOIN ${this.uiSchemaTreePathTableName} as NodeInfo ON NodeInfo.descendant = SchemaTable.uid and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
|
||||
LEFT JOIN ${this.uiSchemaTreePathTableName} as ParentPath ON (ParentPath.descendant = SchemaTable.uid AND ParentPath.depth = 1)
|
||||
LEFT JOIN ${this.uiSchemasTableName} as "SchemaTable" ON "SchemaTable"."x-uid" = TreePath.descendant
|
||||
LEFT JOIN ${this.uiSchemaTreePathTableName} as NodeInfo ON NodeInfo.descendant = "SchemaTable"."x-uid" and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
|
||||
LEFT JOIN ${this.uiSchemaTreePathTableName} as ParentPath ON (ParentPath.descendant = "SchemaTable"."x-uid" AND ParentPath.depth = 1)
|
||||
WHERE TreePath.ancestor = :ancestor AND (NodeInfo.async = false or TreePath.depth = 1)`;
|
||||
|
||||
const nodes = await db.sequelize.query(rawSql, {
|
||||
const nodes = await db.sequelize.query(this.sqlAdapter(rawSql), {
|
||||
replacements: {
|
||||
ancestor: uid,
|
||||
},
|
||||
@ -128,17 +136,17 @@ export class UiSchemaRepository extends Repository {
|
||||
const treeTable = this.uiSchemaTreePathTableName;
|
||||
|
||||
const rawSql = `
|
||||
SELECT SchemaTable.uid as uid, SchemaTable.name as name, SchemaTable.schema as "schema" ,
|
||||
SELECT "SchemaTable"."x-uid" as "x-uid", "SchemaTable"."name" as name, "SchemaTable"."schema" as "schema" ,
|
||||
TreePath.depth as depth,
|
||||
NodeInfo.type as type, NodeInfo.async as async, ParentPath.ancestor as parent, ParentPath.sort as sort
|
||||
FROM ${treeTable} as TreePath
|
||||
LEFT JOIN ${this.uiSchemasTableName} as SchemaTable ON SchemaTable.uid = TreePath.descendant
|
||||
LEFT JOIN ${treeTable} as NodeInfo ON NodeInfo.descendant = SchemaTable.uid and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
|
||||
LEFT JOIN ${treeTable} as ParentPath ON (ParentPath.descendant = SchemaTable.uid AND ParentPath.depth = 1)
|
||||
LEFT JOIN ${this.uiSchemasTableName} as "SchemaTable" ON "SchemaTable"."x-uid" = TreePath.descendant
|
||||
LEFT JOIN ${treeTable} as NodeInfo ON NodeInfo.descendant = "SchemaTable"."x-uid" and NodeInfo.descendant = NodeInfo.ancestor and NodeInfo.depth = 0
|
||||
LEFT JOIN ${treeTable} as ParentPath ON (ParentPath.descendant = "SchemaTable"."x-uid" AND ParentPath.depth = 1)
|
||||
WHERE TreePath.ancestor = :ancestor ${options?.includeAsyncNode ? '' : 'AND (NodeInfo.async != true )'}
|
||||
`;
|
||||
|
||||
const nodes = await db.sequelize.query(rawSql, {
|
||||
const nodes = await db.sequelize.query(this.sqlAdapter(rawSql), {
|
||||
replacements: {
|
||||
ancestor: uid,
|
||||
},
|
||||
@ -158,7 +166,7 @@ export class UiSchemaRepository extends Repository {
|
||||
const schema = {
|
||||
...(lodash.isPlainObject(node.schema) ? node.schema : JSON.parse(node.schema)),
|
||||
...lodash.pick(node, [...nodeKeys, 'name']),
|
||||
['x-uid']: node.uid,
|
||||
['x-uid']: node['x-uid'],
|
||||
['x-async']: !!node.async,
|
||||
};
|
||||
|
||||
@ -170,7 +178,7 @@ export class UiSchemaRepository extends Repository {
|
||||
};
|
||||
|
||||
const buildTree = (rootNode) => {
|
||||
const children = nodes.filter((node) => node.parent == rootNode.uid);
|
||||
const children = nodes.filter((node) => node.parent == rootNode['x-uid']);
|
||||
|
||||
if (children.length > 0) {
|
||||
const childrenGroupByType = lodash.groupBy(children, 'type');
|
||||
@ -196,7 +204,7 @@ export class UiSchemaRepository extends Repository {
|
||||
return nodeAttributeSanitize(rootNode);
|
||||
};
|
||||
|
||||
return buildTree(nodes.find((node) => node.uid == rootUid));
|
||||
return buildTree(nodes.find((node) => node['x-uid'] == rootUid));
|
||||
}
|
||||
|
||||
treeCollection() {
|
||||
@ -244,7 +252,7 @@ export class UiSchemaRepository extends Repository {
|
||||
async updateNode(uid: string, schema: any, transaction?: Transaction) {
|
||||
const nodeModel = await this.findOne({
|
||||
filter: {
|
||||
uid,
|
||||
'x-uid': uid,
|
||||
},
|
||||
});
|
||||
|
||||
@ -299,7 +307,7 @@ export class UiSchemaRepository extends Repository {
|
||||
protected async findNodeSchemaWithParent(uid, transaction) {
|
||||
const schema = await this.database.getRepository('uiSchemas').findOne({
|
||||
filter: {
|
||||
uid,
|
||||
'x-uid': uid,
|
||||
},
|
||||
transaction,
|
||||
});
|
||||
@ -324,7 +332,7 @@ export class UiSchemaRepository extends Repository {
|
||||
if (parentChildrenCount == 1) {
|
||||
const schema = await db.getRepository('uiSchemas').findOne({
|
||||
filter: {
|
||||
uid: parent,
|
||||
'x-uid': parent,
|
||||
},
|
||||
transaction,
|
||||
});
|
||||
@ -342,7 +350,7 @@ export class UiSchemaRepository extends Repository {
|
||||
const parent = await this.isSingleChild(nodeUid, transaction);
|
||||
|
||||
if (parent && !this.breakOnMatched(parent, breakRemoveOn)) {
|
||||
await removeParent(parent.get('uid') as string);
|
||||
await removeParent(parent.get('x-uid') as string);
|
||||
} else {
|
||||
await this.remove(nodeUid, { transaction });
|
||||
}
|
||||
@ -416,7 +424,7 @@ export class UiSchemaRepository extends Repository {
|
||||
}
|
||||
|
||||
await this.database.sequelize.query(
|
||||
`DELETE FROM ${this.uiSchemasTableName} WHERE uid IN (
|
||||
`DELETE FROM ${this.uiSchemasTableName} WHERE 'x-uid' IN (
|
||||
SELECT descendant FROM ${treePathTable} WHERE ancestor = :uid
|
||||
)
|
||||
`,
|
||||
@ -482,7 +490,7 @@ export class UiSchemaRepository extends Repository {
|
||||
};
|
||||
|
||||
const insertedNodes = await this.insertNodes(nodes, options);
|
||||
return await this.getJsonSchema(insertedNodes[0].get('uid'));
|
||||
return await this.getJsonSchema(insertedNodes[0].get('x-uid'));
|
||||
}
|
||||
|
||||
async insertInner(targetUid: string, schema: any, position: 'first' | 'last', options?: InsertAdjacentOptions) {
|
||||
@ -496,7 +504,7 @@ export class UiSchemaRepository extends Repository {
|
||||
};
|
||||
|
||||
const insertedNodes = await this.insertNodes(nodes, options);
|
||||
return await this.getJsonSchema(insertedNodes[0].get('uid'));
|
||||
return await this.getJsonSchema(insertedNodes[0].get('x-uid'));
|
||||
}
|
||||
|
||||
async insertAdjacent(
|
||||
@ -563,7 +571,7 @@ export class UiSchemaRepository extends Repository {
|
||||
async insert(schema: any, options?: TransactionAble) {
|
||||
const nodes = UiSchemaRepository.schemaToSingleNodes(schema);
|
||||
const insertedNodes = await this.insertNodes(nodes, options);
|
||||
return this.getJsonSchema(insertedNodes[0].get('uid'), {
|
||||
return this.getJsonSchema(insertedNodes[0].get('x-uid'), {
|
||||
transaction: options?.transaction,
|
||||
});
|
||||
}
|
||||
@ -575,7 +583,6 @@ export class UiSchemaRepository extends Repository {
|
||||
values: {
|
||||
name,
|
||||
['x-uid']: uid,
|
||||
uid,
|
||||
schema,
|
||||
serverHooks,
|
||||
},
|
||||
@ -592,7 +599,6 @@ export class UiSchemaRepository extends Repository {
|
||||
const { transaction } = options;
|
||||
|
||||
const db = this.database;
|
||||
const treeCollection = db.getCollection('uiSchemaTreePath');
|
||||
|
||||
const uid = schema['x-uid'];
|
||||
const name = schema['name'];
|
||||
@ -609,7 +615,7 @@ export class UiSchemaRepository extends Repository {
|
||||
// check node exists or not
|
||||
const existsNode = await this.findOne({
|
||||
filter: {
|
||||
uid,
|
||||
'x-uid': uid,
|
||||
},
|
||||
transaction,
|
||||
});
|
||||
@ -695,7 +701,7 @@ export class UiSchemaRepository extends Repository {
|
||||
type: 'INSERT',
|
||||
transaction,
|
||||
replacements: {
|
||||
modelKey: savedNode.get('uid'),
|
||||
modelKey: savedNode.get('x-uid'),
|
||||
modelParentKey: parentUid,
|
||||
},
|
||||
},
|
||||
@ -709,7 +715,7 @@ export class UiSchemaRepository extends Repository {
|
||||
{
|
||||
type: 'INSERT',
|
||||
replacements: {
|
||||
modelKey: savedNode.get('uid'),
|
||||
modelKey: savedNode.get('x-uid'),
|
||||
type: childOptions.type,
|
||||
async,
|
||||
},
|
||||
@ -858,7 +864,7 @@ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort
|
||||
{
|
||||
type: 'INSERT',
|
||||
replacements: {
|
||||
modelKey: savedNode.get('uid'),
|
||||
modelKey: savedNode.get('x-uid'),
|
||||
async,
|
||||
},
|
||||
transaction,
|
||||
|
@ -8,7 +8,7 @@ export async function bindMenuToRole({ schemaInstance, db, options }) {
|
||||
|
||||
for (const role of addNewMenuRoles) {
|
||||
await db.getRepository('roles.menuUiSchemas', role.get('name')).add({
|
||||
tk: schemaInstance.get('uid'),
|
||||
tk: schemaInstance.get('x-uid'),
|
||||
transaction,
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { UiSchemaRepository } from '../../repository';
|
||||
export async function removeSchema({ schemaInstance, options, db, params }) {
|
||||
const { transaction } = options;
|
||||
const uiSchemaRepository: UiSchemaRepository = db.getRepository('uiSchemas');
|
||||
const uid = schemaInstance.get('uid') as string;
|
||||
const uid = schemaInstance.get('x-uid') as string;
|
||||
|
||||
if (params?.removeParentsIfNoChildren) {
|
||||
await uiSchemaRepository.removeEmptyParents({
|
||||
|
@ -27,7 +27,6 @@ export class UiSchemaStoragePlugin extends Plugin {
|
||||
this.registerRepository();
|
||||
|
||||
db.on('uiSchemas.beforeCreate', function setUid(model) {
|
||||
model.set('uid', model.get('x-uid'));
|
||||
if (!model.get('name')) {
|
||||
model.set('name', uid());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user