mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 05:36:05 +00:00
fix: resolve unauthorized error on button click for normal roles (#5206)
* feat(server): add 'upgrade' action for uiSchemas * test: add unit tests * chore: update unit test * refactor: rename 'upgrade' to 'initializeActionContext' * fix: transaction * chore: fix build --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
4365c3ea4a
commit
68c3d1d62a
@ -54,12 +54,11 @@ describe('usePopupContextInActionOrAssociationField', () => {
|
|||||||
dataSource: 'dataSource',
|
dataSource: 'dataSource',
|
||||||
collection: 'collection',
|
collection: 'collection',
|
||||||
association: 'association',
|
association: 'association',
|
||||||
sourceId: 'sourceId',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
result.current.updatePopupContext(context);
|
result.current.updatePopupContext(context);
|
||||||
|
|
||||||
expect(dnMock.emit).toHaveBeenCalledWith('patch', {
|
expect(dnMock.emit).toHaveBeenCalledWith('initializeActionContext', {
|
||||||
schema: {
|
schema: {
|
||||||
'x-uid': fieldSchemaMock['x-uid'],
|
'x-uid': fieldSchemaMock['x-uid'],
|
||||||
'x-action-context': context,
|
'x-action-context': context,
|
||||||
@ -84,9 +83,8 @@ describe('usePopupContextInActionOrAssociationField', () => {
|
|||||||
result.current.updatePopupContext({
|
result.current.updatePopupContext({
|
||||||
...context,
|
...context,
|
||||||
collection: undefined,
|
collection: undefined,
|
||||||
sourceId: null,
|
|
||||||
});
|
});
|
||||||
expect(dnMock.emit).toHaveBeenCalledWith('patch', {
|
expect(dnMock.emit).toHaveBeenCalledWith('initializeActionContext', {
|
||||||
schema: {
|
schema: {
|
||||||
'x-uid': fieldSchemaMock['x-uid'],
|
'x-uid': fieldSchemaMock['x-uid'],
|
||||||
'x-action-context': {
|
'x-action-context': {
|
||||||
|
@ -39,7 +39,7 @@ export const usePopupContextInActionOrAssociationField = () => {
|
|||||||
|
|
||||||
customSchema[CONTEXT_SCHEMA_KEY] = context;
|
customSchema[CONTEXT_SCHEMA_KEY] = context;
|
||||||
|
|
||||||
return dn.emit('patch', {
|
return dn.emit('initializeActionContext', {
|
||||||
schema: {
|
schema: {
|
||||||
'x-uid': customSchema['x-uid'],
|
'x-uid': customSchema['x-uid'],
|
||||||
[CONTEXT_SCHEMA_KEY]: context,
|
[CONTEXT_SCHEMA_KEY]: context,
|
||||||
|
@ -217,6 +217,19 @@ export class Designable {
|
|||||||
});
|
});
|
||||||
message.success(t('Saved successfully'), 0.2);
|
message.success(t('Saved successfully'), 0.2);
|
||||||
});
|
});
|
||||||
|
this.on('initializeActionContext', async ({ schema }) => {
|
||||||
|
this.refresh();
|
||||||
|
if (!schema?.['x-uid']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await api.request({
|
||||||
|
url: `/uiSchemas:initializeActionContext`,
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
...schema,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
this.on('batchPatch', async ({ schemas }) => {
|
this.on('batchPatch', async ({ schemas }) => {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
await api.request({
|
await api.request({
|
||||||
@ -267,14 +280,17 @@ export class Designable {
|
|||||||
generateUid(schema);
|
generateUid(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
on(name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch', listener: any) {
|
on(name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch' | 'initializeActionContext', listener: any) {
|
||||||
if (!this.events[name]) {
|
if (!this.events[name]) {
|
||||||
this.events[name] = [];
|
this.events[name] = [];
|
||||||
}
|
}
|
||||||
this.events[name].push(listener);
|
this.events[name].push(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
async emit(name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch', ...args) {
|
async emit(
|
||||||
|
name: 'insertAdjacent' | 'remove' | 'error' | 'patch' | 'batchPatch' | 'initializeActionContext',
|
||||||
|
...args
|
||||||
|
) {
|
||||||
if (!this.events[name]) {
|
if (!this.events[name]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -248,6 +248,65 @@ describe('action test', () => {
|
|||||||
expect(data.properties.b['properties']['c']['title']).toEqual('c-title');
|
expect(data.properties.b['properties']['c']['title']).toEqual('c-title');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('initializeActionContext', async () => {
|
||||||
|
await app
|
||||||
|
.agent()
|
||||||
|
.resource('uiSchemas')
|
||||||
|
.insert({
|
||||||
|
values: {
|
||||||
|
'x-uid': 'n1',
|
||||||
|
name: 'a',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
b: {
|
||||||
|
'x-uid': 'n2',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
c: { 'x-uid': 'n3' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
d: { 'x-uid': 'n4' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = await app
|
||||||
|
.agent()
|
||||||
|
.resource('uiSchemas')
|
||||||
|
.initializeActionContext({
|
||||||
|
values: {
|
||||||
|
'x-uid': 'n1',
|
||||||
|
'x-action-context': {
|
||||||
|
field1: 'field1',
|
||||||
|
field2: 'field2',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
b: {
|
||||||
|
properties: {
|
||||||
|
c: {
|
||||||
|
title: 'c-title',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
response = await app.agent().resource('uiSchemas').getJsonSchema({
|
||||||
|
resourceIndex: 'n1',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data } = response.body;
|
||||||
|
|
||||||
|
// only update the x-action-context
|
||||||
|
expect(data.properties.b['properties']['c']['title']).toBe(undefined);
|
||||||
|
expect(data['x-action-context']).toEqual({
|
||||||
|
field1: 'field1',
|
||||||
|
field2: 'field2',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('insert adjacent', async () => {
|
test('insert adjacent', async () => {
|
||||||
await app
|
await app
|
||||||
.agent()
|
.agent()
|
||||||
|
@ -952,6 +952,96 @@ describe('ui_schema repository', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('initializeActionContext', function () {
|
||||||
|
let rootNode;
|
||||||
|
let rootUid: string;
|
||||||
|
let oldTree;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const root = {
|
||||||
|
type: 'object',
|
||||||
|
title: 'title',
|
||||||
|
name: 'root',
|
||||||
|
properties: {
|
||||||
|
a1: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'A1',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
b1: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'B1',
|
||||||
|
properties: {
|
||||||
|
c1: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'C1',
|
||||||
|
},
|
||||||
|
d1: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'D1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await repository.insert(root);
|
||||||
|
|
||||||
|
rootNode = await repository.findOne({
|
||||||
|
filter: {
|
||||||
|
name: 'root',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
rootUid = rootNode.get('x-uid') as string;
|
||||||
|
|
||||||
|
oldTree = await repository.getJsonSchema(rootUid);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update root ui schema and only have x-action-context to be updated', async () => {
|
||||||
|
await repository.initializeActionContext({
|
||||||
|
'x-uid': rootUid,
|
||||||
|
title: 'test-title',
|
||||||
|
['x-action-context']: {
|
||||||
|
field1: 'field1',
|
||||||
|
field2: 'field2',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
a1: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'new a1 title',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const newTree = await repository.getJsonSchema(rootUid);
|
||||||
|
expect(newTree).toEqual({
|
||||||
|
...oldTree,
|
||||||
|
['x-action-context']: {
|
||||||
|
field1: 'field1',
|
||||||
|
field2: 'field2',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// will not updated when x-action-context existed
|
||||||
|
await repository.initializeActionContext({
|
||||||
|
'x-uid': rootUid,
|
||||||
|
['x-action-context']: {
|
||||||
|
field3: 'field3',
|
||||||
|
field4: 'field4',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(newTree).toEqual({
|
||||||
|
...oldTree,
|
||||||
|
['x-action-context']: {
|
||||||
|
field1: 'field1',
|
||||||
|
field2: 'field2',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should insertInner with removeParent', async () => {
|
it('should insertInner with removeParent', async () => {
|
||||||
const schema = {
|
const schema = {
|
||||||
'x-uid': 'A',
|
'x-uid': 'A',
|
||||||
|
@ -67,6 +67,7 @@ export const uiSchemaActions = {
|
|||||||
insertNewSchema: callRepositoryMethod('insertNewSchema', 'values'),
|
insertNewSchema: callRepositoryMethod('insertNewSchema', 'values'),
|
||||||
remove: callRepositoryMethod('remove', 'resourceIndex'),
|
remove: callRepositoryMethod('remove', 'resourceIndex'),
|
||||||
patch: callRepositoryMethod('patch', 'values'),
|
patch: callRepositoryMethod('patch', 'values'),
|
||||||
|
initializeActionContext: callRepositoryMethod('initializeActionContext', 'values'),
|
||||||
batchPatch: callRepositoryMethod('batchPatch', 'values'),
|
batchPatch: callRepositoryMethod('batchPatch', 'values'),
|
||||||
clearAncestor: callRepositoryMethod('clearAncestor', 'resourceIndex'),
|
clearAncestor: callRepositoryMethod('clearAncestor', 'resourceIndex'),
|
||||||
|
|
||||||
|
@ -331,6 +331,28 @@ export class UiSchemaRepository extends Repository {
|
|||||||
await traverSchemaTree(newSchema);
|
await traverSchemaTree(newSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@transaction()
|
||||||
|
async initializeActionContext(newSchema: any, options: any = {}) {
|
||||||
|
if (!newSchema['x-uid'] || !newSchema['x-action-context']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { transaction } = options;
|
||||||
|
|
||||||
|
const nodeModel = await this.findOne({
|
||||||
|
filter: {
|
||||||
|
'x-uid': newSchema['x-uid'],
|
||||||
|
},
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!lodash.isEmpty(nodeModel?.get('schema')['x-action-context'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.patch(lodash.pick(newSchema, ['x-uid', 'x-action-context']), options);
|
||||||
|
}
|
||||||
|
|
||||||
@transaction()
|
@transaction()
|
||||||
async batchPatch(schemas: any[], options?) {
|
async batchPatch(schemas: any[], options?) {
|
||||||
const { transaction } = options;
|
const { transaction } = options;
|
||||||
|
@ -80,7 +80,11 @@ export class PluginUISchemaStorageServer extends Plugin {
|
|||||||
actions: uiSchemaActions,
|
actions: uiSchemaActions,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.acl.allow('uiSchemas', ['getProperties', 'getJsonSchema', 'getParentJsonSchema'], 'loggedIn');
|
this.app.acl.allow(
|
||||||
|
'uiSchemas',
|
||||||
|
['getProperties', 'getJsonSchema', 'getParentJsonSchema', 'initializeActionContext'],
|
||||||
|
'loggedIn',
|
||||||
|
);
|
||||||
this.app.acl.allow('uiSchemaTemplates', ['get', 'list'], 'loggedIn');
|
this.app.acl.allow('uiSchemaTemplates', ['get', 'list'], 'loggedIn');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user