Merge pull request #16343 from strapi/fix/audit-logs-users-permissions

This commit is contained in:
markkaylor 2023-04-12 18:22:58 +02:00 committed by GitHub
commit bdb92a93a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 53 deletions

View File

@ -2,7 +2,7 @@ import { useQuery } from 'react-query';
import { useNotification, useFetchClient } from '@strapi/helper-plugin';
import { useLocation } from 'react-router-dom';
const useAuditLogsData = ({ canRead }) => {
const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
const { get } = useFetchClient();
const { search } = useLocation();
const toggleNotification = useNotification();
@ -21,7 +21,6 @@ const useAuditLogsData = ({ canRead }) => {
};
const queryOptions = {
enabled: canRead,
keepPreviousData: true,
retry: false,
staleTime: 1000 * 20, // 20 seconds
@ -32,10 +31,14 @@ const useAuditLogsData = ({ canRead }) => {
data: auditLogs,
isLoading,
isError: isAuditLogsError,
} = useQuery(['auditLogs', search], fetchAuditLogsPage, queryOptions);
} = useQuery(['auditLogs', search], fetchAuditLogsPage, {
...queryOptions,
enabled: canReadAuditLogs,
});
const { data: users, isError: isUsersError } = useQuery(['auditLogsUsers'], fetchAllUsers, {
...queryOptions,
enabled: canReadUsers,
staleTime: 2 * (1000 * 60), // 2 minutes
});

View File

@ -25,17 +25,27 @@ import Filters from '../../../../../../../admin/src/pages/SettingsPage/component
import getDisplayedFilters from './utils/getDisplayedFilters';
import useAuditLogsData from './hooks/useAuditLogsData';
const auditLogsPermissions = {
...adminPermissions.settings.auditLogs,
readUsers: adminPermissions.settings.users.read,
};
const ListView = () => {
const { formatMessage } = useIntl();
const {
allowedActions: { canRead },
} = useRBAC(adminPermissions.settings.auditLogs);
allowedActions: { canRead: canReadAuditLogs, canReadUsers },
} = useRBAC(auditLogsPermissions);
const [{ query }, setQuery] = useQueryParams();
const { auditLogs, users, isLoading, hasError } = useAuditLogsData({ canRead });
const { auditLogs, users, isLoading, hasError } = useAuditLogsData({
canReadAuditLogs,
canReadUsers,
});
useFocusWhenNavigate();
const displayedFilters = getDisplayedFilters({ formatMessage, users });
const displayedFilters = getDisplayedFilters({ formatMessage, users, canReadUsers });
const title = formatMessage({
id: 'global.auditLogs',
@ -73,7 +83,7 @@ const ListView = () => {
})}
/>
<ActionLayout startActions={<Filters displayedFilters={displayedFilters} />} />
<ContentLayout canRead={canRead}>
<ContentLayout canRead={canReadAuditLogs}>
<DynamicTable
contentType="Audit logs"
headers={headers}

View File

@ -0,0 +1,42 @@
import getDisplayedFilters from '../utils/getDisplayedFilters';
const mockUsers = {
results: [
{
id: 1,
firstname: 'test',
lastname: 'tester',
username: null,
email: 'test@test.com',
},
{
id: 2,
firstname: 'test2',
lastname: 'tester2',
username: null,
email: 'test2@test.com',
},
],
};
describe('Audit Logs getDisplayedFilters', () => {
it('should return all filters when canReadUsers is true', () => {
const filters = getDisplayedFilters({
users: mockUsers,
formatMessage: jest.fn(({ defaultMessage }) => defaultMessage),
canReadUsers: true,
});
const filterNames = filters.map((filter) => filter.name);
expect(filterNames).toEqual(['action', 'date', 'user']);
});
it('should not return user filter when canReadUsers is false', () => {
const filters = getDisplayedFilters({
users: mockUsers,
formatMessage: jest.fn(({ defaultMessage }) => defaultMessage),
canReadUsers: false,
});
const filterNames = filters.map((filter) => filter.name);
expect(filterNames).toEqual(['action', 'date']);
});
});

View File

@ -12,27 +12,7 @@ const customOperators = [
},
];
const getDisplayedFilters = ({ formatMessage, users }) => {
const getDisplaynameFromUser = (user) => {
if (user.username) {
return user.username;
}
if (user.firstname && user.lastname) {
return formatMessage(
{
id: 'Settings.permissions.auditLogs.user.fullname',
defaultMessage: '{firstname} {lastname}',
},
{
firstname: user.firstname,
lastname: user.lastname,
}
);
}
return user.email;
};
const getDisplayedFilters = ({ formatMessage, users, canReadUsers }) => {
const actionOptions = Object.keys(actionTypes).map((action) => {
return {
label: formatMessage(
@ -46,17 +26,7 @@ const getDisplayedFilters = ({ formatMessage, users }) => {
};
});
const userOptions =
users &&
users.results.map((user) => {
return {
label: getDisplaynameFromUser(user),
// Combobox expects a string value
customValue: user.id.toString(),
};
});
return [
const filters = [
{
name: 'action',
metadatas: {
@ -80,20 +50,57 @@ const getDisplayedFilters = ({ formatMessage, users }) => {
},
fieldSchema: { type: 'datetime' },
},
{
name: 'user',
metadatas: {
customOperators,
label: formatMessage({
id: 'Settings.permissions.auditLogs.user',
defaultMessage: 'User',
}),
options: userOptions,
customInput: ComboboxFilter,
},
fieldSchema: { type: 'relation', mainField: { name: 'id' } },
},
];
if (canReadUsers && users) {
const getDisplayNameFromUser = (user) => {
if (user.username) {
return user.username;
}
if (user.firstname && user.lastname) {
return formatMessage(
{
id: 'Settings.permissions.auditLogs.user.fullname',
defaultMessage: '{firstname} {lastname}',
},
{
firstname: user.firstname,
lastname: user.lastname,
}
);
}
return user.email;
};
const userOptions = users.results.map((user) => {
return {
label: getDisplayNameFromUser(user),
// Combobox expects a string value
customValue: user.id.toString(),
};
});
return [
...filters,
{
name: 'user',
metadatas: {
customOperators,
label: formatMessage({
id: 'Settings.permissions.auditLogs.user',
defaultMessage: 'User',
}),
options: userOptions,
customInput: ComboboxFilter,
},
fieldSchema: { type: 'relation', mainField: { name: 'id' } },
},
];
}
return filters;
};
export default getDisplayedFilters;