diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/RBACManager/useSyncRbac.js b/packages/strapi-plugin-content-manager/admin/src/containers/RBACManager/useSyncRbac.js index f241b44a96..12b44f16a6 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/RBACManager/useSyncRbac.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/RBACManager/useSyncRbac.js @@ -1,14 +1,9 @@ import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import pluginId from '../../pluginId'; import { resetPermissions, setPermissions } from './actions'; +import { selectPermissions, selectCollectionTypePermissions } from '../../selectors'; -const selectPermissions = state => state.get(`${pluginId}_rbacManager`).permissions; - -const selectCollectionTypePermissions = state => - state.get('permissionsManager').collectionTypesRelatedPermissions; - -const useSyncRbac = (query, collectionTypeUID = 'listView') => { +const useSyncRbac = (query, collectionTypeUID) => { const collectionTypesRelatedPermissions = useSelector(selectCollectionTypePermissions); const permissions = useSelector(selectPermissions); const dispatch = useDispatch(); diff --git a/packages/strapi-plugin-content-manager/admin/src/selectors.js b/packages/strapi-plugin-content-manager/admin/src/selectors.js new file mode 100644 index 0000000000..c9c1d3ca77 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/selectors.js @@ -0,0 +1,6 @@ +import pluginId from './pluginId'; + +export const selectPermissions = state => state.get(`${pluginId}_rbacManager`).permissions; + +export const selectCollectionTypePermissions = state => + state.get('permissionsManager').collectionTypesRelatedPermissions; diff --git a/packages/strapi-plugin-content-manager/admin/src/tests/selectors.test.js b/packages/strapi-plugin-content-manager/admin/src/tests/selectors.test.js new file mode 100644 index 0000000000..e26e982b17 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/tests/selectors.test.js @@ -0,0 +1,43 @@ +import { selectPermissions, selectCollectionTypePermissions } from '../selectors'; + +describe('selectors', () => { + let store; + + beforeEach(() => { + store = new Map(); + }); + + describe('selectPermissions', () => { + it('resolves the permissions key of the "content-manager_rbacManager" store key', () => { + store.set('content-manager_rbacManager', { + permissions: { + some: 'permission', + }, + }); + + const actual = selectPermissions(store); + const expected = { + some: 'permission', + }; + + expect(actual).toEqual(expected); + }); + }); + + describe('selectCollectionTypePermissions', () => { + it('resolves the permissions key of the "permissionsManager" store key', () => { + store.set('permissionsManager', { + collectionTypesRelatedPermissions: { + some: 'permission again', + }, + }); + + const actual = selectCollectionTypePermissions(store); + const expected = { + some: 'permission again', + }; + + expect(actual).toEqual(expected); + }); + }); +}); diff --git a/packages/strapi-plugin-i18n/admin/src/components/LocalePicker/index.js b/packages/strapi-plugin-i18n/admin/src/components/LocalePicker/index.js index fc4a34f40a..b18b20e862 100644 --- a/packages/strapi-plugin-i18n/admin/src/components/LocalePicker/index.js +++ b/packages/strapi-plugin-i18n/admin/src/components/LocalePicker/index.js @@ -4,6 +4,7 @@ import { Picker, Padded, Text, Flex } from '@buffetjs/core'; import { Carret, useQueryParams } from 'strapi-helper-plugin'; import styled from 'styled-components'; import get from 'lodash/get'; +import getInitialLocale from '../../utils/getInitialLocale'; const List = styled.ul` list-style-type: none; @@ -34,16 +35,6 @@ const EllipsisParagraph = styled(Text)` text-align: left; `; -const getInitialLocale = (query, locales = []) => { - const localeFromQuery = get(query, 'query.pluginOptions.locale', undefined); - - if (localeFromQuery) { - return locales.find(locale => locale.code === localeFromQuery); - } - - return locales[0]; -}; - const selectContentManagerListViewPluginOptions = state => state.get('content-manager_listView').contentType.pluginOptions; diff --git a/packages/strapi-plugin-i18n/admin/src/middlewares/localePermissionMiddleware.js b/packages/strapi-plugin-i18n/admin/src/middlewares/localePermissionMiddleware.js index ba0c5aab5b..b206f4c73b 100644 --- a/packages/strapi-plugin-i18n/admin/src/middlewares/localePermissionMiddleware.js +++ b/packages/strapi-plugin-i18n/admin/src/middlewares/localePermissionMiddleware.js @@ -8,15 +8,18 @@ const localePermissionMiddleware = () => () => next => action => { return next(action); } - if (action.__meta__.containerName !== 'listView') { + const containerName = get(action, '__meta__.containerName', null); + + if (containerName !== 'listView') { return next(action); } - if (!get(action, '__meta__.pluginOptions.locale', false)) { + const locale = get(action, '__meta__.pluginOptions.locale', null); + + if (!locale) { return next(action); } - const locale = action.__meta__.pluginOptions.locale; const permissions = action.permissions; const nextPermissions = Object.keys(permissions).reduce((acc, key) => { diff --git a/packages/strapi-plugin-i18n/admin/src/middlewares/tests/localePermissionMiddleware.test.js b/packages/strapi-plugin-i18n/admin/src/middlewares/tests/localePermissionMiddleware.test.js new file mode 100644 index 0000000000..ee2d04ce9b --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/middlewares/tests/localePermissionMiddleware.test.js @@ -0,0 +1,136 @@ +import localePermissionMiddleware from '../localePermissionMiddleware'; + +describe('localePermissionMiddleware', () => { + it('does not modify the action when the type is not "ContentManager/RBACManager/SET_PERMISSIONS"', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'UNKNOWN_TYPE', + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toBe(action); + }); + + it('does not modify the action when it the __meta__ key is not set', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: undefined, + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toBe(action); + }); + + it('does not modify the action when it the __meta__.containerName is not "listView"', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { containerName: undefined }, + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toBe(action); + }); + + it('does not modify the action when it the __meta__.pluginOptions is not set', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { containerName: 'listView' }, + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toBe(action); + }); + + it('does not modify the action when it the __meta__.pluginOptions.locale is not set', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { + containerName: 'listView', + pluginOptions: {}, + }, + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toBe(action); + }); + + it('creates an empty permissions object from an empty array', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { + containerName: 'listView', + pluginOptions: { + locale: 'en', + }, + }, + permissions: {}, + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toEqual({ + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { containerName: 'listView', pluginOptions: { locale: 'en' } }, + permissions: {}, + }); + }); + + it('creates a valid permissions object from a filled array', () => { + const nextFn = jest.fn(x => x); + const action = { + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { + containerName: 'listView', + pluginOptions: { + locale: 'en', + }, + }, + permissions: { + 'plugins::content-manager.explorer.create': [ + { + id: 459, + action: 'plugins::content-manager.explorer.create', + subject: 'application::article.article', + properties: { + fields: ['Name'], + locales: ['en'], + }, + conditions: [], + }, + ], + }, + }; + + const nextAction = localePermissionMiddleware()()(nextFn)(action); + + expect(nextAction).toEqual({ + type: 'ContentManager/RBACManager/SET_PERMISSIONS', + __meta__: { containerName: 'listView', pluginOptions: { locale: 'en' } }, + permissions: { + 'plugins::content-manager.explorer.create': [ + { + id: 459, + action: 'plugins::content-manager.explorer.create', + subject: 'application::article.article', + properties: { + fields: ['Name'], + locales: ['en'], + }, + + conditions: [], + }, + ], + }, + }); + }); +}); diff --git a/packages/strapi-plugin-i18n/admin/src/utils/getInitialLocale.js b/packages/strapi-plugin-i18n/admin/src/utils/getInitialLocale.js new file mode 100644 index 0000000000..66fa768730 --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/utils/getInitialLocale.js @@ -0,0 +1,14 @@ +import getLocaleFromQuery from './getLocaleFromQuery'; + +const getInitialLocale = (query, locales = []) => { + const localeFromQuery = getLocaleFromQuery(query); + + if (localeFromQuery) { + return locales.find(locale => locale.code === localeFromQuery); + } + + // Returns the default locale when nothing is in the query + return locales.find(locale => locale.isDefault); +}; + +export default getInitialLocale; diff --git a/packages/strapi-plugin-i18n/admin/src/utils/getLocaleFromQuery.js b/packages/strapi-plugin-i18n/admin/src/utils/getLocaleFromQuery.js new file mode 100644 index 0000000000..83d977b2aa --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/utils/getLocaleFromQuery.js @@ -0,0 +1,7 @@ +import get from 'lodash/get'; + +const getLocaleFromQuery = query => { + return get(query, 'query.pluginOptions.locale', undefined); +}; + +export default getLocaleFromQuery; diff --git a/packages/strapi-plugin-i18n/admin/src/utils/tests/getInitialLocale.test.js b/packages/strapi-plugin-i18n/admin/src/utils/tests/getInitialLocale.test.js new file mode 100644 index 0000000000..b71bc1b03e --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/utils/tests/getInitialLocale.test.js @@ -0,0 +1,115 @@ +import getInitialLocale from '../getInitialLocale'; + +describe('getInitialLocale', () => { + it('gives "fr-FR" when the query.pluginOptions.locale is "fr-FR"', () => { + const query = { + query: { + page: '1', + pageSize: '10', + _sort: 'Name:ASC', + pluginOptions: { + locale: 'fr-FR', + }, + }, + rawQuery: '?page=1&pageSize=10&_sort=Name:ASC&pluginOptions[locale]=fr-FR', + }; + + const locales = [ + { + id: 1, + name: 'English', + code: 'en', + created_at: '2021-03-09T14:57:03.016Z', + updated_at: '2021-03-09T14:57:03.016Z', + isDefault: true, + }, + { + id: 2, + name: 'French (France) (fr-FR)', + code: 'fr-FR', + created_at: '2021-03-09T15:03:06.992Z', + updated_at: '2021-03-09T15:03:06.996Z', + isDefault: false, + }, + ]; + + const expected = { + id: 2, + name: 'French (France) (fr-FR)', + code: 'fr-FR', + created_at: '2021-03-09T15:03:06.992Z', + updated_at: '2021-03-09T15:03:06.996Z', + isDefault: false, + }; + const actual = getInitialLocale(query, locales); + + expect(actual).toEqual(expected); + }); + + it('gives the default locale ("en") when there s no locale in the query', () => { + const query = { + query: { + page: '1', + pageSize: '10', + _sort: 'Name:ASC', + pluginOptions: { + something: 'great', + }, + }, + rawQuery: '?page=1&pageSize=10&_sort=Name:ASC&pluginOptions[something]=great', + }; + + const locales = [ + { + id: 2, + name: 'French (France) (fr-FR)', + code: 'fr-FR', + created_at: '2021-03-09T15:03:06.992Z', + updated_at: '2021-03-09T15:03:06.996Z', + isDefault: false, + }, + { + id: 1, + name: 'English', + code: 'en', + created_at: '2021-03-09T14:57:03.016Z', + updated_at: '2021-03-09T14:57:03.016Z', + isDefault: true, + }, + ]; + + const expected = { + id: 1, + name: 'English', + code: 'en', + created_at: '2021-03-09T14:57:03.016Z', + updated_at: '2021-03-09T14:57:03.016Z', + isDefault: true, + }; + + const actual = getInitialLocale(query, locales); + + expect(actual).toEqual(expected); + }); + + it('gives "undefined" when theres no locale. IMPORTANT: such case should not exist since at least one locale is created on the backend when plug-in i18n', () => { + const query = { + query: { + page: '1', + pageSize: '10', + _sort: 'Name:ASC', + pluginOptions: { + something: 'great', + }, + }, + rawQuery: '?page=1&pageSize=10&_sort=Name:ASC&pluginOptions[something]=great', + }; + + const locales = []; + + const expected = undefined; + const actual = getInitialLocale(query, locales); + + expect(actual).toEqual(expected); + }); +});