diff --git a/packages/core/acl/src/acl.ts b/packages/core/acl/src/acl.ts index 1e39a5e9aa..00e86e5ceb 100644 --- a/packages/core/acl/src/acl.ts +++ b/packages/core/acl/src/acl.ts @@ -467,6 +467,8 @@ export class ACL extends EventEmitter { } } + const isEmptyFields = resourcerAction.params.fields && resourcerAction.params.fields.length === 0; + resourcerAction.mergeParams(parsedParams, { appends: (x, y) => { if (!x) { @@ -478,6 +480,11 @@ export class ACL extends EventEmitter { return (x as any[]).filter((i) => y.includes(i.split('.').shift())); }, }); + + if (isEmptyFields) { + resourcerAction.params.fields = []; + } + ctx.permission.mergedParams = lodash.cloneDeep(resourcerAction.params); } } catch (e) { diff --git a/packages/core/server/src/middlewares/data-template.ts b/packages/core/server/src/middlewares/data-template.ts index 473645b623..023e12145f 100644 --- a/packages/core/server/src/middlewares/data-template.ts +++ b/packages/core/server/src/middlewares/data-template.ts @@ -12,14 +12,14 @@ import { Collection } from '@nocobase/database'; export async function dataTemplate(ctx: Context, next) { const { resourceName, actionName } = ctx.action; - const { isTemplate, fields } = ctx.action.params; + const { isTemplate, fields, appends } = ctx.action.params; await next(); - if (isTemplate && actionName === 'get' && fields.length > 0) { + if (isTemplate && actionName === 'get') { ctx.body = traverseJSON(JSON.parse(JSON.stringify(ctx.body)), { collection: ctx.db.getCollection(resourceName), - include: fields, + include: [...(fields || []), ...(appends || [])], }); } } diff --git a/packages/plugins/@nocobase/plugin-acl/src/server/__tests__/get-action.test.ts b/packages/plugins/@nocobase/plugin-acl/src/server/__tests__/get-action.test.ts new file mode 100644 index 0000000000..d8191abccf --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/server/__tests__/get-action.test.ts @@ -0,0 +1,90 @@ +import { MockServer } from '@nocobase/test'; +import { prepareApp } from './prepare'; + +describe('get action with acl', () => { + let app: MockServer; + + let Post; + + let Comment; + + beforeEach(async () => { + app = await prepareApp(); + + Post = app.db.collection({ + name: 'posts', + fields: [ + { type: 'string', name: 'title' }, + { + type: 'bigInt', + name: 'createdById', + }, + { + type: 'hasMany', + name: 'comments', + target: 'comments', + }, + ], + }); + + Comment = app.db.collection({ + name: 'comments', + fields: [ + { + type: 'string', + name: 'content', + }, + ], + }); + + await app.db.sync(); + }); + + it('should get with fields', async () => { + const testRole = app.acl.define({ + role: 'test', + }); + + testRole.grantAction('posts:view', { + fields: ['title', 'comments'], + }); + + testRole.grantAction('comments:view', { + fields: ['content'], + }); + + const [p1] = await Post.repository.create({ + values: [ + { + title: 'p1', + comments: [{ content: 'c1' }, { content: 'c2' }], + }, + ], + }); + + app.resourceManager.use( + (ctx, next) => { + ctx.state.currentRole = 'test'; + return next(); + }, + { + before: 'acl', + }, + ); + + const response = await (app as any) + .agent() + .resource('posts') + .get({ + filterByTk: p1.get('id'), + fields: ['comments'], + }); + + expect(response.status).toBe(200); + + console.log(response.body); + // expect only has comments + expect(response.body.data.title).toBeUndefined(); + expect(response.body.data.comments).toBeDefined(); + }); +});