mirror of
https://github.com/strapi/strapi.git
synced 2025-11-17 02:28:30 +00:00
Merge branch 'master' into fix-graphql-many-to-many-relations
This commit is contained in:
commit
5188d70d91
@ -13,6 +13,7 @@ before_install:
|
|||||||
- export CHROME_BIN=chromium-browser
|
- export CHROME_BIN=chromium-browser
|
||||||
- export DISPLAY=:99.0
|
- export DISPLAY=:99.0
|
||||||
- sh -e /etc/init.d/xvfb start
|
- sh -e /etc/init.d/xvfb start
|
||||||
|
- git fetch -a
|
||||||
# - sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
|
# - sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
|
||||||
# - npm cache clean --force
|
# - npm cache clean --force
|
||||||
# - rm -rf node_modules/
|
# - rm -rf node_modules/
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -14,14 +14,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Switch, Route } from 'react-router-dom';
|
import { Switch, Route } from 'react-router-dom';
|
||||||
|
|
||||||
import AdminPage from 'containers/AdminPage';
|
import AdminPage from 'containers/AdminPage';
|
||||||
import NotFoundPage from 'containers/NotFoundPage';
|
import NotFoundPage from 'containers/NotFoundPage';
|
||||||
|
|
||||||
import NotificationProvider from 'containers/NotificationProvider';
|
import NotificationProvider from 'containers/NotificationProvider';
|
||||||
|
import AppLoader from 'containers/AppLoader';
|
||||||
|
import LoadingIndicatorPage from 'components/LoadingIndicatorPage';
|
||||||
import '../../styles/main.scss';
|
import '../../styles/main.scss';
|
||||||
|
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
|
|
||||||
export class App extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
export class App extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
@ -29,12 +27,22 @@ export class App extends React.Component { // eslint-disable-line react/prefer-s
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<NotificationProvider />
|
<NotificationProvider />
|
||||||
|
<AppLoader>
|
||||||
|
{({ shouldLoad }) => {
|
||||||
|
if (shouldLoad) {
|
||||||
|
return <LoadingIndicatorPage />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/" component={AdminPage} />
|
<Route path="/" component={AdminPage} />
|
||||||
<Route path="" component={NotFoundPage} />
|
<Route path="" component={NotFoundPage} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</AppLoader>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,11 @@ const selectPlugins = () => createSelector(
|
|||||||
(appState) => appState.get('plugins')
|
(appState) => appState.get('plugins')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const makeSelectApp = () => createSelector(
|
||||||
|
selectApp(),
|
||||||
|
appState => appState.toJS(),
|
||||||
|
);
|
||||||
|
|
||||||
const selectHasUserPlugin = () => createSelector(
|
const selectHasUserPlugin = () => createSelector(
|
||||||
selectApp(),
|
selectApp(),
|
||||||
(appState) => appState.get('hasUserPlugin'),
|
(appState) => appState.get('hasUserPlugin'),
|
||||||
@ -38,7 +43,7 @@ const makeSelectAppPlugins = () => createSelector(
|
|||||||
selectApp(),
|
selectApp(),
|
||||||
appState => appState.get('appPlugins').toJS(),
|
appState => appState.get('appPlugins').toJS(),
|
||||||
);
|
);
|
||||||
|
export default makeSelectApp;
|
||||||
export {
|
export {
|
||||||
selectApp,
|
selectApp,
|
||||||
selectHasUserPlugin,
|
selectHasUserPlugin,
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* AppLoader
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import makeSelectApp from 'containers/App/selectors';
|
||||||
|
|
||||||
|
class AppLoader extends React.Component {
|
||||||
|
shouldLoad = () => {
|
||||||
|
const { appPlugins, plugins: mountedPlugins } = this.props;
|
||||||
|
|
||||||
|
return appPlugins.length !== Object.keys(mountedPlugins).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children } = this.props;
|
||||||
|
|
||||||
|
return children({ shouldLoad: this.shouldLoad() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppLoader.propTypes = {
|
||||||
|
appPlugins: PropTypes.array.isRequired,
|
||||||
|
children: PropTypes.func.isRequired,
|
||||||
|
plugins: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = makeSelectApp();
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(AppLoader);
|
||||||
@ -291,6 +291,15 @@ module.exports = async cb => {
|
|||||||
// Update the displayed fields
|
// Update the displayed fields
|
||||||
const updatedListDisplay = prevListDisplay.filter(obj => obj.name !== currentAttr.join());
|
const updatedListDisplay = prevListDisplay.filter(obj => obj.name !== currentAttr.join());
|
||||||
|
|
||||||
|
// Retrieve the model's displayed fields for the `EditPage`
|
||||||
|
const fieldsPath = getEditDisplayFieldsPath(attrPath);
|
||||||
|
// Retrieve the previous settings
|
||||||
|
const prevEditDisplayFields = _.get(prevSchema.models, fieldsPath);
|
||||||
|
// Update the fields
|
||||||
|
const updatedEditDisplayFields = prevEditDisplayFields.filter(field => field !== currentAttr.join());
|
||||||
|
// Set the new layout
|
||||||
|
_.set(prevSchema.models, fieldsPath, updatedEditDisplayFields);
|
||||||
|
|
||||||
if (updatedListDisplay.length === 0) {
|
if (updatedListDisplay.length === 0) {
|
||||||
// Update it with the one from the generated schema
|
// Update it with the one from the generated schema
|
||||||
_.set(prevSchema.models, listDisplayPath, _.get(schema.models, listDisplayPath, []));
|
_.set(prevSchema.models, listDisplayPath, _.get(schema.models, listDisplayPath, []));
|
||||||
|
|||||||
@ -4,6 +4,7 @@ const fs = require('fs');
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
const Service = require('../services/ContentTypeBuilder');
|
const Service = require('../services/ContentTypeBuilder');
|
||||||
|
const { escapeNewlines } = require('../utils/helpers.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getModels: async ctx => {
|
getModels: async ctx => {
|
||||||
@ -47,11 +48,13 @@ module.exports = {
|
|||||||
return ctx.badRequest(null, [{ messages: attributesErrors }]);
|
return ctx.badRequest(null, [{ messages: attributesErrors }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _description = escapeNewlines(description, '\\n');
|
||||||
|
|
||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
await Service.appearance(formatedAttributes, name);
|
await Service.appearance(formatedAttributes, name);
|
||||||
|
|
||||||
await Service.generateAPI(name, description, connection, collectionName, []);
|
await Service.generateAPI(name, _description, connection, collectionName, []);
|
||||||
|
|
||||||
const modelFilePath = await Service.getModelPath(name, plugin);
|
const modelFilePath = await Service.getModelPath(name, plugin);
|
||||||
|
|
||||||
@ -103,12 +106,14 @@ module.exports = {
|
|||||||
return ctx.badRequest(null, [{ messages: attributesErrors }]);
|
return ctx.badRequest(null, [{ messages: attributesErrors }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _description = escapeNewlines(description);
|
||||||
|
|
||||||
let modelFilePath = Service.getModelPath(model, plugin);
|
let modelFilePath = Service.getModelPath(model, plugin);
|
||||||
|
|
||||||
strapi.reload.isWatching = false;
|
strapi.reload.isWatching = false;
|
||||||
|
|
||||||
if (name !== model) {
|
if (name !== model) {
|
||||||
await Service.generateAPI(name, description, connection, collectionName, []);
|
await Service.generateAPI(name, _description, connection, collectionName, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Service.appearance(formatedAttributes, name, plugin);
|
await Service.appearance(formatedAttributes, name, plugin);
|
||||||
@ -120,7 +125,7 @@ module.exports = {
|
|||||||
modelJSON.collectionName = collectionName;
|
modelJSON.collectionName = collectionName;
|
||||||
modelJSON.info = {
|
modelJSON.info = {
|
||||||
name,
|
name,
|
||||||
description
|
description: _description
|
||||||
};
|
};
|
||||||
modelJSON.attributes = formatedAttributes;
|
modelJSON.attributes = formatedAttributes;
|
||||||
|
|
||||||
|
|||||||
@ -61,10 +61,15 @@ const reorderList = (manager, list) => {
|
|||||||
return List(flattenDeep(reordered));
|
return List(flattenDeep(reordered));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const escapeNewlines = (content, placeholder = '\n') => {
|
||||||
|
return content.replace(/[\r\n]+/g, placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createArrayOfLastEls,
|
createArrayOfLastEls,
|
||||||
createManager,
|
createManager,
|
||||||
getElementsOnALine,
|
getElementsOnALine,
|
||||||
removeColsLine,
|
removeColsLine,
|
||||||
reorderList,
|
reorderList,
|
||||||
|
escapeNewlines
|
||||||
};
|
};
|
||||||
@ -9,6 +9,7 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const pluralize = require('pluralize');
|
const pluralize = require('pluralize');
|
||||||
const Schema = require('./Schema.js');
|
const Schema = require('./Schema.js');
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
@ -387,22 +388,6 @@ module.exports = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of fields that have type included in fieldTypes.
|
|
||||||
*/
|
|
||||||
getFieldsByTypes: (fields, typeCheck, returnType) => {
|
|
||||||
return _.reduce(
|
|
||||||
fields,
|
|
||||||
(acc, fieldType, fieldName) => {
|
|
||||||
if (typeCheck(fieldType)) {
|
|
||||||
acc[fieldName] = returnType(fieldType, fieldName);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the connection type of each non-array field of the model
|
* Generate the connection type of each non-array field of the model
|
||||||
*
|
*
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const _ = require('lodash');
|
|||||||
const pluralize = require('pluralize');
|
const pluralize = require('pluralize');
|
||||||
const policyUtils = require('strapi-utils').policy;
|
const policyUtils = require('strapi-utils').policy;
|
||||||
const Query = require('./Query.js');
|
const Query = require('./Query.js');
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
@ -64,10 +65,7 @@ module.exports = {
|
|||||||
const [name, action] = handler.split('.');
|
const [name, action] = handler.split('.');
|
||||||
|
|
||||||
const controller = plugin
|
const controller = plugin
|
||||||
? _.get(
|
? _.get(strapi.plugins, `${plugin}.controllers.${_.toLower(name)}.${action}`)
|
||||||
strapi.plugins,
|
|
||||||
`${plugin}.controllers.${_.toLower(name)}.${action}`,
|
|
||||||
)
|
|
||||||
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
@ -148,10 +146,7 @@ module.exports = {
|
|||||||
const [name, action] = resolverOf.split('.');
|
const [name, action] = resolverOf.split('.');
|
||||||
|
|
||||||
const controller = plugin
|
const controller = plugin
|
||||||
? _.get(
|
? _.get(strapi.plugins, `${plugin}.controllers.${_.toLower(name)}.${action}`)
|
||||||
strapi.plugins,
|
|
||||||
`${plugin}.controllers.${_.toLower(name)}.${action}`,
|
|
||||||
)
|
|
||||||
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
|
|||||||
@ -95,10 +95,7 @@ module.exports = {
|
|||||||
const [name, action] = handler.split('.');
|
const [name, action] = handler.split('.');
|
||||||
|
|
||||||
const controller = plugin
|
const controller = plugin
|
||||||
? _.get(
|
? _.get(strapi.plugins, `${plugin}.controllers.${_.toLower(name)}.${action}`)
|
||||||
strapi.plugins,
|
|
||||||
`${plugin}.controllers.${_.toLower(name)}.${action}`,
|
|
||||||
)
|
|
||||||
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
@ -199,10 +196,7 @@ module.exports = {
|
|||||||
const [name, action] = resolverOf.split('.');
|
const [name, action] = resolverOf.split('.');
|
||||||
|
|
||||||
const controller = plugin
|
const controller = plugin
|
||||||
? _.get(
|
? _.get(strapi.plugins, `${plugin}.controllers.${_.toLower(name)}.${action}`)
|
||||||
strapi.plugins,
|
|
||||||
`${plugin}.controllers.${_.toLower(name)}.${action}`,
|
|
||||||
)
|
|
||||||
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
: _.get(strapi.controllers, `${_.toLower(name)}.${action}`);
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
|
|||||||
@ -65,11 +65,11 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Object.assign(acc.resolver[globalId], {
|
Object.assign(acc.resolver[globalId], {
|
||||||
createdAt: (obj, options, context) => {
|
createdAt: (obj) => {
|
||||||
// eslint-disable-line no-unused-vars
|
// eslint-disable-line no-unused-vars
|
||||||
return obj.createdAt || obj.created_at;
|
return obj.createdAt || obj.created_at;
|
||||||
},
|
},
|
||||||
updatedAt: (obj, options, context) => {
|
updatedAt: (obj) => {
|
||||||
// eslint-disable-line no-unused-vars
|
// eslint-disable-line no-unused-vars
|
||||||
return obj.updatedAt || obj.updated_at;
|
return obj.updatedAt || obj.updated_at;
|
||||||
},
|
},
|
||||||
@ -154,7 +154,7 @@ module.exports = {
|
|||||||
Object.keys(queries).forEach(type => {
|
Object.keys(queries).forEach(type => {
|
||||||
// The query cannot be built.
|
// The query cannot be built.
|
||||||
if (_.isError(queries[type])) {
|
if (_.isError(queries[type])) {
|
||||||
console.error(queries[type]);
|
strapi.log.error(queries[type]);
|
||||||
strapi.stop();
|
strapi.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ module.exports = {
|
|||||||
case 'manyMorphToMany':
|
case 'manyMorphToMany':
|
||||||
case 'manyToManyMorph':
|
case 'manyToManyMorph':
|
||||||
return _.merge(acc.resolver[globalId], {
|
return _.merge(acc.resolver[globalId], {
|
||||||
[association.alias]: async (obj, options, context) => {
|
[association.alias]: async (obj) => {
|
||||||
// eslint-disable-line no-unused-vars
|
// eslint-disable-line no-unused-vars
|
||||||
const [withRelated, withoutRelated] = await Promise.all([
|
const [withRelated, withoutRelated] = await Promise.all([
|
||||||
resolvers.fetch(
|
resolvers.fetch(
|
||||||
@ -362,7 +362,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_.merge(acc.resolver[globalId], {
|
_.merge(acc.resolver[globalId], {
|
||||||
[association.alias]: async (obj, options, context) => {
|
[association.alias]: async (obj, options) => {
|
||||||
// eslint-disable-line no-unused-vars
|
// eslint-disable-line no-unused-vars
|
||||||
// Construct parameters object to retrieve the correct related entries.
|
// Construct parameters object to retrieve the correct related entries.
|
||||||
const params = {
|
const params = {
|
||||||
|
|||||||
@ -303,7 +303,7 @@ module.exports = {
|
|||||||
if (err && err.code === 'ENOENT') {
|
if (err && err.code === 'ENOENT') {
|
||||||
fs.mkdirSync(generatedFolder);
|
fs.mkdirSync(generatedFolder);
|
||||||
} else {
|
} else {
|
||||||
console.error(err);
|
strapi.log.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ const graphql = require('graphql');
|
|||||||
const GraphQLJSON = require('graphql-type-json');
|
const GraphQLJSON = require('graphql-type-json');
|
||||||
const GraphQLDateTime = require('graphql-type-datetime');
|
const GraphQLDateTime = require('graphql-type-datetime');
|
||||||
const pluralize = require('pluralize');
|
const pluralize = require('pluralize');
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
@ -212,7 +213,7 @@ module.exports = {
|
|||||||
|
|
||||||
const inputName = `${_.capitalize(name)}Input`;
|
const inputName = `${_.capitalize(name)}Input`;
|
||||||
const payloadName = `${_.capitalize(name)}Payload`;
|
const payloadName = `${_.capitalize(name)}Payload`;
|
||||||
|
/* eslint-disable indent */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'create':
|
case 'create':
|
||||||
return `
|
return `
|
||||||
@ -238,5 +239,6 @@ module.exports = {
|
|||||||
default:
|
default:
|
||||||
// Nothing
|
// Nothing
|
||||||
}
|
}
|
||||||
|
/* eslint-enable indent */
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import Button from 'components/Button';
|
|||||||
import Input from 'components/InputsIndex';
|
import Input from 'components/InputsIndex';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
|
import auth from 'utils/auth';
|
||||||
import injectSaga from 'utils/injectSaga';
|
import injectSaga from 'utils/injectSaga';
|
||||||
import injectReducer from 'utils/injectReducer';
|
import injectReducer from 'utils/injectReducer';
|
||||||
|
|
||||||
@ -40,47 +41,90 @@ import styles from './styles.scss';
|
|||||||
|
|
||||||
export class AuthPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
export class AuthPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const params = this.props.location.search ? replace(this.props.location.search, '?code=', '') : this.props.match.params.id;
|
auth.clearAppStorage();
|
||||||
this.props.setForm(this.props.match.params.authType, params);
|
this.setForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (this.props.match.params.authType !== nextProps.match.params.authType) {
|
const {
|
||||||
const params = nextProps.location.search ? replace(nextProps.location.search, '?code=', '') : nextProps.match.params.id;
|
hideLoginErrorsInput,
|
||||||
this.props.setForm(nextProps.match.params.authType, params);
|
match: {
|
||||||
this.props.hideLoginErrorsInput(false);
|
params : {
|
||||||
|
authType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
submitSuccess,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (authType !== prevProps.match.params.authType) {
|
||||||
|
this.setForm();
|
||||||
|
hideLoginErrorsInput(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextProps.submitSuccess) {
|
if (submitSuccess) {
|
||||||
switch (this.props.match.params.authType) {
|
switch (authType) {
|
||||||
case 'login':
|
case 'login':
|
||||||
case 'reset-password':
|
case 'reset-password':
|
||||||
this.props.history.push('/');
|
// Check if we have token to handle redirection to login or admin.
|
||||||
|
// Done to prevent redirection to admin after reset password if user should
|
||||||
|
// not have access.
|
||||||
|
auth.getToken()
|
||||||
|
? this.redirect('/')
|
||||||
|
: this.redirect('/plugins/users-permissions/auth/login');
|
||||||
break;
|
break;
|
||||||
case 'register':
|
case 'register':
|
||||||
this.props.history.push('/');
|
this.redirect('/');
|
||||||
// NOTE: prepare for comfirm email;
|
// NOTE: prepare for comfirm email;
|
||||||
// this.props.history.push(`/plugins/users-permissions/auth/register-success/${this.props.modifiedData.email}`);
|
// this.redirect(`/plugins/users-permissions/auth/register-success/${this.props.modifiedData.email}`);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get form Errors shortcut.
|
||||||
|
getFormErrors = () => {
|
||||||
|
const { formErrors } = this.props;
|
||||||
|
return get(formErrors, ['0', 'errors', '0', 'id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setForm = () => {
|
||||||
|
const {
|
||||||
|
location: {
|
||||||
|
search,
|
||||||
|
},
|
||||||
|
match: {
|
||||||
|
params: {
|
||||||
|
authType,
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setForm,
|
||||||
|
} = this.props;
|
||||||
|
const params = search ? replace(search, '?code=', '') : id;
|
||||||
|
|
||||||
|
setForm(authType, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isAuthType = type => {
|
||||||
|
const { match: { params: { authType } } } = this.props;
|
||||||
|
return authType === type;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = (e) => {
|
handleSubmit = (e) => {
|
||||||
|
const { modifiedData, setErrors, submit } = this.props;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formErrors = Object.keys(this.props.modifiedData).reduce((acc, key) => {
|
const formErrors = Object.keys(modifiedData).reduce((acc, key) => {
|
||||||
if (isEmpty(get(this.props.modifiedData, key)) && !isBoolean(get(this.props.modifiedData, key))) {
|
if (isEmpty(get(modifiedData, key)) && !isBoolean(get(modifiedData, key))) {
|
||||||
acc.push({ name: key, errors: [{ id: 'components.Input.error.validation.required' }] });
|
acc.push({ name: key, errors: [{ id: 'components.Input.error.validation.required' }] });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEmpty(get(this.props.modifiedData, 'password')) && !isEmpty(get(this.props.modifiedData, 'confirmPassword')) && findIndex(acc, ['name', 'confirmPassword']) === -1) {
|
if (!isEmpty(get(modifiedData, 'password')) && !isEmpty(get(modifiedData, 'confirmPassword')) && findIndex(acc, ['name', 'confirmPassword']) === -1) {
|
||||||
if (this.props.modifiedData.password.length < 6) {
|
if (modifiedData.password.length < 6) {
|
||||||
acc.push({ name: 'password', errors: [{ id: 'users-permissions.components.Input.error.password.length' }] });
|
acc.push({ name: 'password', errors: [{ id: 'users-permissions.components.Input.error.password.length' }] });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get(this.props.modifiedData, 'password') !== get(this.props.modifiedData, 'confirmPassword')) {
|
if (get(modifiedData, 'password') !== get(modifiedData, 'confirmPassword')) {
|
||||||
acc.push({ name: 'confirmPassword', errors: [{ id: 'users-permissions.components.Input.error.password.noMatch' }] });
|
acc.push({ name: 'confirmPassword', errors: [{ id: 'users-permissions.components.Input.error.password.noMatch' }] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,25 +132,27 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
|
|||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
this.props.setErrors(formErrors);
|
setErrors(formErrors);
|
||||||
|
|
||||||
if (isEmpty(formErrors)) {
|
if (isEmpty(formErrors)) {
|
||||||
this.props.submit(this.context);
|
submit(this.context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redirect = path => this.props.history.push(path);
|
||||||
|
|
||||||
renderButton = () => {
|
renderButton = () => {
|
||||||
const { match: { params: { authType } }, submitSuccess } = this.props;
|
const { match: { params: { authType } }, submitSuccess } = this.props;
|
||||||
|
|
||||||
if (this.props.match.params.authType === 'login') {
|
if (this.isAuthType('login')) {
|
||||||
return (
|
return (
|
||||||
<div className={cn('col-md-6', styles.loginButton)}>
|
<div className={cn('col-md-6', styles.loginButton)}>
|
||||||
<Button primary label="users-permissions.Auth.form.button.login" type="submit" />
|
<Button primary label="users-permissions.Auth.form.button.login" type="submit" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const isEmailForgotSent = authType === 'forgot-password' && submitSuccess;
|
const isEmailForgotSent = this.isAuthType('forgot-password') && submitSuccess;
|
||||||
const label = isEmailForgotSent ? 'users-permissions.Auth.form.button.forgot-password.success' : `users-permissions.Auth.form.button.${this.props.match.params.authType}`;
|
const label = isEmailForgotSent ? 'users-permissions.Auth.form.button.forgot-password.success' : `users-permissions.Auth.form.button.${authType}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('col-md-12', styles.buttonContainer)}>
|
<div className={cn('col-md-12', styles.buttonContainer)}>
|
||||||
@ -121,9 +167,10 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLink = () => {
|
renderLogo = () => this.isAuthType('register') && <div className={styles.logoContainer}><img src={LogoStrapi} alt="logo" /></div>;
|
||||||
|
|
||||||
if (this.props.match.params.authType === 'login') {
|
renderLink = () => {
|
||||||
|
if (this.isAuthType('login')) {
|
||||||
return (
|
return (
|
||||||
<Link to="/plugins/users-permissions/auth/forgot-password">
|
<Link to="/plugins/users-permissions/auth/forgot-password">
|
||||||
<FormattedMessage id="users-permissions.Auth.link.forgot-password" />
|
<FormattedMessage id="users-permissions.Auth.link.forgot-password" />
|
||||||
@ -131,7 +178,7 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.match.params.authType === 'forgot-password' || this.props.match.params.authType === 'register-success') {
|
if (this.isAuthType('forgot-password') || this.isAuthType('register-success')) {
|
||||||
return (
|
return (
|
||||||
<Link to="/plugins/users-permissions/auth/login">
|
<Link to="/plugins/users-permissions/auth/login">
|
||||||
<FormattedMessage id="users-permissions.Auth.link.ready" />
|
<FormattedMessage id="users-permissions.Auth.link.ready" />
|
||||||
@ -143,33 +190,53 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderInputs = () => {
|
renderInputs = () => {
|
||||||
const { match: { params: { authType } } } = this.props;
|
const {
|
||||||
const inputs = get(form, ['form', authType]);
|
didCheckErrors,
|
||||||
|
formErrors,
|
||||||
|
match: {
|
||||||
|
params: {
|
||||||
|
authType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modifiedData,
|
||||||
|
noErrorsDescription,
|
||||||
|
onChangeInput,
|
||||||
|
submitSuccess,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return map(inputs, (input, key) => (
|
const inputs = get(form, ['form', authType]);
|
||||||
|
const isForgotEmailSent = this.isAuthType('forgot-password') && submitSuccess;
|
||||||
|
return map(inputs, (input, key) => {
|
||||||
|
const label =
|
||||||
|
isForgotEmailSent
|
||||||
|
? { id: 'users-permissions.Auth.form.forgot-password.email.label.success' }
|
||||||
|
: get(input, 'label');
|
||||||
|
|
||||||
|
return (
|
||||||
<Input
|
<Input
|
||||||
autoFocus={key === 0}
|
autoFocus={key === 0}
|
||||||
customBootstrapClass={get(input, 'customBootstrapClass')}
|
customBootstrapClass={get(input, 'customBootstrapClass')}
|
||||||
didCheckErrors={this.props.didCheckErrors}
|
didCheckErrors={didCheckErrors}
|
||||||
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', input.name]), 'errors'])}
|
errors={get(formErrors, [findIndex(formErrors, ['name', input.name]), 'errors'])}
|
||||||
key={get(input, 'name')}
|
key={get(input, 'name')}
|
||||||
label={authType === 'forgot-password' && this.props.submitSuccess? { id: 'users-permissions.Auth.form.forgot-password.email.label.success' } : get(input, 'label')}
|
label={label}
|
||||||
name={get(input, 'name')}
|
name={get(input, 'name')}
|
||||||
onChange={this.props.onChangeInput}
|
onChange={onChangeInput}
|
||||||
placeholder={get(input, 'placeholder')}
|
placeholder={get(input, 'placeholder')}
|
||||||
type={get(input, 'type')}
|
type={get(input, 'type')}
|
||||||
validations={{ required: true }}
|
validations={{ required: true }}
|
||||||
value={get(this.props.modifiedData, get(input, 'name'), get(input, 'value'))}
|
value={get(modifiedData, get(input, 'name'), get(input, 'value'))}
|
||||||
noErrorsDescription={this.props.noErrorsDescription}
|
noErrorsDescription={noErrorsDescription}
|
||||||
/>
|
/>
|
||||||
));
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { match: { params: { authType } }, modifiedData, submitSuccess } = this.props;
|
const { modifiedData, noErrorsDescription, submitSuccess } = this.props;
|
||||||
let divStyle = authType === 'register' ? { marginTop: '3.2rem' } : { marginTop: '.9rem' };
|
let divStyle = this.isAuthType('register') ? { marginTop: '3.2rem' } : { marginTop: '.9rem' };
|
||||||
|
|
||||||
if (authType === 'forgot-password' && submitSuccess) {
|
if (this.isAuthType('forgot-password') && submitSuccess) {
|
||||||
divStyle = { marginTop: '.9rem', minHeight: '18.2rem' };
|
divStyle = { marginTop: '.9rem', minHeight: '18.2rem' };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,33 +244,33 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
|
|||||||
<div className={styles.authPage}>
|
<div className={styles.authPage}>
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<div className={styles.headerContainer}>
|
<div className={styles.headerContainer}>
|
||||||
{this.props.match.params.authType === 'register' ? (
|
{this.isAuthType('register') ? (
|
||||||
<FormattedMessage id="users-permissions.Auth.form.header.register" />
|
<FormattedMessage id="users-permissions.Auth.form.header.register" />
|
||||||
) : (
|
) : (
|
||||||
<img src={LogoStrapi} alt="logo" />
|
<img src={LogoStrapi} alt="logo" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.headerDescription}>
|
<div className={styles.headerDescription}>
|
||||||
{authType === 'register' && <FormattedMessage id="users-permissions.Auth.header.register.description" />}
|
{this.isAuthType('register') && <FormattedMessage id="users-permissions.Auth.header.register.description" />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
styles.formContainer,
|
styles.formContainer,
|
||||||
authType === 'forgot-password' && submitSuccess ? styles.borderedSuccess : styles.bordered,
|
this.isAuthType('forgot-password') && submitSuccess ? styles.borderedSuccess : styles.bordered,
|
||||||
)}
|
)}
|
||||||
style={divStyle}
|
style={divStyle}
|
||||||
>
|
>
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
{this.props.noErrorsDescription && !isEmpty(get(this.props.formErrors, ['0', 'errors', '0', 'id']))? (
|
{noErrorsDescription && !isEmpty(this.getFormErrors())? (
|
||||||
<div className={styles.errorsContainer}>
|
<div className={styles.errorsContainer}>
|
||||||
<FormattedMessage id={get(this.props.formErrors, ['0', 'errors', '0', 'id'])} />
|
<FormattedMessage id={this.getFormErrors()} />
|
||||||
</div>
|
</div>
|
||||||
): ''}
|
): ''}
|
||||||
<div className="row" style={{ textAlign: 'start' }}>
|
<div className="row" style={{ textAlign: 'start' }}>
|
||||||
{!submitSuccess && this.renderInputs()}
|
{!submitSuccess && this.renderInputs()}
|
||||||
{ authType === 'forgot-password' && submitSuccess && (
|
{ this.isAuthType('forgot-password') && submitSuccess && (
|
||||||
<div className={styles.forgotSuccess}>
|
<div className={styles.forgotSuccess}>
|
||||||
<FormattedMessage id="users-permissions.Auth.form.forgot-password.email.label.success" />
|
<FormattedMessage id="users-permissions.Auth.form.forgot-password.email.label.success" />
|
||||||
<br />
|
<br />
|
||||||
@ -219,7 +286,7 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
|
|||||||
{this.renderLink()}
|
{this.renderLink()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{authType === 'register' && <div className={styles.logoContainer}><img src={LogoStrapi} alt="logo" /></div>}
|
{this.renderLogo()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
import { get, includes, isArray, set, omit } from 'lodash';
|
import { get, includes, isArray, omit, set } from 'lodash';
|
||||||
import { call, fork, takeLatest, put, select } from 'redux-saga/effects';
|
import { call, fork, put, select, takeLatest } from 'redux-saga/effects';
|
||||||
import auth from 'utils/auth';
|
import auth from 'utils/auth';
|
||||||
import request from 'utils/request';
|
import request from 'utils/request';
|
||||||
|
|
||||||
import { makeSelectFormType, makeSelectModifiedData } from './selectors';
|
|
||||||
import { hideLoginErrorsInput, submitError, submitSucceeded } from './actions';
|
import { hideLoginErrorsInput, submitError, submitSucceeded } from './actions';
|
||||||
import { SUBMIT } from './constants';
|
import { SUBMIT } from './constants';
|
||||||
|
import { makeSelectFormType, makeSelectModifiedData } from './selectors';
|
||||||
|
|
||||||
export function* submitForm(action) {
|
export function* submitForm(action) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const formType = yield select(makeSelectFormType());
|
|
||||||
const body = yield select(makeSelectModifiedData());
|
const body = yield select(makeSelectModifiedData());
|
||||||
|
const formType = yield select(makeSelectFormType());
|
||||||
|
const isRegister = formType === 'register';
|
||||||
|
|
||||||
let requestURL;
|
let requestURL;
|
||||||
|
|
||||||
switch (formType) {
|
switch (formType) {
|
||||||
@ -33,12 +36,13 @@ export function* submitForm(action) {
|
|||||||
|
|
||||||
const response = yield call(request, requestURL, { method: 'POST', body: omit(body, 'news') });
|
const response = yield call(request, requestURL, { method: 'POST', body: omit(body, 'news') });
|
||||||
|
|
||||||
if (response.jwt) {
|
if(get(response, 'user.role.name', '') === 'Administrator' || isRegister){
|
||||||
|
|
||||||
yield call(auth.setToken, response.jwt, body.rememberMe);
|
yield call(auth.setToken, response.jwt, body.rememberMe);
|
||||||
yield call(auth.setUserInfo, response.user, body.rememberMe);
|
yield call(auth.setUserInfo, response.user, body.rememberMe);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formType === 'register') {
|
if (isRegister) {
|
||||||
action.context.updatePlugin('users-permissions', 'hasAdminUser', true);
|
action.context.updatePlugin('users-permissions', 'hasAdminUser', true);
|
||||||
|
|
||||||
if (body.news) {
|
if (body.news) {
|
||||||
|
|||||||
@ -13,11 +13,11 @@ module.exports = async (ctx, next) => {
|
|||||||
|
|
||||||
ctx.state.user = await strapi.query('user', 'users-permissions').findOne({ _id, id });
|
ctx.state.user = await strapi.query('user', 'users-permissions').findOne({ _id, id });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return ctx.unauthorized(err);
|
return handleErrors(ctx, err, 'unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
return ctx.unauthorized(`User Not Found.`);
|
return handleErrors(ctx, 'User Not Found', 'unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
role = ctx.state.user.role;
|
role = ctx.state.user.role;
|
||||||
@ -33,13 +33,14 @@ module.exports = async (ctx, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (_.get(await store.get({key: 'advanced'}), 'email_confirmation') && ctx.state.user.confirmed !== true) {
|
if (_.get(await store.get({key: 'advanced'}), 'email_confirmation') && ctx.state.user.confirmed !== true) {
|
||||||
return ctx.unauthorized('Your account email is not confirmed.');
|
return handleErrors(ctx, 'Your account email is not confirmed.', 'unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.state.user.blocked === true) {
|
if (ctx.state.user.blocked === true) {
|
||||||
return ctx.unauthorized(`Your account has been blocked by the administrator.`);
|
return handleErrors(ctx, 'Your account has been blocked by the administrator.', 'unauthorized');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve `public` role.
|
// Retrieve `public` role.
|
||||||
if (!role) {
|
if (!role) {
|
||||||
role = await strapi.query('role', 'users-permissions').findOne({ type: 'public' }, []);
|
role = await strapi.query('role', 'users-permissions').findOne({ type: 'public' }, []);
|
||||||
@ -55,11 +56,7 @@ module.exports = async (ctx, next) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!permission) {
|
if (!permission) {
|
||||||
if (ctx.request.graphql === null) {
|
return handleErrors(ctx, undefined, 'forbidden');
|
||||||
return ctx.request.graphql = strapi.errors.forbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.forbidden();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the policies.
|
// Execute the policies.
|
||||||
@ -70,3 +67,11 @@ module.exports = async (ctx, next) => {
|
|||||||
// Execute the action.
|
// Execute the action.
|
||||||
await next();
|
await next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleErrors = (ctx, err = undefined, type) => {
|
||||||
|
if (ctx.request.graphql === null) {
|
||||||
|
return ctx.request.graphql = strapi.errors[type](err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx[type](err);
|
||||||
|
};
|
||||||
@ -91,6 +91,8 @@ module.exports = {
|
|||||||
ctx.request.body.role = defaultRole._id || defaultRole.id;
|
ctx.request.body.role = defaultRole._id || defaultRole.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.request.body.provider = 'local';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await strapi.plugins['users-permissions'].services.user.add(ctx.request.body);
|
const data = await strapi.plugins['users-permissions'].services.user.add(ctx.request.body);
|
||||||
// Send 201 `created`
|
// Send 201 `created`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user