fix(acl): bug of user filtering when adding them to roles (#3754)

* fix(acl): bug of user filtering when adding them to roles

* chore: add tests
This commit is contained in:
YANG QIA 2024-03-19 17:53:13 +08:00 committed by GitHub
parent 02742c3c76
commit b6d17853d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 123 additions and 55 deletions

View File

@ -1,6 +1,13 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Card, Row, Col, Tabs, Divider } from 'antd'; import { Card, Row, Col, Tabs, Divider } from 'antd';
import { CollectionProvider, CollectionProvider_deprecated, ResourceActionProvider, usePlugin } from '@nocobase/client'; import {
CollectionProvider,
CollectionProvider_deprecated,
ResourceActionProvider,
SchemaComponentContext,
usePlugin,
useSchemaComponentContext,
} from '@nocobase/client';
import { ISchema, Schema } from '@formily/react'; import { ISchema, Schema } from '@formily/react';
import { RolesMenu } from './RolesMenu'; import { RolesMenu } from './RolesMenu';
import { useACLTranslation } from './locale'; import { useACLTranslation } from './locale';
@ -58,53 +65,56 @@ export const RolesManagement: React.FC = () => {
children: item.Component ? React.createElement(item.Component, { active: activeKey === name }) : null, children: item.Component ? React.createElement(item.Component, { active: activeKey === name }) : null,
})); }));
const [role, setRole] = useState(null); const [role, setRole] = useState(null);
const scCtx = useSchemaComponentContext();
return ( return (
<RolesManagerContext.Provider value={{ role, setRole }}> <SchemaComponentContext.Provider value={{ ...scCtx, designable: false }}>
<Card> <RolesManagerContext.Provider value={{ role, setRole }}>
<Row gutter={24} style={{ flexWrap: 'nowrap' }}> <Card>
<Col flex="280px" style={{ borderRight: '1px solid #eee', minWidth: '250px' }}> <Row gutter={24} style={{ flexWrap: 'nowrap' }}>
<ResourceActionProvider <Col flex="280px" style={{ borderRight: '1px solid #eee', minWidth: '250px' }}>
collection={collection} <ResourceActionProvider
request={{ collection={collection}
resource: 'roles', request={{
action: 'list', resource: 'roles',
params: { action: 'list',
pagination: false, params: {
filter: { pagination: false,
'name.$ne': 'root', filter: {
'name.$ne': 'root',
},
showAnonymous: true,
sort: ['createdAt'],
appends: [],
}, },
showAnonymous: true, }}
sort: ['createdAt'], >
appends: [], <CollectionProvider_deprecated collection={collection}>
}, <Row>
}} <NewRole />
> </Row>
<CollectionProvider_deprecated collection={collection}> <Divider style={{ margin: '12px 0' }} />
<Row> <RolesMenu />
<NewRole /> </CollectionProvider_deprecated>
</Row> </ResourceActionProvider>
<Divider style={{ margin: '12px 0' }} /> </Col>
<RolesMenu /> <Col flex="auto" style={{ overflow: 'hidden' }}>
</CollectionProvider_deprecated> <Tabs
</ResourceActionProvider> activeKey={activeKey}
</Col> onChange={(key) => setActiveKey(key)}
<Col flex="auto" style={{ overflow: 'hidden' }}> items={[
<Tabs {
activeKey={activeKey} key: 'permissions',
onChange={(key) => setActiveKey(key)} label: t('Permissions'),
items={[ children: <Permissions active={activeKey === 'permissions'} />,
{ },
key: 'permissions', ...tabs,
label: t('Permissions'), ]}
children: <Permissions active={activeKey === 'permissions'} />, />
}, </Col>
...tabs, </Row>
]} </Card>
/> </RolesManagerContext.Provider>
</Col> </SchemaComponentContext.Provider>
</Row>
</Card>
</RolesManagerContext.Provider>
); );
}; };

View File

@ -0,0 +1,56 @@
import { Database, Repository } from '@nocobase/database';
import { MockServer, createMockServer } from '@nocobase/test';
describe('actions', () => {
let app: MockServer;
let db: Database;
let repo: Repository;
let agent: any;
beforeAll(async () => {
app = await createMockServer({
plugins: ['acl', 'users', 'data-source-manager'],
});
db = app.db;
repo = db.getRepository('users');
agent = app.agent();
});
afterAll(async () => {
await app.destroy();
});
it('should list users exclude role', async () => {
const res = await agent.resource('users').listExcludeRole({
roleName: ['admin'],
});
expect(res.status).toBe(200);
expect(res.body.data.length).toBe(0);
});
it('should list users exclude role with filter', async () => {
let res = await agent.resource('users').listExcludeRole({
roleName: ['test'],
});
expect(res.status).toBe(200);
expect(res.body.data.length).toBe(1);
res = await agent.resource('users').listExcludeRole({
roleName: ['test'],
filter: {
id: 1,
},
});
expect(res.status).toBe(200);
expect(res.body.data.length).toBe(1);
res = await agent.resource('users').listExcludeRole({
roleName: ['test'],
filter: {
id: 2,
},
});
expect(res.status).toBe(200);
expect(res.body.data.length).toBe(0);
});
});

View File

@ -25,19 +25,21 @@ export const listExcludeRole = async (ctx: Context, next: Next) => {
}, },
}); });
const userIds = users.map((user: { id: number }) => user.id); const userIds = users.map((user: { id: number }) => user.id);
if (userIds.length) {
ctx.action.mergeParams({
filter: {
id: {
$notIn: userIds,
},
},
});
}
const { filter } = ctx.action.params;
const [rows, count] = await repo.findAndCount({ const [rows, count] = await repo.findAndCount({
context: ctx, context: ctx,
offset: (page - 1) * pageSize, offset: (page - 1) * pageSize,
limit: pageSize, limit: pageSize,
// Ensure memberIds is not empty to resolve strange issue: filter,
// notIn: [] will be translated to "WHERE id IS NULL"
filter: userIds.length
? {
id: {
$notIn: userIds,
},
}
: {},
}); });
ctx.body = { ctx.body = {
count, count,