diff --git a/packages/strapi-admin/admin/src/utils/fakePermissionsData.js b/packages/strapi-admin/admin/src/utils/fakePermissionsData.js index 888d82e5cb..700bd9bc0a 100644 --- a/packages/strapi-admin/admin/src/utils/fakePermissionsData.js +++ b/packages/strapi-admin/admin/src/utils/fakePermissionsData.js @@ -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 // { diff --git a/packages/strapi-helper-plugin/lib/src/components/WithPagePermissions/index.js b/packages/strapi-helper-plugin/lib/src/components/WithPagePermissions/index.js new file mode 100644 index 0000000000..d7bf7e828f --- /dev/null +++ b/packages/strapi-helper-plugin/lib/src/components/WithPagePermissions/index.js @@ -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 ; + } + + if (!state.canAccess) { + return ; + } + + return children; +}; + +WithPagePermissions.defaultProps = { + permissions: [], +}; + +WithPagePermissions.propTypes = { + children: PropTypes.node.isRequired, + permissions: PropTypes.array, +}; + +export default WithPagePermissions; diff --git a/packages/strapi-helper-plugin/lib/src/components/WithPermissions/index.js b/packages/strapi-helper-plugin/lib/src/components/WithPermissions/index.js new file mode 100644 index 0000000000..acaf549b83 --- /dev/null +++ b/packages/strapi-helper-plugin/lib/src/components/WithPermissions/index.js @@ -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; diff --git a/packages/strapi-helper-plugin/lib/src/hooks/useUser.js b/packages/strapi-helper-plugin/lib/src/hooks/useUser.js new file mode 100644 index 0000000000..5bcc15fcda --- /dev/null +++ b/packages/strapi-helper-plugin/lib/src/hooks/useUser.js @@ -0,0 +1,12 @@ +/** + * + * useUser + * + */ + +import { useContext } from 'react'; +import UserContext from '../contexts/UserContext'; + +const useUser = () => useContext(UserContext); + +export default useUser; diff --git a/packages/strapi-helper-plugin/lib/src/index.js b/packages/strapi-helper-plugin/lib/src/index.js index e7a09ae632..07321aa6d6 100644 --- a/packages/strapi-helper-plugin/lib/src/index.js +++ b/packages/strapi-helper-plugin/lib/src/index.js @@ -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'; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js index a338688a42..ae09ff88e9 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js @@ -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 ( -