Skip to content

Commit

Permalink
Fix site setup access at toolbar by using @actions endpoint. (#6413)
Browse files Browse the repository at this point in the history
Signed-off-by: Faakhir30 <zahidfaakhir@gmail.com>
  • Loading branch information
Faakhir30 authored Oct 22, 2024
1 parent 3a98447 commit 27120d9
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/volto/news/6355.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix site setup access check by using `@actions` endpoint to validate permissions. @Faakhir30
14 changes: 7 additions & 7 deletions packages/volto/src/components/manage/Toolbar/PersonalTools.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
import { Icon } from '@plone/volto/components';
import { getUser } from '@plone/volto/actions';
import { Pluggable } from '@plone/volto/components/manage/Pluggable';
import {
expandToBackendURL,
getBaseUrl,
userHasRoles,
} from '@plone/volto/helpers';
import { expandToBackendURL, getBaseUrl } from '@plone/volto/helpers';
import logoutSVG from '@plone/volto/icons/log-out.svg';
import rightArrowSVG from '@plone/volto/icons/right-key.svg';
import backSVG from '@plone/volto/icons/back.svg';
Expand Down Expand Up @@ -50,7 +46,11 @@ const PersonalTools = (props) => {
const token = useSelector((state) => state.userSession.token, shallowEqual);
const user = useSelector((state) => state.users.user);
const userId = token ? jwtDecode(token).sub : '';

const siteSetupAction = useSelector((state) =>
state.actions?.actions?.user?.find(
(action) => action?.id === 'plone_setup',
),
);
useEffect(() => {
dispatch(getUser(userId));
}, [dispatch, userId]);
Expand Down Expand Up @@ -127,7 +127,7 @@ const PersonalTools = (props) => {
</button>
</li>

{userHasRoles(user, ['Site Administrator', 'Manager']) && (
{siteSetupAction && (
<li>
<Link to="/controlpanel">
<FormattedMessage id="Site Setup" defaultMessage="Site Setup" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ describe('Toolbar Personal Tools component', () => {
is_folderish: true,
},
},
actions: {
actions: {
user: [
{
id: 'plone_setup',
title: 'Site Setup',
},
],
},
},
intl: {
locale: 'en',
messages: {},
Expand Down Expand Up @@ -70,6 +80,16 @@ describe('Toolbar Personal Tools component', () => {
is_folderish: true,
},
},
actions: {
actions: {
user: [
{
id: 'plone_setup',
title: 'Site Setup',
},
],
},
},
intl: {
locale: 'en',
messages: {},
Expand Down Expand Up @@ -112,6 +132,57 @@ describe('Toolbar Personal Tools component', () => {
is_folderish: true,
},
},
actions: {
actions: {
user: [
{
id: 'plone_setup',
title: 'Site Setup',
},
],
},
},
intl: {
locale: 'en',
messages: {},
},
});
const component = renderer.create(
<Provider store={store}>
<PluggablesProvider>
<MemoryRouter>
<PersonalTools
loadComponent={() => {}}
theToolbar={{
current: { getBoundingClientRect: () => ({ width: '320' }) },
}}
/>
</MemoryRouter>
</PluggablesProvider>
</Provider>,
);
const json = component.toJSON();
expect(json).toMatchSnapshot();
});

it('renders an Toolbar Personal Tools component without Site Setup access', () => {
const store = mockStore({
users: {
user: {
fullname: 'regular_user',
email: 'user@plone.org',
roles: ['Member'],
},
},
userSession: {
token: jwt.sign({ sub: 'regular_user' }, 'secret'),
},
content: {
data: {
'@type': 'Folder',
is_folderish: true,
},
},
intl: {
locale: 'en',
messages: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,153 @@ exports[`Toolbar Personal Tools component renders an Toolbar Personal Tools comp
</div>
</div>
`;

exports[`Toolbar Personal Tools component renders an Toolbar Personal Tools component without Site Setup access 1`] = `
<div
className="personal-tools pastanaga-menu"
style={
Object {
"flex": "0 0 320px",
}
}
>
<header
className="header"
>
<button
className="back"
onClick={[Function]}
>
<svg
className="icon"
dangerouslySetInnerHTML={
Object {
"__html": "<title>Back</title>undefined",
}
}
onClick={null}
style={
Object {
"fill": "currentColor",
"height": "30px",
"width": "auto",
}
}
viewBox=""
xmlns=""
/>
</button>
<div
className="vertical divider"
/>
<h2>
regular_user
</h2>
<a
href="/logout"
id="toolbar-logout"
onClick={[Function]}
>
<svg
className="icon logout"
dangerouslySetInnerHTML={
Object {
"__html": "<title>Logout</title>undefined",
}
}
onClick={null}
style={
Object {
"fill": "currentColor",
"height": "30px",
"width": "auto",
}
}
viewBox=""
xmlns=""
/>
</a>
</header>
<div
className="avatar default"
>
<svg
className="icon"
dangerouslySetInnerHTML={
Object {
"__html": undefined,
}
}
onClick={null}
style={
Object {
"fill": "currentColor",
"height": "96px",
"width": "auto",
}
}
viewBox=""
xmlns=""
/>
</div>
<div
className="pastanaga-menu-list"
>
<ul>
<li>
<a
href="/personal-information"
id="Profile"
onClick={[Function]}
>
Profile
<svg
className="icon"
dangerouslySetInnerHTML={
Object {
"__html": undefined,
}
}
onClick={null}
style={
Object {
"fill": "currentColor",
"height": "24px",
"width": "auto",
}
}
viewBox=""
xmlns=""
/>
</a>
</li>
<li>
<button
aria-label="Preferences"
onClick={[Function]}
>
Preferences
<svg
className="icon"
dangerouslySetInnerHTML={
Object {
"__html": undefined,
}
}
onClick={null}
style={
Object {
"fill": "currentColor",
"height": "24px",
"width": "auto",
}
}
viewBox=""
xmlns=""
/>
</button>
</li>
</ul>
</div>
</div>
`;

0 comments on commit 27120d9

Please sign in to comment.