Init permissions check for the general links

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2020-06-08 13:15:01 +02:00 committed by Alexandre Bodin
parent 30d8d08cc4
commit 372951327d
6 changed files with 225 additions and 103 deletions

View File

@ -19,9 +19,11 @@ import {
GlobalContextProvider,
LoadingIndicatorPage,
OverlayBlocker,
UserProvider,
} from 'strapi-helper-plugin';
import TestEE from 'ee_else_ce/containers/TestEE';
import { SETTINGS_BASE_URL, SHOW_TUTORIALS } from '../../config';
import { fakePermissionsData } from '../../utils';
import Header from '../../components/Header/index';
import NavTopRightWrapper from '../../components/NavTopRightWrapper';
@ -176,52 +178,54 @@ export class Admin extends React.Component {
settingsBaseURL={SETTINGS_BASE_URL || '/settings'}
updatePlugin={updatePlugin}
>
<Wrapper>
<LeftMenu version={strapiVersion} plugins={plugins} />
<NavTopRightWrapper>
{/* Injection zone not ready yet */}
<Logout />
<LocaleToggle isLogged />
</NavTopRightWrapper>
<div className="adminPageRightWrapper">
<Header />
<Content>
<Switch>
<Route path="/" render={props => this.renderRoute(props, HomePage)} exact />
<Route path="/me" component={ProfilePage} />
{/* TODO remove this Route it is just made for the test */}
<Route path="/test" component={TestEE} />
<Route path="/plugins/:pluginId" render={this.renderPluginDispatcher} />
<Route
path="/list-plugins"
render={props => this.renderRoute(props, InstalledPluginsPage)}
exact
/>
<Route
path="/marketplace"
render={props => this.renderRoute(props, MarketplacePage)}
/>
<Route
path={`${SETTINGS_BASE_URL || '/settings'}/:settingId`}
render={props => this.renderRoute(props, SettingsPage)}
/>
<Route
path={SETTINGS_BASE_URL || '/settings'}
render={props => this.renderRoute(props, SettingsPage)}
exact
/>
<Route key="7" path="" component={NotFoundPage} />
<Route key="8" path="404" component={NotFoundPage} />
</Switch>
</Content>
</div>
<OverlayBlocker
key="overlayBlocker"
isOpen={blockApp && showGlobalAppBlocker}
{...overlayBlockerData}
/>
{SHOW_TUTORIALS && <OnboardingVideos />}
</Wrapper>
<UserProvider value={fakePermissionsData.user2}>
<Wrapper>
<LeftMenu version={strapiVersion} plugins={plugins} />
<NavTopRightWrapper>
{/* Injection zone not ready yet */}
<Logout />
<LocaleToggle isLogged />
</NavTopRightWrapper>
<div className="adminPageRightWrapper">
<Header />
<Content>
<Switch>
<Route path="/" render={props => this.renderRoute(props, HomePage)} exact />
<Route path="/me" component={ProfilePage} />
{/* TODO remove this Route it is just made for the test */}
<Route path="/test" component={TestEE} />
<Route path="/plugins/:pluginId" render={this.renderPluginDispatcher} />
<Route
path="/list-plugins"
render={props => this.renderRoute(props, InstalledPluginsPage)}
exact
/>
<Route
path="/marketplace"
render={props => this.renderRoute(props, MarketplacePage)}
/>
<Route
path={`${SETTINGS_BASE_URL || '/settings'}/:settingId`}
render={props => this.renderRoute(props, SettingsPage)}
/>
<Route
path={SETTINGS_BASE_URL || '/settings'}
render={props => this.renderRoute(props, SettingsPage)}
exact
/>
<Route key="7" path="" component={NotFoundPage} />
<Route key="8" path="404" component={NotFoundPage} />
</Switch>
</Content>
</div>
<OverlayBlocker
key="overlayBlocker"
isOpen={blockApp && showGlobalAppBlocker}
{...overlayBlockerData}
/>
{SHOW_TUTORIALS && <OnboardingVideos />}
</Wrapper>
</UserProvider>
</GlobalContextProvider>
);
}

