Merge branch 'i18n/rbac-rework-front' of github.com:strapi/strapi into i18n/add-filters-to-relations

This commit is contained in:
soupette 2021-03-15 10:46:35 +01:00
commit 534dba09ad
9 changed files with 330 additions and 20 deletions

View File

@ -1,14 +1,9 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import pluginId from '../../pluginId';
import { resetPermissions, setPermissions } from './actions'; import { resetPermissions, setPermissions } from './actions';
import { selectPermissions, selectCollectionTypePermissions } from '../../selectors';
const selectPermissions = state => state.get(`${pluginId}_rbacManager`).permissions; const useSyncRbac = (query, collectionTypeUID) => {
const selectCollectionTypePermissions = state =>
state.get('permissionsManager').collectionTypesRelatedPermissions;
const useSyncRbac = (query, collectionTypeUID = 'listView') => {
const collectionTypesRelatedPermissions = useSelector(selectCollectionTypePermissions); const collectionTypesRelatedPermissions = useSelector(selectCollectionTypePermissions);
const permissions = useSelector(selectPermissions); const permissions = useSelector(selectPermissions);
const dispatch = useDispatch(); const dispatch = useDispatch();

View File

@ -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;

View File

@ -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);
});
});
});

View File

@ -4,6 +4,7 @@ import { Picker, Padded, Text, Flex } from '@buffetjs/core';
import { Carret, useQueryParams } from 'strapi-helper-plugin'; import { Carret, useQueryParams } from 'strapi-helper-plugin';
import styled from 'styled-components'; import styled from 'styled-components';
import get from 'lodash/get'; import get from 'lodash/get';
import getInitialLocale from '../../utils/getInitialLocale';
const List = styled.ul` const List = styled.ul`
list-style-type: none; list-style-type: none;
@ -34,16 +35,6 @@ const EllipsisParagraph = styled(Text)`
text-align: left; 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 => const selectContentManagerListViewPluginOptions = state =>
state.get('content-manager_listView').contentType.pluginOptions; state.get('content-manager_listView').contentType.pluginOptions;

View File

@ -8,15 +8,18 @@ const localePermissionMiddleware = () => () => next => action => {
return next(action); return next(action);
} }
if (action.__meta__.containerName !== 'listView') { const containerName = get(action, '__meta__.containerName', null);
if (containerName !== 'listView') {
return next(action); return next(action);
} }
if (!get(action, '__meta__.pluginOptions.locale', false)) { const locale = get(action, '__meta__.pluginOptions.locale', null);
if (!locale) {
return next(action); return next(action);
} }
const locale = action.__meta__.pluginOptions.locale;
const permissions = action.permissions; const permissions = action.permissions;
const nextPermissions = Object.keys(permissions).reduce((acc, key) => { const nextPermissions = Object.keys(permissions).reduce((acc, key) => {

View File

@ -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: [],
},
],
},
});
});
});

View File

@ -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;

View File

@ -0,0 +1,7 @@
import get from 'lodash/get';
const getLocaleFromQuery = query => {
return get(query, 'query.pluginOptions.locale', undefined);
};
export default getLocaleFromQuery;

View File

@ -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);
});
});