Add permissions to ctb main compo

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2020-06-10 14:37:43 +02:00 committed by Alexandre Bodin
parent e73101b664
commit 7d9041ecc3
10 changed files with 186 additions and 52 deletions

View File

@ -331,6 +331,11 @@ const data = {
subject: 'application::address.address',
conditions: [],
},
{
action: 'plugins::content-manager.explorer.create',
subject: 'application::restaurant.restaurant',
conditions: [],
},
{
action: 'plugins::content-manager.explorer.create',
subject: 'application::homepage.homepage',
@ -338,12 +343,12 @@ const data = {
},
// Content type builder
{
action: 'plugins::content-type-builder.read',
subject: null,
fields: null,
conditions: [],
},
// {
// action: 'plugins::content-type-builder.read',
// subject: null,
// fields: null,
// conditions: [],
// },
// Documentation plugin
// {

View File

@ -0,0 +1,50 @@
import React, { useEffect, useState } from 'react';
import { Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import useUser from '../../hooks/useUser';
import hasPermissions from '../../utils/hasPermissions';
import LoadingIndicatorPage from '../LoadingIndicatorPage';
const WithPagePermissions = ({ permissions, children }) => {
const userPermissions = useUser();
const [state, setState] = useState({ isLoading: true, canAccess: false });
useEffect(() => {
const checkPermission = async () => {
try {
const canAccess = await hasPermissions(userPermissions, permissions);
setState({ isLoading: false, canAccess });
} catch (err) {
console.error(err);
strapi.notification.error('notification.error');
setState({ isLoading: false });
}
};
checkPermission();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (state.isLoading) {
return <LoadingIndicatorPage />;
}
if (!state.canAccess) {
return <Redirect to="/" />;
}
return children;
};
WithPagePermissions.defaultProps = {
permissions: [],
};
WithPagePermissions.propTypes = {
children: PropTypes.node.isRequired,
permissions: PropTypes.array,
};
export default WithPagePermissions;

View File

@ -0,0 +1,52 @@
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import useUser from '../../hooks/useUser';
import hasPermissions from '../../utils/hasPermissions';
// NOTE: this component is very similar to the WithPagePermissions
// except that it does not handle redirections nor loading state
const WithPermissions = ({ permissions, children }) => {
const userPermissions = useUser();
const [state, setState] = useState({ isLoading: true, canAccess: false });
useEffect(() => {
const checkPermission = async () => {
try {
const canAccess = await hasPermissions(userPermissions, permissions);
setState({ isLoading: false, canAccess });
} catch (err) {
console.error(err);
strapi.notification.error('notification.error');
setState({ isLoading: false });
}
};
checkPermission();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (state.isLoading) {
return null;
}
if (!state.canAccess) {
return null;
}
return children;
};
WithPermissions.defaultProps = {
permissions: [],
};
WithPermissions.propTypes = {
children: PropTypes.node.isRequired,
permissions: PropTypes.array,
};
export default WithPermissions;

View File

@ -0,0 +1,12 @@
/**
*
* useUser
*
*/
import { useContext } from 'react';
import UserContext from '../contexts/UserContext';
const useUser = () => useContext(UserContext);
export default useUser;

View File

@ -79,6 +79,8 @@ export { default as SelectNav } from './components/SelectNav';
export { default as SelectWrapper } from './components/SelectWrapper';
export { default as UserProvider } from './components/UserProvider';
export { default as ViewContainer } from './components/ViewContainer';
export { default as WithPagePermissions } from './components/WithPagePermissions';
export { default as WithPermissions } from './components/WithPermissions';
// Contexts
export { GlobalContext, GlobalContextProvider, useGlobalContext } from './contexts/GlobalContext';
@ -87,6 +89,7 @@ export { default as UserContext } from './contexts/UserContext';
// Hooks
export { default as useQuery } from './hooks/useQuery';
export { default as useStrapi } from './hooks/useStrapi';
export { default as useUser } from './hooks/useUser';
// Providers
export { default as StrapiProvider } from './providers/StrapiProvider';

View File

@ -6,11 +6,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useGlobalContext } from 'strapi-helper-plugin';
import { useGlobalContext, WithPermissions } from 'strapi-helper-plugin';
import { get } from 'lodash';
import { Button } from '@buffetjs/core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import getTrad from '../../utils/getTrad';
import pluginPermissions from '../../utils/permissions';
// Create link from content-type-builder to content-manager
function EditViewButton(props) {
@ -31,9 +32,7 @@ function EditViewButton(props) {
const category = get(modifiedData, 'category', '');
const suffixUrl =
type === 'content-types'
? props.getModelName()
: `${category}/${componentSlug}`;
type === 'content-types' ? props.getModelName() : `${category}/${componentSlug}`;
const handleClick = () => {
emitEvent('willEditEditLayout');
@ -49,22 +48,22 @@ function EditViewButton(props) {
}
return (
<Button
{...props}
onClick={handleClick}
icon={<FontAwesomeIcon icon="cog" style={{ fontSize: 13 }} />}
label={formatMessage({
id: getTrad(
`injected-components.content-manager.edit-settings-view.link.${type}`
),
})}
style={{
paddingLeft: 15,
paddingRight: 15,
outline: 0,
fontWeight: 600,
}}
/>
<WithPermissions permissions={pluginPermissions.main}>
<Button
{...props}
onClick={handleClick}
icon={<FontAwesomeIcon icon="cog" style={{ fontSize: 13 }} />}
label={formatMessage({
id: getTrad(`injected-components.content-manager.edit-settings-view.link.${type}`),
})}
style={{
paddingLeft: 15,
paddingRight: 15,
outline: 0,
fontWeight: 600,
}}
/>
</WithPermissions>
);
}

View File

@ -6,7 +6,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { LiLink, useGlobalContext } from 'strapi-helper-plugin';
import { LiLink, useGlobalContext, WithPermissions } from 'strapi-helper-plugin';
import pluginPermissions from '../../utils/permissions';
// Create link from content-type-builder to content-manager
function EditViewLink(props) {
@ -23,13 +24,15 @@ function EditViewLink(props) {
}
return (
<LiLink
{...props}
url={url}
onClick={() => {
emitEvent('willEditEditLayout');
}}
/>
<WithPermissions permissions={pluginPermissions.main}>
<LiLink
{...props}
url={url}
onClick={() => {
emitEvent('willEditEditLayout');
}}
/>
</WithPermissions>
);
}

View File

@ -6,8 +6,9 @@
import React, { Suspense, lazy } from 'react';
import { Switch, Route } from 'react-router-dom';
import { LoadingIndicatorPage } from 'strapi-helper-plugin';
import { LoadingIndicatorPage, WithPagePermissions } from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
import pluginPermissions from '../../utils/permissions';
import DataManagerProvider from '../DataManagerProvider';
import RecursivePath from '../RecursivePath';
import icons from './utils/icons.json';
@ -17,22 +18,21 @@ const ListView = lazy(() => import('../ListView'));
const App = () => {
return (
<Wrapper>
<DataManagerProvider allIcons={icons}>
<Suspense fallback={<LoadingIndicatorPage />}>
<Switch>
<Route
path={`/plugins/${pluginId}/content-types/:uid`}
component={ListView}
/>
<Route
path={`/plugins/${pluginId}/component-categories/:categoryUid`}
component={RecursivePath}
/>
</Switch>
</Suspense>
</DataManagerProvider>
</Wrapper>
<WithPagePermissions permissions={pluginPermissions.main}>
<Wrapper>
<DataManagerProvider allIcons={icons}>
<Suspense fallback={<LoadingIndicatorPage />}>
<Switch>
<Route path={`/plugins/${pluginId}/content-types/:uid`} component={ListView} />
<Route
path={`/plugins/${pluginId}/component-categories/:categoryUid`}
component={RecursivePath}
/>
</Switch>
</Suspense>
</DataManagerProvider>
</Wrapper>
</WithPagePermissions>
);
};

View File

@ -11,6 +11,7 @@ import App from './containers/App';
import Initializer from './containers/Initializer';
import Link from './InjectedComponents/ContentManager/EditViewLink';
import Button from './InjectedComponents/ContentManager/EditSettingViewButton';
import pluginPermissions from './utils/permissions';
import lifecycles from './lifecycles';
import trads from './translations';
import pluginId from './pluginId';
@ -64,7 +65,7 @@ export default strapi => {
defaultMessage: 'Content-Types Builder',
},
name,
permissions: [{ action: 'plugins::content-type-builder.read', subject: null }],
permissions: pluginPermissions.main,
},
],
},

View File

@ -0,0 +1,9 @@
const pluginPermissions = {
// This permission regards the main component (App) and is used to tell
// If the plugin link should be displayed in the menu
// And also if the plugin is accessible. This use case is found when a user types the url of the
// plugin directly in the browser
main: [{ action: 'plugins::content-type-builder.read', subject: null }],
};
export default pluginPermissions;