mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-03 19:36:20 +00:00 
			
		
		
		
	Merge branch 'features/i18n' of github.com:strapi/strapi into features/i18n
This commit is contained in:
		
						commit
						48c3817541
					
				@ -4,13 +4,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  GET_STRAPI_LATEST_RELEASE_SUCCEEDED,
 | 
			
		||||
  GET_USER_PERMISSIONS,
 | 
			
		||||
  GET_USER_PERMISSIONS_ERROR,
 | 
			
		||||
  GET_USER_PERMISSIONS_SUCCEEDED,
 | 
			
		||||
  SET_APP_ERROR,
 | 
			
		||||
} from './constants';
 | 
			
		||||
import { GET_STRAPI_LATEST_RELEASE_SUCCEEDED, SET_APP_ERROR } from './constants';
 | 
			
		||||
 | 
			
		||||
export function getStrapiLatestReleaseSucceeded(latestStrapiReleaseTag, shouldUpdateStrapi) {
 | 
			
		||||
  return {
 | 
			
		||||
@ -20,26 +14,6 @@ export function getStrapiLatestReleaseSucceeded(latestStrapiReleaseTag, shouldUp
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUserPermissions() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: GET_USER_PERMISSIONS,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUserPermissionsError(error) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: GET_USER_PERMISSIONS_ERROR,
 | 
			
		||||
    error,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUserPermissionsSucceeded(data) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: GET_USER_PERMISSIONS_SUCCEEDED,
 | 
			
		||||
    data,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setAppError() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: SET_APP_ERROR,
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,3 @@
 | 
			
		||||
export const SET_APP_ERROR = 'StrapiAdmin/Admin/SET_APP_ERROR';
 | 
			
		||||
export const GET_STRAPI_LATEST_RELEASE_SUCCEEDED =
 | 
			
		||||
  'StrapiAdmin/Admin/GET_STRAPI_LATEST_RELEASE_SUCCEEDED';
 | 
			
		||||
export const GET_USER_PERMISSIONS = 'StrapiAdmin/Admin/GET_USER_PERMISSIONS';
 | 
			
		||||
export const GET_USER_PERMISSIONS_ERROR = 'StrapiAdmin/Admin/GET_USER_PERMISSIONS_ERROR';
 | 
			
		||||
export const GET_USER_PERMISSIONS_SUCCEEDED = 'StrapiAdmin/Admin/GET_USER_PERMISSIONS_SUCCEEDED';
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,6 @@ import {
 | 
			
		||||
  GlobalContextProvider,
 | 
			
		||||
  LoadingIndicatorPage,
 | 
			
		||||
  OverlayBlocker,
 | 
			
		||||
  UserProvider,
 | 
			
		||||
  CheckPagePermissions,
 | 
			
		||||
  request,
 | 
			
		||||
} from 'strapi-helper-plugin';
 | 
			
		||||
@ -31,14 +30,14 @@ import Header from '../../components/Header/index';
 | 
			
		||||
import NavTopRightWrapper from '../../components/NavTopRightWrapper';
 | 
			
		||||
import LeftMenu from '../LeftMenu';
 | 
			
		||||
import InstalledPluginsPage from '../InstalledPluginsPage';
 | 
			
		||||
 | 
			
		||||
import HomePage from '../HomePage';
 | 
			
		||||
import MarketplacePage from '../MarketplacePage';
 | 
			
		||||
import NotFoundPage from '../NotFoundPage';
 | 
			
		||||
import OnboardingVideos from '../Onboarding';
 | 
			
		||||
import SettingsPage from '../SettingsPage';
 | 
			
		||||
import PermissionsManager from '../PermissionsManager';
 | 
			
		||||
import PluginDispatcher from '../PluginDispatcher';
 | 
			
		||||
import ProfilePage from '../ProfilePage';
 | 
			
		||||
import SettingsPage from '../SettingsPage';
 | 
			
		||||
import Logout from './Logout';
 | 
			
		||||
import {
 | 
			
		||||
  disableGlobalOverlayBlocker,
 | 
			
		||||
@ -47,13 +46,7 @@ import {
 | 
			
		||||
  updatePlugin,
 | 
			
		||||
} from '../App/actions';
 | 
			
		||||
import makeSelecApp from '../App/selectors';
 | 
			
		||||
import {
 | 
			
		||||
  getStrapiLatestReleaseSucceeded,
 | 
			
		||||
  getUserPermissions,
 | 
			
		||||
  getUserPermissionsError,
 | 
			
		||||
  getUserPermissionsSucceeded,
 | 
			
		||||
  setAppError,
 | 
			
		||||
} from './actions';
 | 
			
		||||
import { getStrapiLatestReleaseSucceeded, setAppError } from './actions';
 | 
			
		||||
import makeSelectAdmin from './selectors';
 | 
			
		||||
import Wrapper from './Wrapper';
 | 
			
		||||
import Content from './Content';
 | 
			
		||||
@ -165,24 +158,6 @@ export class Admin extends React.Component {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  fetchUserPermissions = async (resetState = false) => {
 | 
			
		||||
    const { getUserPermissions, getUserPermissionsError, getUserPermissionsSucceeded } = this.props;
 | 
			
		||||
 | 
			
		||||
    if (resetState) {
 | 
			
		||||
      // Show a loader
 | 
			
		||||
      getUserPermissions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await request('/admin/users/me/permissions', { method: 'GET' });
 | 
			
		||||
 | 
			
		||||
      getUserPermissionsSucceeded(data);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      getUserPermissionsError(err);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  hasApluginNotReady = props => {
 | 
			
		||||
    const {
 | 
			
		||||
      global: { plugins },
 | 
			
		||||
@ -194,7 +169,6 @@ export class Admin extends React.Component {
 | 
			
		||||
  initApp = async () => {
 | 
			
		||||
    await this.fetchAppInfo();
 | 
			
		||||
    await this.fetchStrapiLatestRelease();
 | 
			
		||||
    await this.fetchUserPermissions(true);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -233,7 +207,7 @@ export class Admin extends React.Component {
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const {
 | 
			
		||||
      admin: { isLoading, shouldUpdateStrapi, userPermissions },
 | 
			
		||||
      admin: { shouldUpdateStrapi },
 | 
			
		||||
      global: {
 | 
			
		||||
        autoReload,
 | 
			
		||||
        blockApp,
 | 
			
		||||
@ -259,29 +233,23 @@ export class Admin extends React.Component {
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Show a loader while permissions are being fetched
 | 
			
		||||
    if (isLoading) {
 | 
			
		||||
      return <LoadingIndicatorPage />;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <GlobalContextProvider
 | 
			
		||||
        autoReload={autoReload}
 | 
			
		||||
        emitEvent={this.emitEvent}
 | 
			
		||||
        currentEnvironment={currentEnvironment}
 | 
			
		||||
        currentLocale={locale}
 | 
			
		||||
        disableGlobalOverlayBlocker={disableGlobalOverlayBlocker}
 | 
			
		||||
        enableGlobalOverlayBlocker={enableGlobalOverlayBlocker}
 | 
			
		||||
        fetchUserPermissions={this.fetchUserPermissions}
 | 
			
		||||
        formatMessage={formatMessage}
 | 
			
		||||
        shouldUpdateStrapi={shouldUpdateStrapi}
 | 
			
		||||
        menu={this.menuRef.current}
 | 
			
		||||
        plugins={plugins}
 | 
			
		||||
        settingsBaseURL={SETTINGS_BASE_URL || '/settings'}
 | 
			
		||||
        strapiVersion={strapiVersion}
 | 
			
		||||
        updatePlugin={updatePlugin}
 | 
			
		||||
      >
 | 
			
		||||
        <UserProvider value={userPermissions}>
 | 
			
		||||
      <PermissionsManager>
 | 
			
		||||
        <GlobalContextProvider
 | 
			
		||||
          autoReload={autoReload}
 | 
			
		||||
          emitEvent={this.emitEvent}
 | 
			
		||||
          currentEnvironment={currentEnvironment}
 | 
			
		||||
          currentLocale={locale}
 | 
			
		||||
          disableGlobalOverlayBlocker={disableGlobalOverlayBlocker}
 | 
			
		||||
          enableGlobalOverlayBlocker={enableGlobalOverlayBlocker}
 | 
			
		||||
          formatMessage={formatMessage}
 | 
			
		||||
          shouldUpdateStrapi={shouldUpdateStrapi}
 | 
			
		||||
          menu={this.menuRef.current}
 | 
			
		||||
          plugins={plugins}
 | 
			
		||||
          settingsBaseURL={SETTINGS_BASE_URL || '/settings'}
 | 
			
		||||
          strapiVersion={strapiVersion}
 | 
			
		||||
          updatePlugin={updatePlugin}
 | 
			
		||||
        >
 | 
			
		||||
          <Wrapper>
 | 
			
		||||
            <LeftMenu
 | 
			
		||||
              shouldUpdateStrapi={shouldUpdateStrapi}
 | 
			
		||||
@ -327,8 +295,8 @@ export class Admin extends React.Component {
 | 
			
		||||
            />
 | 
			
		||||
            {SHOW_TUTORIALS && <OnboardingVideos />}
 | 
			
		||||
          </Wrapper>
 | 
			
		||||
        </UserProvider>
 | 
			
		||||
      </GlobalContextProvider>
 | 
			
		||||
        </GlobalContextProvider>
 | 
			
		||||
      </PermissionsManager>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -343,17 +311,12 @@ Admin.defaultProps = {
 | 
			
		||||
Admin.propTypes = {
 | 
			
		||||
  admin: PropTypes.shape({
 | 
			
		||||
    appError: PropTypes.bool,
 | 
			
		||||
    isLoading: PropTypes.bool,
 | 
			
		||||
    shouldUpdateStrapi: PropTypes.bool.isRequired,
 | 
			
		||||
    userPermissions: PropTypes.array,
 | 
			
		||||
  }).isRequired,
 | 
			
		||||
  disableGlobalOverlayBlocker: PropTypes.func.isRequired,
 | 
			
		||||
  enableGlobalOverlayBlocker: PropTypes.func.isRequired,
 | 
			
		||||
  getInfosDataSucceeded: PropTypes.func.isRequired,
 | 
			
		||||
  getStrapiLatestReleaseSucceeded: PropTypes.func.isRequired,
 | 
			
		||||
  getUserPermissions: PropTypes.func.isRequired,
 | 
			
		||||
  getUserPermissionsError: PropTypes.func.isRequired,
 | 
			
		||||
  getUserPermissionsSucceeded: PropTypes.func.isRequired,
 | 
			
		||||
  global: PropTypes.shape({
 | 
			
		||||
    autoReload: PropTypes.bool,
 | 
			
		||||
    blockApp: PropTypes.bool,
 | 
			
		||||
@ -385,9 +348,6 @@ export function mapDispatchToProps(dispatch) {
 | 
			
		||||
      enableGlobalOverlayBlocker,
 | 
			
		||||
      getInfosDataSucceeded,
 | 
			
		||||
      getStrapiLatestReleaseSucceeded,
 | 
			
		||||
      getUserPermissions,
 | 
			
		||||
      getUserPermissionsError,
 | 
			
		||||
      getUserPermissionsSucceeded,
 | 
			
		||||
      setAppError,
 | 
			
		||||
      updatePlugin,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@ -7,21 +7,13 @@
 | 
			
		||||
import produce from 'immer';
 | 
			
		||||
import packageJSON from '../../../../package.json';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  GET_STRAPI_LATEST_RELEASE_SUCCEEDED,
 | 
			
		||||
  GET_USER_PERMISSIONS,
 | 
			
		||||
  GET_USER_PERMISSIONS_ERROR,
 | 
			
		||||
  GET_USER_PERMISSIONS_SUCCEEDED,
 | 
			
		||||
  SET_APP_ERROR,
 | 
			
		||||
} from './constants';
 | 
			
		||||
import { GET_STRAPI_LATEST_RELEASE_SUCCEEDED, SET_APP_ERROR } from './constants';
 | 
			
		||||
 | 
			
		||||
const packageVersion = packageJSON.version;
 | 
			
		||||
const initialState = {
 | 
			
		||||
  appError: false,
 | 
			
		||||
  isLoading: true,
 | 
			
		||||
  latestStrapiReleaseTag: `v${packageVersion}`,
 | 
			
		||||
  shouldUpdateStrapi: false,
 | 
			
		||||
  userPermissions: [],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const reducer = (state = initialState, action) =>
 | 
			
		||||
@ -33,21 +25,7 @@ const reducer = (state = initialState, action) =>
 | 
			
		||||
        draftState.shouldUpdateStrapi = action.shouldUpdateStrapi;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case GET_USER_PERMISSIONS: {
 | 
			
		||||
        draftState.isLoading = true;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case GET_USER_PERMISSIONS_ERROR: {
 | 
			
		||||
        draftState.error = action.error;
 | 
			
		||||
        draftState.isLoading = false;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case GET_USER_PERMISSIONS_SUCCEEDED: {
 | 
			
		||||
        draftState.isLoading = false;
 | 
			
		||||
        draftState.userPermissions = action.data;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case SET_APP_ERROR: {
 | 
			
		||||
        draftState.appError = true;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,6 @@
 | 
			
		||||
import produce from 'immer';
 | 
			
		||||
import packageJSON from '../../../../../package.json';
 | 
			
		||||
import {
 | 
			
		||||
  setAppError,
 | 
			
		||||
  getUserPermissions,
 | 
			
		||||
  getUserPermissionsError,
 | 
			
		||||
  getUserPermissionsSucceeded,
 | 
			
		||||
  getStrapiLatestReleaseSucceeded,
 | 
			
		||||
} from '../actions';
 | 
			
		||||
import { setAppError, getStrapiLatestReleaseSucceeded } from '../actions';
 | 
			
		||||
import adminReducer from '../reducer';
 | 
			
		||||
 | 
			
		||||
describe('adminReducer', () => {
 | 
			
		||||
@ -15,9 +9,7 @@ describe('adminReducer', () => {
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    state = {
 | 
			
		||||
      appError: false,
 | 
			
		||||
      isLoading: true,
 | 
			
		||||
      latestStrapiReleaseTag: `v${packageJSON.version}`,
 | 
			
		||||
      userPermissions: [],
 | 
			
		||||
      shouldUpdateStrapi: false,
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
@ -44,32 +36,4 @@ describe('adminReducer', () => {
 | 
			
		||||
 | 
			
		||||
    expect(adminReducer(state, setAppError())).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle the getUserPermissions action correctly', () => {
 | 
			
		||||
    const expected = produce(state, draft => {
 | 
			
		||||
      draft.isLoading = true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(adminReducer(state, getUserPermissions())).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle the getUserPermissionsError action correctly', () => {
 | 
			
		||||
    const error = 'Error';
 | 
			
		||||
    const expected = produce(state, draft => {
 | 
			
		||||
      draft.isLoading = false;
 | 
			
		||||
      draft.error = error;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(adminReducer(state, getUserPermissionsError(error))).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle the getUserPermissionsSucceeded action correctly', () => {
 | 
			
		||||
    const data = ['permission 1', 'permission 2'];
 | 
			
		||||
    const expected = produce(state, draft => {
 | 
			
		||||
      draft.isLoading = false;
 | 
			
		||||
      draft.userPermissions = data;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(adminReducer(state, getUserPermissionsSucceeded(data))).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ import Wrapper from './Wrapper';
 | 
			
		||||
 | 
			
		||||
const LeftMenu = forwardRef(({ shouldUpdateStrapi, version, plugins }, ref) => {
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
  const permissions = useContext(UserContext);
 | 
			
		||||
  const { userPermissions: permissions } = useContext(UserContext);
 | 
			
		||||
  const { menu: settingsMenu } = useSettingsMenu(true);
 | 
			
		||||
 | 
			
		||||
  // TODO: this needs to be added to the settings API in the v4
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
import {
 | 
			
		||||
  GET_USER_PERMISSIONS,
 | 
			
		||||
  GET_USER_PERMISSIONS_SUCCEEDED,
 | 
			
		||||
  GET_USER_PERMISSIONS_ERROR,
 | 
			
		||||
} from './constants';
 | 
			
		||||
 | 
			
		||||
export function getUserPermissions() {
 | 
			
		||||
  return {
 | 
			
		||||
    type: GET_USER_PERMISSIONS,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUserPermissionsError(error) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: GET_USER_PERMISSIONS_ERROR,
 | 
			
		||||
    error,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getUserPermissionsSucceeded(data) {
 | 
			
		||||
  return {
 | 
			
		||||
    type: GET_USER_PERMISSIONS_SUCCEEDED,
 | 
			
		||||
    data,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,5 @@
 | 
			
		||||
export const GET_USER_PERMISSIONS = 'StrapiAdmin/PermissionsManager/GET_USER_PERMISSIONS';
 | 
			
		||||
export const GET_USER_PERMISSIONS_ERROR =
 | 
			
		||||
  'StrapiAdmin/PermissionsManager/GET_USER_PERMISSIONS_ERROR';
 | 
			
		||||
export const GET_USER_PERMISSIONS_SUCCEEDED =
 | 
			
		||||
  'StrapiAdmin/PermissionsManager/GET_USER_PERMISSIONS_SUCCEEDED';
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
import React, { useEffect } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { useSelector, useDispatch } from 'react-redux';
 | 
			
		||||
import { LoadingIndicatorPage, UserProvider, request } from 'strapi-helper-plugin';
 | 
			
		||||
import {
 | 
			
		||||
  getUserPermissions,
 | 
			
		||||
  getUserPermissionsError,
 | 
			
		||||
  getUserPermissionsSucceeded,
 | 
			
		||||
} from './actions';
 | 
			
		||||
 | 
			
		||||
const PermissionsManager = ({ children }) => {
 | 
			
		||||
  const { isLoading, userPermissions } = useSelector(state => state.get('permissionsManager'));
 | 
			
		||||
 | 
			
		||||
  const dispatch = useDispatch();
 | 
			
		||||
  const fetchUserPermissions = async (resetState = false) => {
 | 
			
		||||
    if (resetState) {
 | 
			
		||||
      // Show a loader
 | 
			
		||||
      dispatch(getUserPermissions());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await request('/admin/users/me/permissions', { method: 'GET' });
 | 
			
		||||
 | 
			
		||||
      dispatch(getUserPermissionsSucceeded(data));
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      dispatch(getUserPermissionsError(err));
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    fetchUserPermissions(true);
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  if (isLoading) {
 | 
			
		||||
    return <LoadingIndicatorPage />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <UserProvider value={{ userPermissions, fetchUserPermissions }}>{children}</UserProvider>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PermissionsManager.defaultProps = {};
 | 
			
		||||
 | 
			
		||||
PermissionsManager.propTypes = {
 | 
			
		||||
  children: PropTypes.node.isRequired,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default PermissionsManager;
 | 
			
		||||
@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 * PermissionsManager reducer
 | 
			
		||||
 * The goal of this reducer is to provide
 | 
			
		||||
 * the plugins with an access to the user's permissions
 | 
			
		||||
 * in our middleware system
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import produce from 'immer';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  GET_USER_PERMISSIONS,
 | 
			
		||||
  GET_USER_PERMISSIONS_ERROR,
 | 
			
		||||
  GET_USER_PERMISSIONS_SUCCEEDED,
 | 
			
		||||
} from './constants';
 | 
			
		||||
 | 
			
		||||
const initialState = {
 | 
			
		||||
  isLoading: true,
 | 
			
		||||
  userPermissions: [],
 | 
			
		||||
  collectionTypesRelatedPermissions: {},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const reducer = (state = initialState, action) =>
 | 
			
		||||
  // eslint-disable-next-line consistent-return
 | 
			
		||||
  produce(state, draftState => {
 | 
			
		||||
    switch (action.type) {
 | 
			
		||||
      case GET_USER_PERMISSIONS: {
 | 
			
		||||
        draftState.isLoading = true;
 | 
			
		||||
        draftState.userPermissions = [];
 | 
			
		||||
        draftState.collectionTypesRelatedPermissions = {};
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case GET_USER_PERMISSIONS_ERROR: {
 | 
			
		||||
        draftState.error = action.error;
 | 
			
		||||
        draftState.isLoading = false;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case GET_USER_PERMISSIONS_SUCCEEDED: {
 | 
			
		||||
        draftState.isLoading = false;
 | 
			
		||||
        draftState.userPermissions = action.data;
 | 
			
		||||
        draftState.collectionTypesRelatedPermissions = action.data
 | 
			
		||||
          .filter(perm => perm.subject)
 | 
			
		||||
          .reduce((acc, current) => {
 | 
			
		||||
            const { subject, action } = current;
 | 
			
		||||
 | 
			
		||||
            if (!acc[subject]) {
 | 
			
		||||
              acc[subject] = {};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            acc[subject] = acc[subject][action]
 | 
			
		||||
              ? { ...acc[subject], [action]: [...acc[subject][action], current] }
 | 
			
		||||
              : { ...acc[subject], [action]: [current] };
 | 
			
		||||
 | 
			
		||||
            return acc;
 | 
			
		||||
          }, {});
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      default:
 | 
			
		||||
        return state;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
export default reducer;
 | 
			
		||||
export { initialState };
 | 
			
		||||
@ -0,0 +1,103 @@
 | 
			
		||||
import produce from 'immer';
 | 
			
		||||
import {
 | 
			
		||||
  getUserPermissions,
 | 
			
		||||
  getUserPermissionsError,
 | 
			
		||||
  getUserPermissionsSucceeded,
 | 
			
		||||
} from '../actions';
 | 
			
		||||
import permissionsManagerReducer from '../reducer';
 | 
			
		||||
 | 
			
		||||
describe('permissionsManagerReducer', () => {
 | 
			
		||||
  let state;
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    state = {
 | 
			
		||||
      isLoading: true,
 | 
			
		||||
      userPermissions: [],
 | 
			
		||||
      collectionTypesRelatedPermissions: {},
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('returns the initial state', () => {
 | 
			
		||||
    const expected = state;
 | 
			
		||||
 | 
			
		||||
    expect(permissionsManagerReducer(undefined, {})).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle the getUserPermissions action correctly', () => {
 | 
			
		||||
    state.userPermissions = ['test'];
 | 
			
		||||
    state.collectionTypesRelatedPermissions = null;
 | 
			
		||||
 | 
			
		||||
    const expected = produce(state, draft => {
 | 
			
		||||
      draft.isLoading = true;
 | 
			
		||||
      draft.userPermissions = [];
 | 
			
		||||
      draft.collectionTypesRelatedPermissions = {};
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(permissionsManagerReducer(state, getUserPermissions())).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle the getUserPermissionsError action correctly', () => {
 | 
			
		||||
    const error = 'Error';
 | 
			
		||||
    const expected = produce(state, draft => {
 | 
			
		||||
      draft.isLoading = false;
 | 
			
		||||
      draft.error = error;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(permissionsManagerReducer(state, getUserPermissionsError(error))).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle the getUserPermissionsSucceeded action correctly', () => {
 | 
			
		||||
    const data = [
 | 
			
		||||
      {
 | 
			
		||||
        action: 'create',
 | 
			
		||||
        subject: 'address',
 | 
			
		||||
        properties: {
 | 
			
		||||
          fields: ['f1'],
 | 
			
		||||
        },
 | 
			
		||||
        conditions: [],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        action: 'create',
 | 
			
		||||
        subject: 'address',
 | 
			
		||||
        properties: {
 | 
			
		||||
          fields: ['f2'],
 | 
			
		||||
        },
 | 
			
		||||
        conditions: [],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        action: 'tes',
 | 
			
		||||
        subject: null,
 | 
			
		||||
        properties: {},
 | 
			
		||||
        conditions: [],
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
    const expected = produce(state, draft => {
 | 
			
		||||
      draft.isLoading = false;
 | 
			
		||||
      draft.userPermissions = data;
 | 
			
		||||
      draft.collectionTypesRelatedPermissions = {
 | 
			
		||||
        address: {
 | 
			
		||||
          create: [
 | 
			
		||||
            {
 | 
			
		||||
              action: 'create',
 | 
			
		||||
              subject: 'address',
 | 
			
		||||
              properties: {
 | 
			
		||||
                fields: ['f1'],
 | 
			
		||||
              },
 | 
			
		||||
              conditions: [],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              action: 'create',
 | 
			
		||||
              subject: 'address',
 | 
			
		||||
              properties: {
 | 
			
		||||
                fields: ['f2'],
 | 
			
		||||
              },
 | 
			
		||||
              conditions: [],
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(permissionsManagerReducer(state, getUserPermissionsSucceeded(data))).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -5,7 +5,7 @@ import reducer, { initialState } from './reducer';
 | 
			
		||||
import init from './init';
 | 
			
		||||
 | 
			
		||||
const useSettingsMenu = (noCheck = false) => {
 | 
			
		||||
  const permissions = useContext(UserContext);
 | 
			
		||||
  const { userPermissions: permissions } = useContext(UserContext);
 | 
			
		||||
  const { plugins } = useGlobalContext();
 | 
			
		||||
 | 
			
		||||
  const [{ isLoading, menu }, dispatch] = useReducer(reducer, initialState, () =>
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ import adminReducer from './containers/Admin/reducer';
 | 
			
		||||
import languageProviderReducer from './containers/LanguageProvider/reducer';
 | 
			
		||||
import notificationProviderReducer from './containers/NotificationProvider/reducer';
 | 
			
		||||
import newNotificationReducer from './containers/NewNotification/reducer';
 | 
			
		||||
 | 
			
		||||
import permissionsManagerReducer from './containers/PermissionsManager/reducer';
 | 
			
		||||
/**
 | 
			
		||||
 * Creates the main reducer with the dynamically injected ones
 | 
			
		||||
 */
 | 
			
		||||
@ -20,6 +20,7 @@ export default function createReducer(injectedReducers) {
 | 
			
		||||
    language: languageProviderReducer,
 | 
			
		||||
    notification: notificationProviderReducer,
 | 
			
		||||
    newNotification: newNotificationReducer,
 | 
			
		||||
    permissionsManager: permissionsManagerReducer,
 | 
			
		||||
    ...injectedReducers,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,8 @@ import LoadingIndicatorPage from '../LoadingIndicatorPage';
 | 
			
		||||
const CheckPagePermissions = ({ permissions, children }) => {
 | 
			
		||||
  const abortController = new AbortController();
 | 
			
		||||
  const { signal } = abortController;
 | 
			
		||||
  const userPermissions = useUser();
 | 
			
		||||
  const { userPermissions } = useUser();
 | 
			
		||||
 | 
			
		||||
  const [state, setState] = useState({ isLoading: true, canAccess: false });
 | 
			
		||||
  const isMounted = useRef(true);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ import hasPermissions from '../../utils/hasPermissions';
 | 
			
		||||
// except that it does not handle redirections nor loading state
 | 
			
		||||
 | 
			
		||||
const CheckPermissions = ({ permissions, children }) => {
 | 
			
		||||
  const userPermissions = useUser();
 | 
			
		||||
  const { userPermissions } = useUser();
 | 
			
		||||
  const [state, setState] = useState({ isLoading: true, canAccess: false });
 | 
			
		||||
  const isMounted = useRef(true);
 | 
			
		||||
  const abortController = new AbortController();
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ const useUserPermissions = pluginPermissions => {
 | 
			
		||||
  const permissionNames = useMemo(() => {
 | 
			
		||||
    return Object.keys(pluginPermissions);
 | 
			
		||||
  }, [pluginPermissions]);
 | 
			
		||||
  const currentUserPermissions = useUser();
 | 
			
		||||
  const { userPermissions: currentUserPermissions } = useUser();
 | 
			
		||||
  const [state, dispatch] = useReducer(reducer, {}, () => init(permissionNames));
 | 
			
		||||
  const checkPermissionsRef = useRef();
 | 
			
		||||
  const generateArrayOfPromisesRef = useRef();
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ const DynamicComponent = ({ componentUid, friendlyName, icon, setIsOverDynamicZo
 | 
			
		||||
  const [isOver, setIsOver] = useState(false);
 | 
			
		||||
  const [{ isLoading, canAccess }, setState] = useState({ isLoading: true, canAccess: false });
 | 
			
		||||
  const { push } = useHistory();
 | 
			
		||||
  const userPermissions = useUser();
 | 
			
		||||
  const { userPermissions } = useUser();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const checkPermission = async () => {
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ function FilterPicker({
 | 
			
		||||
}) {
 | 
			
		||||
  const { emitEvent } = useGlobalContext();
 | 
			
		||||
  const emitEventRef = useRef(emitEvent);
 | 
			
		||||
  const userPermissions = useUser();
 | 
			
		||||
  const { userPermissions } = useUser();
 | 
			
		||||
  const readActionAllowedFields = useMemo(() => {
 | 
			
		||||
    const matchingPermissions = findMatchingPermissions(userPermissions, [
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ const EditView = ({ isSingleType, goBack, layout, slug, state, id, origin }) =>
 | 
			
		||||
  const { allowedActions, isLoading: isLoadingForPermissions } = useUserPermissions(
 | 
			
		||||
    viewPermissions
 | 
			
		||||
  );
 | 
			
		||||
  const userPermissions = useUser();
 | 
			
		||||
  const { userPermissions } = useUser();
 | 
			
		||||
 | 
			
		||||
  // Here in case of a 403 response when fetching data we will either redirect to the previous page
 | 
			
		||||
  // Or to the homepage if there's no state in the history stack
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ import {
 | 
			
		||||
  useGlobalContext,
 | 
			
		||||
  PopUpWarning,
 | 
			
		||||
  useStrapi,
 | 
			
		||||
  useUser,
 | 
			
		||||
} from 'strapi-helper-plugin';
 | 
			
		||||
import { useHistory, useLocation, useRouteMatch, Redirect } from 'react-router-dom';
 | 
			
		||||
import { connect, useDispatch } from 'react-redux';
 | 
			
		||||
@ -67,7 +68,9 @@ const DataManagerProvider = ({
 | 
			
		||||
  } = useStrapi();
 | 
			
		||||
  const { apis } = getPlugin(pluginId);
 | 
			
		||||
  const [infoModals, toggleInfoModal] = useState({ cancel: false });
 | 
			
		||||
  const { autoReload, emitEvent, fetchUserPermissions, formatMessage, menu } = useGlobalContext();
 | 
			
		||||
  const { autoReload, emitEvent, formatMessage } = useGlobalContext();
 | 
			
		||||
  const { fetchUserPermissions } = useUser();
 | 
			
		||||
 | 
			
		||||
  const { pathname } = useLocation();
 | 
			
		||||
  const { push } = useHistory();
 | 
			
		||||
  const contentTypeMatch = useRouteMatch(`/plugins/${pluginId}/content-types/:uid`);
 | 
			
		||||
@ -301,8 +304,6 @@ const DataManagerProvider = ({
 | 
			
		||||
        // Refetch the permissions
 | 
			
		||||
        await updatePermissions();
 | 
			
		||||
 | 
			
		||||
        // Update the app menu
 | 
			
		||||
        await updateAppMenu();
 | 
			
		||||
        // Refetch all the data
 | 
			
		||||
        getDataRef.current();
 | 
			
		||||
      }
 | 
			
		||||
@ -399,7 +400,6 @@ const DataManagerProvider = ({
 | 
			
		||||
 | 
			
		||||
    const dataShape = orderAllDataAttributesWithImmutable(newSchemaToSet, isInContentTypeView);
 | 
			
		||||
 | 
			
		||||
    // This prevents from losing the created content type or component when clicking on the link from the left menu
 | 
			
		||||
    const hasJustCreatedSchema =
 | 
			
		||||
      get(schemaToSet, 'isTemporary', false) &&
 | 
			
		||||
      size(get(schemaToSet, 'schema.attributes', {})) === 0;
 | 
			
		||||
@ -471,9 +471,6 @@ const DataManagerProvider = ({
 | 
			
		||||
 | 
			
		||||
      await updatePermissions();
 | 
			
		||||
 | 
			
		||||
      // Update the app menu
 | 
			
		||||
      await updateAppMenu();
 | 
			
		||||
 | 
			
		||||
      // Submit ct tracking success
 | 
			
		||||
      if (isInContentTypeView) {
 | 
			
		||||
        emitEvent('didSaveContentType');
 | 
			
		||||
@ -512,13 +509,6 @@ const DataManagerProvider = ({
 | 
			
		||||
    toggleInfoModal(prev => ({ ...prev, cancel: !prev.cancel }));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Update the menu using the internal API
 | 
			
		||||
  const updateAppMenu = async () => {
 | 
			
		||||
    if (menu.getModels) {
 | 
			
		||||
      await menu.getModels();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const updatePermissions = async () => {
 | 
			
		||||
    await fetchUserPermissions();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user