fix(acl): parse acl params of association collection (#2594)
* fix(acl): parse params of association collection * fix: filter params in association acl
This commit is contained in:
parent
c096a98ceb
commit
d6a2ab4b61
@ -321,20 +321,20 @@ export class ACL extends EventEmitter {
|
|||||||
this.snippetManager.register(snippet);
|
this.snippetManager.register(snippet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterParams(ctx, resourceName, params) {
|
||||||
|
if (params?.filter?.createdById) {
|
||||||
|
const collection = ctx.db.getCollection(resourceName);
|
||||||
|
if (!collection || !collection.getField('createdById')) {
|
||||||
|
return lodash.omit(params, 'filter.createdById');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
protected addCoreMiddleware() {
|
protected addCoreMiddleware() {
|
||||||
const acl = this;
|
const acl = this;
|
||||||
|
|
||||||
const filterParams = (ctx, resourceName, params) => {
|
|
||||||
if (params?.filter?.createdById) {
|
|
||||||
const collection = ctx.db.getCollection(resourceName);
|
|
||||||
if (!collection || !collection.getField('createdById')) {
|
|
||||||
return lodash.omit(params, 'filter.createdById');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.middlewares.add(
|
this.middlewares.add(
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
const resourcerAction: Action = ctx.action;
|
const resourcerAction: Action = ctx.action;
|
||||||
@ -354,7 +354,7 @@ export class ACL extends EventEmitter {
|
|||||||
ctx.log?.info && ctx.log.info('acl params', params);
|
ctx.log?.info && ctx.log.info('acl params', params);
|
||||||
|
|
||||||
if (params && resourcerAction.mergeParams) {
|
if (params && resourcerAction.mergeParams) {
|
||||||
const filteredParams = filterParams(ctx, resourceName, params);
|
const filteredParams = acl.filterParams(ctx, resourceName, params);
|
||||||
const parsedParams = await acl.parseJsonTemplate(filteredParams, ctx);
|
const parsedParams = await acl.parseJsonTemplate(filteredParams, ctx);
|
||||||
|
|
||||||
ctx.permission.parsedParams = parsedParams;
|
ctx.permission.parsedParams = parsedParams;
|
||||||
|
@ -26,6 +26,125 @@ describe('destroy action with acl', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should load the association collection when the source collection does not have the createdById field', async () => {
|
||||||
|
const A = app.collection({
|
||||||
|
name: 'a',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'title' },
|
||||||
|
{ type: 'belongsToMany', name: 'bs', target: 'b' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const B = app.collection({
|
||||||
|
name: 'b',
|
||||||
|
fields: [{ type: 'string', name: 'title' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.db.sync();
|
||||||
|
|
||||||
|
await A.repository.create({
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
title: 'a1',
|
||||||
|
bs: [
|
||||||
|
{
|
||||||
|
title: 'b1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const userRole = app.acl.define({
|
||||||
|
role: 'user',
|
||||||
|
strategy: {
|
||||||
|
actions: ['view:own'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.resourcer.use(
|
||||||
|
(ctx, next) => {
|
||||||
|
ctx.state.currentRole = 'user';
|
||||||
|
ctx.state.currentUser = {
|
||||||
|
id: 1,
|
||||||
|
};
|
||||||
|
return next();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
before: 'acl',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const a1 = await A.repository.findOne({ filter: { title: 'a1' } });
|
||||||
|
|
||||||
|
const response = await app.agent().resource('a.bs', a1.get('id')).list();
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse association acl params', async () => {
|
||||||
|
const Comment = app.db.collection({
|
||||||
|
name: 'comments',
|
||||||
|
fields: [
|
||||||
|
{ type: 'string', name: 'content' },
|
||||||
|
{ type: 'belongsToMany', name: 'posts' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.db.sync();
|
||||||
|
|
||||||
|
await Post.repository.create({
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
title: 'p1',
|
||||||
|
comments: [
|
||||||
|
{
|
||||||
|
content: 'c11',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: 'c12',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'p2',
|
||||||
|
comments: [
|
||||||
|
{
|
||||||
|
content: 'c21',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: 'c22',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const userRole = app.acl.define({
|
||||||
|
role: 'user',
|
||||||
|
strategy: {
|
||||||
|
actions: ['view:own'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.resourcer.use(
|
||||||
|
(ctx, next) => {
|
||||||
|
ctx.state.currentRole = 'user';
|
||||||
|
ctx.state.currentUser = {
|
||||||
|
id: 1,
|
||||||
|
};
|
||||||
|
return next();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
before: 'acl',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const p1 = await Post.repository.findOne({ filter: { title: 'p1' } });
|
||||||
|
|
||||||
|
const response = await app.agent().resource('posts.comments', p1.get('id')).list();
|
||||||
|
expect(response.statusCode).toEqual(403);
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw error when user has no permission to destroy record', async () => {
|
it('should throw error when user has no permission to destroy record', async () => {
|
||||||
const userRole = app.acl.define({
|
const userRole = app.acl.define({
|
||||||
role: 'user',
|
role: 'user',
|
||||||
|
@ -570,7 +570,6 @@ export class PluginACL extends Plugin {
|
|||||||
const action = ctx.can({ resource: collectionName, action: actionName });
|
const action = ctx.can({ resource: collectionName, action: actionName });
|
||||||
|
|
||||||
const availableAction = this.app.acl.getAvailableAction(actionName);
|
const availableAction = this.app.acl.getAvailableAction(actionName);
|
||||||
|
|
||||||
if (availableAction?.options?.onNewRecord) {
|
if (availableAction?.options?.onNewRecord) {
|
||||||
if (action) {
|
if (action) {
|
||||||
ctx.permission.skip = true;
|
ctx.permission.skip = true;
|
||||||
@ -578,11 +577,14 @@ export class PluginACL extends Plugin {
|
|||||||
ctx.permission.can = false;
|
ctx.permission.can = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const filter = await parseJsonTemplate(action?.params?.filter || {}, ctx);
|
const filteredParams = this.app.acl.filterParams(ctx, collectionName, action?.params || {});
|
||||||
|
const params = await parseJsonTemplate(filteredParams, ctx);
|
||||||
|
|
||||||
const sourceInstance = await ctx.db.getRepository(collectionName).findOne({
|
const sourceInstance = await ctx.db.getRepository(collectionName).findOne({
|
||||||
filterByTk: resourceOf,
|
filterByTk: resourceOf,
|
||||||
filter,
|
filter: params.filter || {},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!sourceInstance) {
|
if (!sourceInstance) {
|
||||||
ctx.permission.can = false;
|
ctx.permission.can = false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user