View File

@ -4,9 +4,10 @@
*
*/
import React from 'react';
import React, { useContext, useEffect, useReducer } from 'react';
import PropTypes from 'prop-types';
import { useLocation } from 'react-router-dom';
import { UserContext } from 'strapi-helper-plugin';
import {
LeftMenuLinksSection,
LeftMenuFooter,
@ -14,40 +15,48 @@ import {
LeftMenuLinkContainer,
LinksContainer,
} from '../../components/LeftMenu';
import { SETTINGS_BASE_URL } from '../../config';
import { hasPermissions } from '../../utils';
import reducer, { initialState } from './reducer';
import Wrapper from './Wrapper';
const LeftMenu = ({ version, plugins }) => {
const location = useLocation();
const general = {
searchable: false,
name: 'general',
links: [
{
icon: 'list',
label: 'app.components.LeftMenuLinkContainer.listPlugins',
destination: '/list-plugins',
},
{
icon: 'shopping-basket',
label: 'app.components.LeftMenuLinkContainer.installNewPlugin',
destination: '/marketplace',
},
{
icon: 'cog',
label: 'app.components.LeftMenuLinkContainer.settings',
destination: SETTINGS_BASE_URL,
},
],
};
const permissions = useContext(UserContext);
const [{ generalSectionLinks }, dispatch] = useReducer(reducer, initialState);
const filteredLinks = generalSectionLinks.filter(link => link.isDisplayed);
useEffect(() => {
const getLinksPermissions = async () => {
generalSectionLinks.forEach(async (_, i) => {
const hasPermission = await hasPermissions(permissions, generalSectionLinks[i].permissions);
dispatch({
type: 'SET_LINK_PERMISSION',
index: i,
hasPermission,
});
});
};
getLinksPermissions();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<Wrapper>
<LeftMenuHeader />
<LinksContainer>
<LeftMenuLinkContainer plugins={plugins} />
<LeftMenuLinksSection section="general" {...general} location={location} />
{filteredLinks.length && (
<LeftMenuLinksSection
section="general"
name="general"
links={filteredLinks}
location={location}
searchable={false}
/>
)}
</LinksContainer>
<LeftMenuFooter key="footer" version={version} />
</Wrapper>

View File

@ -0,0 +1,71 @@
/* eslint-disable consistent-return */
import produce from 'immer';
import { set } from 'lodash';
import { SETTINGS_BASE_URL } from '../../config';
const initialState = {
generalSectionLinks: [
{
icon: 'list',
label: 'app.components.LeftMenuLinkContainer.listPlugins',
destination: '/list-plugins',
isDisplayed: false,
permissions: [
{ action: 'admin::marketplace.read', subject: null },
{ action: 'admin::marketplace.plugins.uninstall', subject: null },
],
},
{
icon: 'shopping-basket',
label: 'app.components.LeftMenuLinkContainer.installNewPlugin',
destination: '/marketplace',
isDisplayed: false,
permissions: [
{ action: 'admin::marketplace.read', subject: null },
{ action: 'admin::marketplace.plugins.install', subject: null },
],
},
{
icon: 'cog',
label: 'app.components.LeftMenuLinkContainer.settings',
isDisplayed: false,
destination: SETTINGS_BASE_URL,
permissions: [
// webhooks
{ action: 'admin::webhook.create', subject: null },
{ action: 'admin::webhook.read', subject: null },
{ action: 'admin::webhook.update', subject: null },
{ action: 'admin::webhook.delete', subject: null },
// users
{ action: 'admin::users.create', subject: null },
{ action: 'admin::users.read', subject: null },
{ action: 'admin::users.update', subject: null },
{ action: 'admin::users.delete', subject: null },
// roles
{ action: 'admin::roles.create', subject: null },
{ action: 'admin::roles.update', subject: null },
{ action: 'admin::roles.read', subject: null },
{ action: 'admin::roles.delete', subject: null },
// media library
{ action: 'plugins::upload.read', subject: null },
{ action: 'plugins::upload.assets.create', subject: null },
{ action: 'plugins::upload.assets.update', subject: null },
],
},
],
};
const reducer = (state, action) =>
produce(state, draftState => {
switch (action.type) {
case 'SET_LINK_PERMISSION': {
set(draftState, ['generalSectionLinks', action.index, 'isDisplayed'], action.hasPermission);
break;
}
default:
return draftState;
}
});
export default reducer;
export { initialState };

View File

@ -17,7 +17,7 @@ const data = {
action: 'admin::marketplace.plugins.uninstall',
subject: null,
fields: null,
conditions: [],
conditions: ['customCondition'],
},
// Admin webhooks
@ -222,24 +222,24 @@ const data = {
],
user2: [
// Admin marketplace
{
action: 'admin::marketplace.read',
subject: null,
fields: null,
conditions: [],
},
// {
// action: 'admin::marketplace.read',
// subject: null,
// fields: null,
// conditions: [],
// },
{
action: 'admin::marketplace.plugins.install',
subject: null,
fields: null,
conditions: [],
},
{
action: 'admin::marketplace.plugins.uninstall',
subject: null,
fields: null,
conditions: [],
conditions: ['some condition'],
},
// {
// action: 'admin::marketplace.plugins.uninstall',
// subject: null,
// fields: null,
// conditions: [],
// },
// Admin webhooks
{
@ -324,7 +324,7 @@ const data = {
action: 'plugins::content-type-builder.read',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
// Documentation plugin
@ -332,19 +332,19 @@ const data = {
// action: 'plugins::documentation.read',
// subject: null,
// fields: null,
// conditions: null,
// conditions:[],
// },
// {
// action: 'plugins::documentation.settings.update',
// subject: null,
// fields: null,
// conditions: null,
// conditions:[],
// },
// {
// action: 'plugins::documentation.settings.regenerate',
// subject: null,
// fields: null,
// conditions: null,
// conditions:[],
// },
// Upload plugin
@ -352,31 +352,31 @@ const data = {
action: 'plugins::upload.read',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::upload.assets.create',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::upload.assets.update',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::upload.assets.dowload',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::upload.assets.copy-link',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
// Users-permissions
@ -384,61 +384,61 @@ const data = {
action: 'plugins::users-permissions.roles.create',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.roles.read',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.roles.update',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.roles.delete',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.email-templates.read',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.email-templates.update',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.providers.read',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.providers.update',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.advanced-settings.read',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
{
action: 'plugins::users-permissions.advanced-settings.update',
subject: null,
fields: null,
conditions: null,
conditions: [],
},
],
};

View File

@ -0,0 +1,36 @@
import { transform } from 'lodash';
const hasPermissions = async (userPermissions, permissions) => {
const matchingPermissions = transform(
userPermissions,
(result, value) => {
const associatedPermission = permissions.find(
perm => perm.action === value.action && perm.subject === value.subject
);
if (associatedPermission) {
result.push(value);
}
},
[]
);
if (!permissions.length) {
return true;
}
if (matchingPermissions.some(perm => perm.conditions && perm.conditions.length)) {
console.log('should do something');
const hasPermission = await new Promise(resolve =>
setTimeout(() => {
resolve(true);
}, 2000)
);
return hasPermission;
}
return matchingPermissions.length > 0;
};
export default hasPermissions;

View File

@ -1,3 +1,5 @@
export { default as checkFormValidity } from './checkFormValidity';
export { default as formatAPIErrors } from './formatAPIErrors';
export { default as roleTabsLabel } from './roleTabsLabel';
export { default as fakePermissionsData } from './fakePermissionsData';
export { default as hasPermissions } from './hasPermissions';