Merge branch 'user-permissions' of https://github.com/strapi/strapi into user-permissions

This commit is contained in:
Jim Laurie 2017-12-01 11:16:08 +01:00
commit 034207a326
15 changed files with 192 additions and 4 deletions

View File

@ -0,0 +1,73 @@
/**
*
* BoundRoute
*
*/
import React from 'react';
import { get, includes, map, tail } from 'lodash';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import styles from './styles.scss';
function BoundRoute({ route }) {
let color;
switch (get(route, 'method')) {
case 'GET':
color = '#008DFE';
break;
case 'POST':
color = '#69BA05';
break;
case 'PUT':
color = '#F68E0E';
break;
default:
color = '#F64D0A';
}
const title = get(route, 'handler');
const formattedRoute = get(route, 'path') ? tail(get(route, 'path').split('/')) : [];
const [ controller = '', action = '' ] = title ? title.split('.') : [];
return (
<div className="col-md-12">
<div className={styles.title}>
<FormattedMessage id="users-permissions.BoundRoute.title" />
&nbsp;
<span>{controller}</span>
<span>.{action} </span>
</div>
<div className={styles.boundRoute}>
<div className={styles.verb} style={{ backgroundColor: color }}>
{get(route, 'method')}
</div>
<div className={styles.path}>
{map(formattedRoute, value => (
<span
key={value}
style={includes(value, ':') ? { color: '#787E8F' } : {}}
>
/{value}
</span>
))}
</div>
</div>
</div>
);
}
BoundRoute.defaultProps = {
route: {
handler: 'Nocontroller.error',
method: 'GET',
path: '/there-is-no-path',
},
};
BoundRoute.propTypes = {
route: PropTypes.object,
};
export default BoundRoute;

View File

@ -0,0 +1,43 @@
.boundRoute {
display: flex;
height: 2.4rem;
border-radius: 3px;
background-color: #E9EAEB;
line-height: 2.4rem;
}
.verb {
padding: 0 1rem;
border-radius: 3px;
color: #FFFFFF;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.path {
padding: 0 1rem;
font-size: 13px;
font-weight: 600;
color: #333740;
}
.title {
margin-bottom: 3rem;
padding-top: 1.1rem;
color: #333740;
font-size: 18px;
font-weight: 600;
> span:not(:first-child) {
color: #787E8F;
font-size: 16px;
font-weight: 500;
}
> span:last-child {
color: #1642E1;
font-weight: 600;
}
}

View File

