diff --git a/packages/volto/cypress/tests/core/controlpanels/groups-controlpanel.js b/packages/volto/cypress/tests/core/controlpanels/groups-controlpanel.js index 62512f1a0e..955229c828 100644 --- a/packages/volto/cypress/tests/core/controlpanels/groups-controlpanel.js +++ b/packages/volto/cypress/tests/core/controlpanels/groups-controlpanel.js @@ -52,6 +52,7 @@ describe('Groups Control Panel Test', () => { // select first group with name, delete it and search if its exists or not! cy.get('div[role="listbox"]').first().click(); + cy.get('div[role="option"]').should('be.visible'); cy.get('div[role="option"]').first().click(); cy.contains('Delete Group'); cy.get('button.ui.primary.button').should('have.text', 'OK').click(); diff --git a/packages/volto/cypress/tests/core/controlpanels/user-group-membership-control-panel.js b/packages/volto/cypress/tests/core/controlpanels/user-group-membership-control-panel.js index 44f2e76daa..bfe69297bc 100644 --- a/packages/volto/cypress/tests/core/controlpanels/user-group-membership-control-panel.js +++ b/packages/volto/cypress/tests/core/controlpanels/user-group-membership-control-panel.js @@ -41,41 +41,33 @@ describe('User Group Membership Control Panel test for NOT many users and many g cy.visit('/controlpanel/usergroupmembership'); cy.wait('@usergroup'); - cy.get('.usergroupmembership').then(($segmentUsergroupmembership) => { - if ($segmentUsergroupmembership.hasClass('upgrade-info')) { - // Panel not supported. - } else { - cy.get('#source-row-max div.checkbox_cooks input').check({ - force: true, - }); - cy.reload(); - cy.get('#source-row-max div.checkbox_cooks input').should('be.checked'); - } + cy.get('.usergroupmembership').then(() => { + cy.get('#source-row-max div.checkbox_cooks input').check({ + force: true, + }); + cy.reload(); + cy.get('#source-row-max div.checkbox_cooks input').should('be.checked'); }); }); it('I can search for a user and show his groups', () => { cy.visit('/controlpanel/usergroupmembership'); cy.wait('@usergroup'); - cy.get('.usergroupmembership').then(($segmentUsergroupmembership) => { - if ($segmentUsergroupmembership.hasClass('upgrade-info')) { - // Panel not supported. - } else { - // Show user - cy.get('#user-search-input').type('fröhlich'); - cy.contains('Max'); - - // Show membership of group "Administrators" - cy.get('input[id="group-search-input"]').type('Adm'); - cy.contains('Administrators'); - cy.get('.label-options').should('not.contain', 'teachers'); - - // Show also groups membersip of groups of users - cy.get('input[name="addJoinedGroups"]').check({ - force: true, - }); - cy.get('.label-options').contains('teachers'); - } + cy.get('.usergroupmembership').then(() => { + // Show user + cy.get('#user-search-input').type('fröhlich'); + cy.contains('Max'); + + // Show membership of group "Administrators" + cy.get('input[id="group-search-input"]').type('Adm'); + cy.contains('Administrators'); + cy.get('.label-options').should('not.contain', 'teachers'); + + // Show also groups membersip of groups of users + cy.get('input[name="addJoinedGroups"]').check({ + force: true, + }); + cy.get('.label-options').contains('teachers'); }); }); }); @@ -160,3 +152,27 @@ describe('User Group Membership Control Panel test for MANY users and MANY group }); }); }); + +// TODO Test should not fail with GET @users and @groups unauthorized for user with role "Site Administrator". +describe('User Group Membership Control Panel test for non-manager', () => { + beforeEach(() => { + init(); + cy.createUser({ + username: 'siteadmin', + fullname: 'Sven Siteadministrator', + roles: ['Site Administrator'], + }); + cy.autologin('siteadmin', 'password'); + }); + it('Non-manager is not allowed to edit managers', () => { + cy.visit('/controlpanel/usergroupmembership'); + cy.wait('@usergroup'); + + // Editing checkboxes for Administrators group are disabled. + cy.get('.usergroupmembership').then(() => { + cy.get('#source-row-max div.checkbox_Administrators input').should( + 'be.disabled', + ); + }); + }); +}); diff --git a/packages/volto/news/5244.feature b/packages/volto/news/5244.feature new file mode 100644 index 0000000000..5565451e9f --- /dev/null +++ b/packages/volto/news/5244.feature @@ -0,0 +1 @@ +Do not display options for Site Administrator to create, modify, or delete Manager users. @wesleybl diff --git a/packages/volto/news/5801.feature b/packages/volto/news/5801.feature new file mode 100644 index 0000000000..064038e2ca --- /dev/null +++ b/packages/volto/news/5801.feature @@ -0,0 +1 @@ +Add test for non-manager user editing group memberships. @ksuess \ No newline at end of file diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx index 95505c9030..fb4a4aac0e 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx @@ -10,7 +10,9 @@ import { listRoles, updateGroup, authenticatedRole, + getUser, } from '@plone/volto/actions'; +import jwtDecode from 'jwt-decode'; import { Icon, ModalForm, @@ -21,7 +23,12 @@ import { Error, } from '@plone/volto/components'; import { Link } from 'react-router-dom'; -import { Helmet, messages } from '@plone/volto/helpers'; +import { + Helmet, + messages, + isManager, + canAssignRole, +} from '@plone/volto/helpers'; import clearSVG from '@plone/volto/icons/clear.svg'; import addUserSvg from '@plone/volto/icons/add-user.svg'; import saveSVG from '@plone/volto/icons/save.svg'; @@ -75,6 +82,19 @@ class GroupsControlpanel extends Component { groupname: PropTypes.string, }), ).isRequired, + user: PropTypes.shape({ + '@id': PropTypes.string, + id: PropTypes.string, + description: PropTypes.string, + email: PropTypes.string, + fullname: PropTypes.string, + groups: PropTypes.object, + location: PropTypes.string, + portrait: PropTypes.string, + home_page: PropTypes.string, + roles: PropTypes.arrayOf(PropTypes.string), + username: PropTypes.string, + }).isRequired, }; /** @@ -118,6 +138,7 @@ class GroupsControlpanel extends Component { groupEntries: this.props.groups, }); } + await this.props.getUser(this.props.userId); }; /** * Component did mount @@ -375,6 +396,8 @@ class GroupsControlpanel extends Component { ? this.state.groupToDelete.id : ''; + const isUserManager = isManager(this.props.user); + return ( @@ -460,10 +483,9 @@ class GroupsControlpanel extends Component { messages.addGroupsFormRolesTitle, ), type: 'array', - choices: this.props.roles.map((role) => [ - role.id, - role.title, - ]), + choices: this.props.roles + .filter((role) => canAssignRole(isUserManager, role)) + .map((role) => [role.id, role.title]), noValueOption: false, description: '', }, @@ -553,6 +575,7 @@ class GroupsControlpanel extends Component { group={group} updateGroups={this.updateGroupRole} inheritedRole={this.state.authenticatedRole} + isUserManager={isUserManager} /> ))} @@ -640,6 +663,10 @@ export default compose( injectIntl, connect( (state, props) => ({ + user: state.users.user, + userId: state.userSession.token + ? jwtDecode(state.userSession.token).sub + : '', roles: state.roles.roles, groups: state.groups.groups, description: state.description, @@ -661,6 +688,7 @@ export default compose( createGroup, updateGroup, authenticatedRole, + getUser, }, dispatch, ), diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx index f6bf548d90..f520c37a07 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx @@ -2,6 +2,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; +import jwt from 'jsonwebtoken'; import GroupsControlpanel from './GroupsControlpanel'; @@ -12,6 +13,17 @@ jest.mock('react-portal', () => ({ describe('UsersControlpanel', () => { it('renders a user control component', () => { const store = mockStore({ + userSession: { + token: jwt.sign({ sub: 'john' }, 'secret'), + }, + users: { + users: [], + create: { loading: false }, + user: { + roles: ['Manager'], + '@id': 'admin', + }, + }, roles: { roles: [] }, groups: { groups: [], diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.jsx b/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.jsx index 816ad593da..f707003ed1 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.jsx @@ -9,6 +9,7 @@ import { Dropdown, Table, Checkbox } from 'semantic-ui-react'; import trashSVG from '@plone/volto/icons/delete.svg'; import ploneSVG from '@plone/volto/icons/plone.svg'; import { Icon } from '@plone/volto/components'; +import { canAssignRole } from '@plone/volto/helpers'; /** * UsersControlpanelGroups class. @@ -38,6 +39,7 @@ class RenderGroups extends Component { ).isRequired, inheritedRole: PropTypes.array, onDelete: PropTypes.func.isRequired, + isUserManager: PropTypes.bool.isRequired, }; /** @@ -69,6 +71,12 @@ class RenderGroups extends Component { isAuthGroup = (roleId) => { return this.props.inheritedRole.includes(roleId); }; + + canDeleteGroup() { + if (this.props.isUserManager) return true; + return !this.props.group.roles.includes('Manager'); + } + /** * Render method. * @method render @@ -98,22 +106,25 @@ class RenderGroups extends Component { } onChange={this.onChange} value={`${this.props.group.id}&role=${role.id}`} + disabled={!canAssignRole(this.props.isUserManager, role)} /> )} ))} - - - - - - - - + {this.canDeleteGroup() && ( + + + + + + + + + )} ); diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.test.jsx b/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.test.jsx index 81f917be36..69ba9887a3 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Groups/RenderGroups.test.jsx @@ -49,6 +49,27 @@ describe('UsersControlpanelGroups', () => { group={testGroups} roles={testRoles} onDelete={() => {}} + isUserManager={true} + /> + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + it('renders a UsersControlpanelGroups component with no Manager user', () => { + const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, + }); + const component = renderer.create( + + {}} + isUserManager={false} /> , ); diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/RenderGroups.test.jsx.snap b/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/RenderGroups.test.jsx.snap index 80e8c78c57..bb19f13b4d 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/RenderGroups.test.jsx.snap +++ b/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/RenderGroups.test.jsx.snap @@ -22,6 +22,7 @@ exports[`UsersControlpanelGroups renders a UsersControlpanelGroups component 1`] `; + +exports[`UsersControlpanelGroups renders a UsersControlpanelGroups component with no Manager user 1`] = ` + + + Administrators + + +
+ +
+ + +
+ +
+ + +
+ +
+ + + +`; diff --git a/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.jsx b/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.jsx index 82cfa252e3..ec50363eac 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.jsx @@ -13,7 +13,7 @@ import { updateUser } from '@plone/volto/actions'; import ploneSVG from '@plone/volto/icons/plone.svg'; import { compose } from 'redux'; import { connect } from 'react-redux'; -import { messages } from '@plone/volto/helpers'; +import { messages, canAssignRole } from '@plone/volto/helpers'; import { toast } from 'react-toastify'; /** @@ -39,6 +39,7 @@ class RenderUsers extends Component { }), ).isRequired, onDelete: PropTypes.func.isRequired, + isUserManager: PropTypes.bool.isRequired, }; /** @@ -110,6 +111,11 @@ class RenderUsers extends Component { this.setState({ user: { ...formData } }); } + canDeleteUser() { + if (this.props.isUserManager) return true; + return !this.props.user.roles.includes('Manager'); + } + /** * Render method. * @method render @@ -139,35 +145,38 @@ class RenderUsers extends Component { checked={this.props.user.roles.includes(role.id)} onChange={this.onChange} value={`${this.props.user.id}&role=${role.id}`} + disabled={!canAssignRole(this.props.isUserManager, role)} /> )} ))} - - - {this.props.userschema && ( + {this.canDeleteUser() && ( + + + {this.props.userschema && ( + { + this.onClickEdit({ formData: this.props.user }); + }} + value={this.props.user['@id']} + > + + + + )} { - this.onClickEdit({ formData: this.props.user }); - }} + id="delete-user-button" + onClick={this.props.onDelete} value={this.props.user['@id']} > - - + + - )} - - - - - - + + + )} {Object.keys(this.state.user).length > 0 && this.props.userschema.loaded && ( diff --git a/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.test.jsx b/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.test.jsx index e2be0df42c..4653d6281a 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/RenderUsers.test.jsx @@ -47,7 +47,33 @@ describe('UsersControlpanelUser', () => { }); const component = renderer.create( - {}} /> + {}} + isUserManager={true} + /> + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + + it('renders a UsersControlpanelUser component with options disabled if not allowed', () => { + const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, + }); + const component = renderer.create( + + {}} + isUserManager={false} + /> , ); const json = component.toJSON(); diff --git a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx deleted file mode 100644 index 2d9a74030d..0000000000 --- a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; -import configureStore from 'redux-mock-store'; -import { Provider } from 'react-intl-redux'; -import { MemoryRouter } from 'react-router-dom'; - -import UserGroupMembershipControlPanel from './UserGroupMembershipControlPanel'; - -const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); -describe('UserGroupMembershipControlPanel', () => { - it('renders a user group membership control component', () => { - const store = mockStore({ - controlpanels: { - controlpanel: { - data: { - many_users: false, - many_groups: false, - }, - }, - }, - groups: { - groups: [ - { - id: 'bern', - title: 'Group Bern', - }, - ], - filter_groups: [ - { - id: 'bern', - title: 'Group Bern', - }, - ], - }, - users: { - users: [ - { - id: 'bob-dabolina', - fullname: 'Bob Dabolina', - '@id': 'http://localhost:8080/Plone/people/bob-dabolina', - }, - ], - }, - intl: { - locale: 'en', - messages: {}, - }, - }); - const component = renderer.create( - - - - - , - ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); - }); -}); diff --git a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx index 7c52c347f2..93fb01ae78 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx @@ -1,17 +1,18 @@ import React, { useEffect, useState } from 'react'; import { cloneDeep, uniqBy } from 'lodash'; import { useIntl } from 'react-intl'; -import { useSelector, useDispatch } from 'react-redux'; +import { useSelector, useDispatch, shallowEqual } from 'react-redux'; +import jwtDecode from 'jwt-decode'; import { toast } from 'react-toastify'; import { Button, Checkbox } from 'semantic-ui-react'; -import { messages } from '@plone/volto/helpers'; -import { listGroups } from '@plone/volto/actions'; +import { messages, isManager, canAssingGroup } from '@plone/volto/helpers'; +import { listGroups, getUser } from '@plone/volto/actions'; import { Icon, Toast } from '@plone/volto/components'; import { updateGroup, listUsers } from '@plone/volto/actions'; import down_key from '@plone/volto/icons/down-key.svg'; -const ListingTemplate = ({ +const UserGroupMembershipListing = ({ query_user, // Show users on y-axis that match query_group, // Show groups on y-axis that match groups_filter, // show members of these groups @@ -25,6 +26,16 @@ const ListingTemplate = ({ const pageSize = 25; const [userLimit, setUserLimit] = useState(pageSize); + const token = useSelector((state) => state.userSession.token, shallowEqual); + const user = useSelector((state) => state.users.user); + const userId = token ? jwtDecode(token).sub : ''; + + useEffect(() => { + dispatch(getUser(userId)); + }, [dispatch, userId]); + + const isUserManager = isManager(user); + // y axis let items = useSelector((state) => state.users.users); let show_users = @@ -51,12 +62,17 @@ const ListingTemplate = ({ // x axis let groups = useSelector((state) => state.groups.groups); + + const getRoles = (group_id) => { + return groups.find((group) => group.id === group_id)?.roles || []; + }; + let show_matrix_options = !many_groups || (many_groups && query_group.length > 1) || groups_filter.length > 0 || add_joined_groups; - let matrix_options; // list of Objects (value, label) + let matrix_options; // list of Objects (value, label, roles) if (show_matrix_options) { matrix_options = !many_groups || (many_groups && query_group.length > 1) @@ -90,6 +106,10 @@ const ListingTemplate = ({ } return 0; }); + matrix_options = matrix_options.map((matrix_option) => ({ + ...matrix_option, + roles: getRoles(matrix_option.value), + })); } else { matrix_options = []; } @@ -126,7 +146,7 @@ const ListingTemplate = ({ }, }), ) - .then((resp) => { + .then(() => { singleClick && dispatch( listUsers({ @@ -209,13 +229,14 @@ const ListingTemplate = ({ + onChange={(_event, { checked }) => onSelectAllHandler( matrix_option.value, items.map((el) => el.id), checked, ) } + disabled={!canAssingGroup(isUserManager, matrix_option)} />
))} @@ -251,13 +272,14 @@ const ListingTemplate = ({ checked={item.groups?.items ?.map((el) => el.id) .includes(matrix_option.value)} - onChange={(event, { checked }) => { + onChange={(_event, { checked }) => { onSelectOptionHandler( { y: matrix_option.value, x: item.id }, checked, true, ); }} + disabled={!canAssingGroup(isUserManager, matrix_option)} /> ))} @@ -292,4 +314,4 @@ const ListingTemplate = ({ ); }; -export default ListingTemplate; +export default UserGroupMembershipListing; diff --git a/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx b/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx index a8f8e6687b..a961ea260e 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx @@ -12,7 +12,9 @@ import { updateUser, updateGroup, getUserSchema, + getUser, } from '@plone/volto/actions'; +import jwtDecode from 'jwt-decode'; import { Icon, ModalForm, @@ -23,7 +25,12 @@ import { Error, } from '@plone/volto/components'; import { Link } from 'react-router-dom'; -import { Helmet, messages } from '@plone/volto/helpers'; +import { + Helmet, + messages, + isManager, + canAssingGroup, +} from '@plone/volto/helpers'; import clearSVG from '@plone/volto/icons/clear.svg'; import addUserSvg from '@plone/volto/icons/add-user.svg'; import saveSVG from '@plone/volto/icons/save.svg'; @@ -77,6 +84,19 @@ class UsersControlpanel extends Component { roles: PropTypes.arrayOf(PropTypes.string), }), ).isRequired, + user: PropTypes.shape({ + '@id': PropTypes.string, + id: PropTypes.string, + description: PropTypes.string, + email: PropTypes.string, + fullname: PropTypes.string, + groups: PropTypes.object, + location: PropTypes.string, + portrait: PropTypes.string, + home_page: PropTypes.string, + roles: PropTypes.arrayOf(PropTypes.string), + username: PropTypes.string, + }).isRequired, }; /** @@ -124,6 +144,7 @@ class UsersControlpanel extends Component { }); } await this.props.getUserSchema(); + await this.props.getUser(this.props.userId); }; // Because username field needs to be disabled if email login is enabled! @@ -406,6 +427,20 @@ class UsersControlpanel extends Component { } } + /** + * Filters the roles a user can assign when adding a user. + * @method canAssignAdd + * @returns {arry} + */ + canAssignAdd(isManager) { + if (isManager) return this.props.roles; + return this.props.user?.roles + ? this.props.roles.filter((role) => + this.props.user.roles.includes(role.id), + ) + : []; + } + /** * Render method. * @method render @@ -426,7 +461,9 @@ class UsersControlpanel extends Component { // of the userschema is changed and it is used like that through // the lifecycle of the application let adduserschema = {}; + let isUserManager = false; if (this.props?.userschema?.loaded) { + isUserManager = isManager(this.props.user); adduserschema = JSON.parse( JSON.stringify(this.props?.userschema?.userschema), ); @@ -454,13 +491,18 @@ class UsersControlpanel extends Component { adduserschema.properties['roles'] = { title: this.props.intl.formatMessage(messages.addUserFormRolesTitle), type: 'array', - choices: this.props.roles.map((role) => [role.id, role.title]), + choices: this.canAssignAdd(isUserManager).map((role) => [ + role.id, + role.title, + ]), noValueOption: false, }; adduserschema.properties['groups'] = { title: this.props.intl.formatMessage(messages.addUserGroupNameTitle), type: 'array', - choices: this.props.groups.map((group) => [group.id, group.id]), + choices: this.props.groups + .filter((group) => canAssingGroup(isUserManager, group)) + .map((group) => [group.id, group.id]), noValueOption: false, }; if ( @@ -598,6 +640,7 @@ class UsersControlpanel extends Component { inheritedRole={this.props.inheritedRole} userschema={this.props.userschema} listUsers={this.props.listUsers} + isUserManager={isUserManager} /> ))} @@ -686,6 +729,10 @@ export default compose( (state, props) => ({ roles: state.roles.roles, users: state.users.users, + user: state.users.user, + userId: state.userSession.token + ? jwtDecode(state.userSession.token).sub + : '', groups: state.groups.groups, many_users: state.controlpanels?.controlpanel?.data?.many_users, many_groups: state.controlpanels?.controlpanel?.data?.many_groups, @@ -710,6 +757,7 @@ export default compose( updateUser, updateGroup, getUserSchema, + getUser, }, dispatch, ), diff --git a/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx b/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx index 49286f9c15..3a2fecc71c 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx @@ -2,6 +2,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; +import jwt from 'jsonwebtoken'; import UsersControlpanel from './UsersControlpanel'; @@ -12,10 +13,17 @@ jest.mock('react-portal', () => ({ describe('UsersControlpanel', () => { it('renders a user control component', () => { const store = mockStore({ + userSession: { + token: jwt.sign({ sub: 'john' }, 'secret'), + }, roles: { roles: [] }, users: { users: [], create: { loading: false }, + user: { + roles: ['Manager'], + '@id': 'admin', + }, }, groups: { groups: [], diff --git a/packages/volto/src/components/manage/Controlpanels/Users/__snapshots__/RenderUsers.test.jsx.snap b/packages/volto/src/components/manage/Controlpanels/Users/__snapshots__/RenderUsers.test.jsx.snap index 150057097e..ebdde31d51 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/__snapshots__/RenderUsers.test.jsx.snap +++ b/packages/volto/src/components/manage/Controlpanels/Users/__snapshots__/RenderUsers.test.jsx.snap @@ -26,6 +26,7 @@ exports[`UsersControlpanelUser renders a UsersControlpanelUser component 1`] = ` `; + +exports[`UsersControlpanelUser renders a UsersControlpanelUser component with options disabled if not allowed 1`] = ` + + + Test User + + ( + testuser + ) + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+