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 (
- }
- label={formatMessage({
- id: getTrad(
- `injected-components.content-manager.edit-settings-view.link.${type}`
- ),
- })}
- style={{
- paddingLeft: 15,
- paddingRight: 15,
- outline: 0,
- fontWeight: 600,
- }}
- />
+
+ }
+ label={formatMessage({
+ id: getTrad(`injected-components.content-manager.edit-settings-view.link.${type}`),
+ })}
+ style={{
+ paddingLeft: 15,
+ paddingRight: 15,
+ outline: 0,
+ fontWeight: 600,
+ }}
+ />
+
);
}
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditViewLink.js b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditViewLink.js
index e92d9d3103..0c52f1dd4e 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditViewLink.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditViewLink.js
@@ -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 (
- {
- emitEvent('willEditEditLayout');
- }}
- />
+
+ {
+ emitEvent('willEditEditLayout');
+ }}
+ />
+
);
}
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js
index cd19059e49..04c8232b67 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/App/index.js
@@ -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 (
-
-
- }>
-
-
-
-
-
-
-
+
+
+
+ }>
+
+
+
+
+
+
+
+
);
};
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/index.js b/packages/strapi-plugin-content-type-builder/admin/src/index.js
index bc70b6d1ed..1ab6010123 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/index.js
@@ -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,
},
],
},
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/utils/permissions.js b/packages/strapi-plugin-content-type-builder/admin/src/utils/permissions.js
new file mode 100644
index 0000000000..bc9af8d855
--- /dev/null
+++ b/packages/strapi-plugin-content-type-builder/admin/src/utils/permissions.js
@@ -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;