mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-15 04:59:50 +00:00
Add users.isBot flag to index and add defaults to the user spec (#10558)
* Add users.isBot flag to index and add defaults to the user spec * Added bot flag in user search api * change as per comments * fix cypress * revert user.json changes --------- Co-authored-by: Ashish Gupta <ashish@getcollate.io>
This commit is contained in:
parent
3c4b423f36
commit
b153b79723
@ -19,11 +19,15 @@ public class UserIndex implements ElasticSearchIndex {
|
||||
if (user.getDisplayName() == null) {
|
||||
user.setDisplayName(user.getName());
|
||||
}
|
||||
if (user.getIsBot() == null) {
|
||||
user.setIsBot(false);
|
||||
}
|
||||
Map<String, Object> doc = JsonUtils.getMap(user);
|
||||
ElasticSearchIndexUtils.removeNonIndexableFields(doc, excludeFields);
|
||||
List<ElasticSearchSuggest> suggest = new ArrayList<>();
|
||||
suggest.add(ElasticSearchSuggest.builder().input(user.getName()).weight(5).build());
|
||||
suggest.add(ElasticSearchSuggest.builder().input(user.getDisplayName()).weight(10).build());
|
||||
|
||||
doc.put("suggest", suggest);
|
||||
doc.put("entityType", Entity.USER);
|
||||
return doc;
|
||||
|
@ -42,7 +42,10 @@
|
||||
"type": "text"
|
||||
},
|
||||
"isAdmin": {
|
||||
"type": "text"
|
||||
"type": "boolean"
|
||||
},
|
||||
"isBot": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"teams": {
|
||||
"properties": {
|
||||
|
@ -27,6 +27,8 @@ const userEmail = `${userName}@gmail.com`;
|
||||
const adminName = `Admincttest${uuid()}`;
|
||||
const adminEmail = `${adminName}@gmail.com`;
|
||||
|
||||
const searchBotText = 'bot';
|
||||
|
||||
describe('Users flow should work properly', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
@ -75,6 +77,25 @@ describe('Users flow should work properly', () => {
|
||||
softDeleteUser(userName);
|
||||
deleteSoftDeletedUser(userName);
|
||||
});
|
||||
|
||||
it('Search for bot user', () => {
|
||||
interceptURL(
|
||||
'GET',
|
||||
`/api/v1/search/query?q=*${searchBotText}***isBot:false&from=0&size=15&index=user_search_index`,
|
||||
'searchUser'
|
||||
);
|
||||
cy.get('[data-testid="searchbar"]')
|
||||
.should('exist')
|
||||
.should('be.visible')
|
||||
.type(searchBotText);
|
||||
|
||||
verifyResponseStatusCode('@searchUser', 200);
|
||||
|
||||
cy.get('.ant-table-placeholder > .ant-table-cell').should(
|
||||
'not.contain',
|
||||
searchBotText
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Admin flow should work properly', () => {
|
||||
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2023 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { cleanup, render, screen } from '@testing-library/react';
|
||||
import { MOCK_USER_DATA } from 'pages/UserListPage/mockUserData';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { act } from 'react-test-renderer';
|
||||
import UserListV1 from './UserListV1';
|
||||
|
||||
jest.mock('rest/userAPI', () => ({
|
||||
updateUser: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
}));
|
||||
|
||||
jest.mock('../../generated/api/teams/createUser', () => ({
|
||||
CreateUser: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/ToastUtils', () => ({
|
||||
showErrorToast: jest.fn(),
|
||||
showSuccessToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../common/DeleteWidget/DeleteWidgetModal', () => {
|
||||
return jest.fn().mockImplementation(() => <div>DeleteWidgetModal</div>);
|
||||
});
|
||||
|
||||
jest.mock('../common/error-with-placeholder/ErrorPlaceHolder', () => {
|
||||
return jest.fn().mockImplementation(() => <div>ErrorPlaceHolder</div>);
|
||||
});
|
||||
|
||||
jest.mock('../common/next-previous/NextPrevious', () => {
|
||||
return jest.fn().mockImplementation(() => <div>NextPrevious</div>);
|
||||
});
|
||||
|
||||
jest.mock('../header/PageHeader.component', () => {
|
||||
return jest.fn().mockImplementation(() => <div>PageHeader</div>);
|
||||
});
|
||||
|
||||
jest.mock('../Loader/Loader', () => {
|
||||
return jest.fn().mockImplementation(() => <div>Loader</div>);
|
||||
});
|
||||
|
||||
jest.mock('../common/searchbar/Searchbar', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation((prop) => (
|
||||
<input
|
||||
data-testid="search-input"
|
||||
type="text"
|
||||
onChange={(e) => prop.onSearch(e.target.value)}
|
||||
/>
|
||||
));
|
||||
});
|
||||
|
||||
const mockFunction = jest.fn();
|
||||
|
||||
const MOCK_PROPS_DATA = {
|
||||
data: MOCK_USER_DATA.data,
|
||||
paging: MOCK_USER_DATA.paging,
|
||||
searchTerm: '',
|
||||
currentPage: 1,
|
||||
isDataLoading: false,
|
||||
showDeletedUser: false,
|
||||
onSearch: mockFunction,
|
||||
onShowDeletedUserChange: mockFunction,
|
||||
onPagingChange: mockFunction,
|
||||
afterDeleteAction: mockFunction,
|
||||
isAdminPage: false,
|
||||
};
|
||||
|
||||
describe('Test UserListV1 component', () => {
|
||||
beforeEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('Should render component', async () => {
|
||||
await act(async () => {
|
||||
render(<UserListV1 {...MOCK_PROPS_DATA} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const userListComponent = await screen.findByTestId(
|
||||
'user-list-v1-component'
|
||||
);
|
||||
const pageHeader = await screen.findByText('PageHeader');
|
||||
|
||||
expect(userListComponent).toBeInTheDocument();
|
||||
expect(pageHeader).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render ErrorPlaceHolder', async () => {
|
||||
await act(async () => {
|
||||
render(<UserListV1 {...MOCK_PROPS_DATA} data={[]} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const emptyComponent = await screen.findByText('ErrorPlaceHolder');
|
||||
|
||||
expect(emptyComponent).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render Users table', async () => {
|
||||
await act(async () => {
|
||||
render(<UserListV1 {...MOCK_PROPS_DATA} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const userListComponent = await screen.findByTestId(
|
||||
'user-list-v1-component'
|
||||
);
|
||||
|
||||
expect(userListComponent).toBeInTheDocument();
|
||||
|
||||
const table = await screen.findByTestId('user-list-table');
|
||||
|
||||
expect(table).toBeInTheDocument();
|
||||
|
||||
const userName = await screen.findByText('label.username');
|
||||
const teams = await screen.findByText('label.team-plural');
|
||||
const role = await screen.findByText('label.role-plural');
|
||||
|
||||
expect(userName).toBeInTheDocument();
|
||||
expect(teams).toBeInTheDocument();
|
||||
expect(role).toBeInTheDocument();
|
||||
|
||||
const rows = await screen.findAllByRole('row');
|
||||
|
||||
expect(rows).toHaveLength(MOCK_PROPS_DATA.data.length + 1);
|
||||
});
|
||||
|
||||
it('Should not render data when bot is search', async () => {
|
||||
await act(async () => {
|
||||
render(<UserListV1 {...MOCK_PROPS_DATA} data={[]} searchTerm="bot" />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const userListComponent = await screen.findByTestId(
|
||||
'user-list-v1-component'
|
||||
);
|
||||
|
||||
expect(userListComponent).toBeInTheDocument();
|
||||
|
||||
const table = await screen.findByTestId('user-list-table');
|
||||
|
||||
const noDataTable = await screen.findByText('No data');
|
||||
|
||||
expect(table).toBeInTheDocument();
|
||||
expect(noDataTable).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -223,7 +223,10 @@ const UserListV1: FC<UserListV1Props> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Row className="user-listing" gutter={[16, 16]}>
|
||||
<Row
|
||||
className="user-listing"
|
||||
data-testid="user-list-v1-component"
|
||||
gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<PageHeader
|
||||
data={isAdminPage ? PAGE_HEADERS.ADMIN : PAGE_HEADERS.USERS}
|
||||
@ -275,6 +278,7 @@ const UserListV1: FC<UserListV1Props> = ({
|
||||
bordered
|
||||
className="user-list-table"
|
||||
columns={columns}
|
||||
data-testid="user-list-table"
|
||||
dataSource={data}
|
||||
loading={{
|
||||
spinning: isDataLoading,
|
||||
|
@ -138,7 +138,6 @@ describe('Test UserListPage component', () => {
|
||||
});
|
||||
|
||||
it('handleSearch function should work properly', async () => {
|
||||
mockParam.tab = GlobalSettingOptions.ADMINS;
|
||||
const userAPI = getUsers as jest.Mock;
|
||||
const searchAPI = searchData as jest.Mock;
|
||||
render(<UserListPageV1 />);
|
||||
@ -151,6 +150,17 @@ describe('Test UserListPage component', () => {
|
||||
fireEvent.change(searchBox, { target: { value: 'test' } });
|
||||
});
|
||||
|
||||
expect(searchAPI.mock.calls[0]).toEqual([
|
||||
'test',
|
||||
1,
|
||||
15,
|
||||
'isBot:false',
|
||||
'',
|
||||
'',
|
||||
'user_search_index',
|
||||
false,
|
||||
]);
|
||||
|
||||
await waitForElement(async () => {
|
||||
const userSearchTerm = new URLSearchParams(window.location.search).get(
|
||||
'user'
|
||||
@ -173,6 +183,43 @@ describe('Test UserListPage component', () => {
|
||||
expect(userlist).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handleSearch function should work properly for Admin', async () => {
|
||||
mockParam.tab = GlobalSettingOptions.ADMINS;
|
||||
const searchAPI = searchData as jest.Mock;
|
||||
|
||||
render(<UserListPageV1 />);
|
||||
|
||||
const searchBox = await screen.findByTestId('search-input');
|
||||
|
||||
expect(searchBox).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(searchBox, { target: { value: 'test' } });
|
||||
});
|
||||
|
||||
expect(searchAPI.mock.calls[0]).toEqual([
|
||||
'test',
|
||||
1,
|
||||
15,
|
||||
'isAdmin:true isBot:false',
|
||||
'',
|
||||
'',
|
||||
'user_search_index',
|
||||
false,
|
||||
]);
|
||||
|
||||
await waitForElement(async () => {
|
||||
const userSearchTerm = new URLSearchParams(window.location.search).get(
|
||||
'user'
|
||||
);
|
||||
|
||||
return userSearchTerm === 'test';
|
||||
});
|
||||
|
||||
expect(searchBox).toHaveValue('test');
|
||||
expect(searchAPI).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handleShowDeletedUserChange function should work properly', async () => {
|
||||
const userAPI = getUsers as jest.Mock;
|
||||
render(<UserListPageV1 />);
|
||||
|
@ -102,9 +102,9 @@ const UserListPageV1 = () => {
|
||||
isAdmin = false,
|
||||
isDeleted = false
|
||||
) => {
|
||||
let filters = '';
|
||||
let filters = 'isBot:false';
|
||||
if (isAdmin) {
|
||||
filters = '(isAdmin:true)';
|
||||
filters = 'isAdmin:true isBot:false';
|
||||
}
|
||||
|
||||
return new Promise<Array<User>>((resolve) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user