mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 15:13:21 +00:00
Merge branch 'user-permissions' of https://github.com/strapi/strapi into user-permissions
This commit is contained in:
commit
034207a326
@ -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" />
|
||||
|
||||
<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;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
<strong>{this.props.item.nb_users || 0}</strong>
|
||||
{this.props.item.nb_users > 1 ? (
|
||||
'users'
|
||||
) : (
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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}
|
||||
/>
|
||||
|
||||
@ -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'))
|
||||
|
||||
@ -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');
|
||||
}
|
||||
|
||||
@ -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} ",
|
||||
|
||||
@ -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} ",
|
||||
|
||||
@ -247,6 +247,10 @@
|
||||
"identity": {
|
||||
"enabled": true,
|
||||
"policy": ""
|
||||
},
|
||||
"getRoutes": {
|
||||
"enabled": true,
|
||||
"policy": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -504,6 +508,10 @@
|
||||
"identity": {
|
||||
"enabled": false,
|
||||
"policy": ""
|
||||
},
|
||||
"getRoutes": {
|
||||
"enabled": false,
|
||||
"policy": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,14 @@
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/routes",
|
||||
"handler": "UsersPermissions.getRoutes",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"method": "POST",
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user