@ -56,7 +56,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
{this.props.item.description}
</div>
<div className="col-md-1">
<strong>{this.props.item.nb_users}</strong>&nbsp;
<strong>{this.props.item.nb_users || 0}</strong>&nbsp;
{this.props.item.nb_users > 1 ? (
'users'
) : (

View File

@ -8,8 +8,9 @@ import React from 'react';
import cn from 'classnames';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { get } from 'lodash';
import { get, isEmpty, map, takeRight, toLower, without } from 'lodash';
import BoundRoute from 'components/BoundRoute';
import Input from 'components/Input';
import styles from './styles.scss';
@ -21,6 +22,9 @@ class Policies extends React.Component { // eslint-disable-line react/prefer-sta
const baseTitle = 'users-permissions.Policies.header';
const title = this.props.shouldDisplayPoliciesHint ? 'hint' : 'title';
const value = get(this.props.values, this.props.inputSelectName);
const path = without(this.props.inputSelectName.split('.'), 'permissions', 'controllers', 'policy');
const controllerRoutes = get(this.props.routes, without(this.props.inputSelectName.split('.'), 'permissions', 'controllers', 'policy')[0]);
const routes = isEmpty(controllerRoutes) ? [] : controllerRoutes.filter(o => toLower(o.handler) === toLower(takeRight(path, 2).join('.')));
return (
<div className={cn('col-md-5',styles.policies)}>
@ -42,6 +46,11 @@ class Policies extends React.Component { // eslint-disable-line react/prefer-sta
/>
) : ''}
</div>
<div className="row">
{!this.props.shouldDisplayPoliciesHint ? (
map(routes, (route, key) => <BoundRoute key={key} route={route} />)
) : ''}
</div>
</div>
</div>
);
@ -52,8 +61,13 @@ Policies.contextTypes = {
onChange: PropTypes.func.isRequired,
};
Policies.defaultProps = {
routes: {},
};
Policies.propTypes = {
inputSelectName: PropTypes.string.isRequired,
routes: PropTypes.object,
selectOptions: PropTypes.array.isRequired,
shouldDisplayPoliciesHint: PropTypes.bool.isRequired,
values: PropTypes.object.isRequired,

View File

@ -13,6 +13,7 @@ import {
GET_POLICIES_SUCCEEDED,
GET_ROLE,
GET_ROLE_SUCCEEDED,
GET_ROUTES_SUCCEEDED,
GET_USER,
GET_USER_SUCCEEDED,
ON_CANCEL,
@ -95,6 +96,13 @@ export function getRoleSucceeded(data) {
};
}
export function getRoutesSucceeded(routes) {
return {
type: GET_ROUTES_SUCCEEDED,
routes,
};
}
export function getUser(user) {
return {
type: GET_USER,

View File

@ -11,6 +11,7 @@ export const GET_POLICIES = 'UsersPermissions/EditPage/GET_POLICIES';
export const GET_POLICIES_SUCCEEDED = 'UsersPermissions/EditPage/GET_POLICIES_SUCCEEDED';
export const GET_ROLE = 'UsersPermissions/EditPage/GET_ROLE';
export const GET_ROLE_SUCCEEDED = 'UsersPermissions/EditPage/GET_ROLE_SUCCEEDED';
export const GET_ROUTES_SUCCEEDED = 'UsersPermissions/EditPage/GET_ROUTES_SUCCEEDED';
export const GET_USER = 'UsersPermissions/EditPage/GET_USER';
export const GET_USER_SUCCEEDED = 'UsersPermissions/EditPage/GET_USER_SUCCEEDED';
export const ON_CANCEL = 'UsersPermissions/EditPage/ON_CANCEL';

View File

@ -207,6 +207,7 @@ export class EditPage extends React.Component { // eslint-disable-line react/pre
<Policies
shouldDisplayPoliciesHint={this.props.editPage.shouldDisplayPoliciesHint}
inputSelectName={this.props.editPage.inputPoliciesPath}
routes={this.props.editPage.routes}
selectOptions={this.props.editPage.policies}
values={this.props.editPage.modifiedData}
/>

View File

@ -12,6 +12,7 @@ import {
GET_POLICIES_SUCCEEDED,
GET_ROLE_SUCCEEDED,
GET_USER_SUCCEEDED,
GET_ROUTES_SUCCEEDED,
ON_CANCEL,
ON_CHANGE_INPUT,
ON_CLICK_ADD,
@ -41,6 +42,7 @@ const initialState = fromJS({
modifiedData: Map({}),
policies: List([]),
roleId: '',
routes: Map([]),
shouldDisplayPoliciesHint: true,
users: List([]),
});
@ -61,6 +63,8 @@ function editPageReducer(state = initialState, action) {
.set('didGetUsers', !state.get('didGetUsers'))
.set('initialData', action.form)
.set('modifiedData', action.form);
case GET_ROUTES_SUCCEEDED:
return state.set('routes', Map(action.routes.routes));
case GET_USER_SUCCEEDED:
return state
.set('didFetchUsers', !state.get('didFetchUsers'))

View File

@ -14,6 +14,7 @@ import {
getPermissionsSucceeded,
getPoliciesSucceeded,
getRoleSucceeded,
getRoutesSucceeded,
getUserSucceeded,
submitSucceeded,
} from './actions';
@ -53,9 +54,13 @@ export function* permissionsGet() {
export function* policiesGet() {
try {
const response = yield call(request, '/users-permissions/policies', { method: 'GET' });
const response = yield [
call(request, '/users-permissions/policies', { method: 'GET' }),
call(request, '/users-permissions/routes', { method: 'GET' }),
];
yield put(getPoliciesSucceeded(response));
yield put(getPoliciesSucceeded(response[0]));
yield put(getRoutesSucceeded(response[1]));
} catch(err) {
strapi.notification.error('users-permissions.EditPage.notification.policies.error');
}

View File

@ -42,6 +42,8 @@
"Auth.link.forgot-password": "Forgot your password?",
"Auth.link.ready": "Ready to sign-in?",
"BoundRoute.title": "Bound route to",
"components.Input.error.password.noMatch": "Password don't match",
"Controller.input.label": "{label} ",

View File

@ -42,6 +42,8 @@
"Auth.link.forgot-password": "Mot de passe oublié?",
"Auth.link.ready": "Prêt à vous connecter?",
"BoundRoute.title": "Route associée à",
"components.Input.error.password.noMatch": "Le mot de passe ne correspond pas",
"Controller.input.label": "{label} ",

View File

@ -247,6 +247,10 @@
"identity": {
"enabled": true,
"policy": ""
},
"getRoutes": {
"enabled": true,
"policy": ""
}
}
}
@ -504,6 +508,10 @@
"identity": {
"enabled": false,
"policy": ""
},
"getRoutes": {
"enabled": false,
"policy": ""
}
}
}

View File

@ -56,6 +56,14 @@
"policies": []
}
},
{
"method": "GET",
"path": "/routes",
"handler": "UsersPermissions.getRoutes",
"config": {
"policies": []
}
},
{
"method": "POST",

View File

@ -95,6 +95,17 @@ module.exports = {
}
},
getRoutes: async (ctx) => {
try {
const routes = await strapi.plugins['users-permissions'].services.userspermissions.getRoutes();
ctx.send({ routes });
} catch(err) {
console.log(err);
ctx.badRequest(null, [{ messages: [{ id: 'Not found' }] }]);
}
},
index: async (ctx) => {
// Add your own logic here.

View File

@ -96,6 +96,14 @@ module.exports = {
return formattedRoles;
},
getRoutes: async () => {
return Object.keys(strapi.plugins).reduce((acc, current) => {
acc[current] = strapi.plugins[current].config.routes;
return acc;
}, {});
},
getRoleConfigPath: () => (
path.join(
strapi.config.appPath,