Resolve conflicts

This commit is contained in:
Aurelsicoko 2018-01-25 15:26:25 +01:00
commit 1ac6a56ce0
27 changed files with 666 additions and 263 deletions

View File

@ -8,4 +8,3 @@ package-lock.json
.DS_Store
npm-debug.log
.idea
manifest.json

View File

@ -1,9 +1,10 @@
.logout {
position: absolute;
position: fixed;
top: 0;
right: 0;
min-width: 19rem;
-webkit-font-smoothing: antialiased;
z-index: 999;
> div {
height: 6rem;
width: 100%;

View File

@ -1,5 +1,5 @@
.backHeader {
position: absolute;
position: fixed;
top: 0;
height: 6rem;
width: 6.5rem;

View File

@ -106,3 +106,15 @@
}
}
.descriptionContainer {
> div {
display: block;
padding-left: 15px;
padding-right: 15px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
}
}

View File

@ -53,7 +53,11 @@ class TableListRow extends React.Component { // eslint-disable-line react/prefer
<ListRow onClick={this.handleGoTo}>
<div className="col-md-1"><i className={`fa ${this.props.rowItem.icon}`} /></div>
<div className={`col-md-3 ${styles.italic} ${styles.nameContainer}`}><span style={{ width: spanStyle }}>{startCase(this.props.rowItem.name)} &nbsp;{pluginSource}</span> {temporary}</div>
<div className="col-md-5 text-center">{description}</div>
<div className={`col-md-5 text-center ${styles.descriptionContainer}`}>
<div>
{description}
</div>
</div>
<div className="col-md-2 text-center">{this.props.rowItem.fields}</div>
<div className="col-md-1">
<IcoContainer icons={icons} />

View File

@ -18,16 +18,17 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
<div className={styles.editForm}>
<div className="row">
<Input
label="users-permissions.EditForm.inputToggle.label"
inputDescription="users-permissions.EditForm.inputToggle.description"
name="uniqueAccount"
label="users-permissions.EditForm.inputToggle.label.email"
inputDescription="users-permissions.EditForm.inputToggle.description.email"
name="unique_email"
onChange={this.props.onChange}
type="toggle"
value={get(this.props.values, 'uniqueAccount')}
value={get(this.props.values, 'unique_email')}
validations={{}}
/>
</div>
<div className={styles.separator} />
{/*}
<div className="row">
<Input
customBootstrapClass="col-md-3"
@ -51,8 +52,20 @@ class EditForm extends React.Component { // eslint-disable-line react/prefer-sta
value={get(this.props.values, 'durations')}
/>
</div>
<div className={styles.separator} />
*/}
<div className="row">
<Input
label="users-permissions.EditForm.inputToggle.label.sign-up"
inputDescription="users-permissions.EditForm.inputToggle.description.sign-up"
name="allow_register"
onChange={this.props.onChange}
type="toggle"
value={get(this.props.values, 'allow_register')}
validations={{}}
/>
</div>
</div>
);
}
}

View File

@ -20,18 +20,18 @@ const links = [
name: 'users-permissions.HeaderNav.link.roles',
to: '/plugins/users-permissions/roles',
},
// {
// name: 'users-permissions.HeaderNav.link.providers',
// to: '/plugins/users-permissions/providers',
// },
// {
// name: 'users-permissions.HeaderNav.link.emailTemplates',
// to: '/plugins/users-permissions/email-templates',
// },
// {
// name: 'users-permissions.HeaderNav.link.advancedSettings',
// to: '/plugins/users-permissions/advanced-settings',
// },
{
name: 'users-permissions.HeaderNav.link.providers',
to: '/plugins/users-permissions/providers',
},
{
name: 'users-permissions.HeaderNav.link.emailTemplates',
to: '/plugins/users-permissions/email-templates',
},
{
name: 'users-permissions.HeaderNav.link.advancedSettings',
to: '/plugins/users-permissions/advanced',
},
];
function HeaderNav() {

View File

@ -48,7 +48,7 @@ const generateListTitle = (data, settingType) => {
}
};
function List({ data, deleteData, noButton, onButtonClick, settingType }) {
function List({ data, deleteData, noButton, onButtonClick, settingType, values }) {
return (
<div className={styles.list}>
<div className={styles.flex}>
@ -73,6 +73,7 @@ function List({ data, deleteData, noButton, onButtonClick, settingType }) {
item={item}
key={item.name}
settingType={settingType}
values={values}
/>
))}
</ul>
@ -92,6 +93,7 @@ List.propTypes = {
noButton: PropTypes.bool,
onButtonClick: PropTypes.func,
settingType: PropTypes.string.isRequired,
values: PropTypes.object.isRequired,
};
export default List;

View File

@ -7,6 +7,7 @@
import React from 'react';
import cn from 'classnames';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { get, includes } from 'lodash';
import { router } from 'app';
@ -14,6 +15,7 @@ import { router } from 'app';
import IcoContainer from 'components/IcoContainer';
import PopUpWarning from 'components/PopUpWarning';
import en from 'translations/en.json';
import styles from './styles.scss';
class ListRow extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -70,12 +72,14 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
</div>
);
case 'providers':
icons.pop(); // Remove the icon-trash
return (
<div className={cn('row', styles.wrapper)}>
<div className="col-md-4">
<div className={styles.flex}>
<div>
<i className={`fa fa-${this.props.item.ico}`} />
<i className={`fa fa-${this.props.item.icon}`} />
</div>
<div>
{this.props.item.name}
@ -83,7 +87,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
</div>
</div>
<div className="col-md-6" style={{ fontWeight: '500' }}>
{this.props.item.enabled ? (
{get(this.props.values, [get(this.props.item, 'name'), 'enabled']) ? (
<span style={{ color: '#5A9E06' }}>Enabled</span>
) : (
<span style={{ color: '#F64D0A' }}>Disabled</span>
@ -96,22 +100,19 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
);
case 'email-templates':
icons = [
{
icoType: 'pencil',
onClick: this.handleClick,
},
];
icons.pop();
return (
<div className={cn('row', styles.wrapper)}>
<div className="col-md-4">
<div className={styles.flex}>
<div>
<i className={`fa fa-${this.props.item.ico}`} />
<i className={`fa fa-${this.props.item.icon}`} />
</div>
<div>
{this.props.item.name}
{this.props.item.display && en[this.props.item.display] ? (
<FormattedMessage id={`users-permissions.${this.props.item.display}`} />
): this.props.item.name}
</div>
</div>
</div>
@ -136,7 +137,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
}
case 'providers':
case 'email-templates':
return router.push(`${router.location.pathname}#edit::${this.props.settingType}::${this.props.item.id}`);
return this.context.setDataToEdit(this.props.item.name);
default:
return;
}
@ -163,11 +164,16 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
}
}
ListRow.contextTypes = {
setDataToEdit: PropTypes.func.isRequired,
};
ListRow.defaultProps = {
item: {
name: 'Owner',
description: 'Rule them all. This role can\'t be deleted',
nb_users: 1,
icon: 'envelope',
},
settingType: 'roles',
};
@ -176,6 +182,7 @@ ListRow.propTypes = {
deleteData: PropTypes.func.isRequired,
item: PropTypes.object,
settingType: PropTypes.string,
values: PropTypes.object.isRequired,
};
export default ListRow;

View File

@ -8,127 +8,195 @@ import React from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { get } from 'lodash';
import { router } from 'app';
import {
capitalize,
get,
findIndex,
isArray,
isEmpty,
isObject,
includes,
map,
startsWith,
tail,
take,
takeRight,
} from 'lodash';
// Translations
import en from 'translations/en.json';
import Input from 'components/Input';
import styles from './styles.scss';
class PopUpForm extends React.Component { // eslint-disable-line react/prefer-stateless-function
toggleModal = () => router.push(router.location.pathname);
state = { enabled: false, isEditing: false };
renderButton = () => {
if (this.props.showLoader) {
return (
<Button onClick={() => {}} type="submit" className={styles.primary} disabled>
<p className={styles.saving}>
<span>.</span><span>.</span><span>.</span>
</p>
</Button>
);
getRedirectURIProviderConf = () => { // NOTE: Still testings providers so the switch statement is likely to change
switch (this.props.dataToEdit) {
case 'facebook':
return `${strapi.backendURL}/connect/facebook/callback`;
case 'github':
return get(this.props.values, 'redirect_uri', '');
default: {
const value = get(this.props.values, 'callback', '');
return startsWith(value, 'http') ? value : `${strapi.backendURL}${value}`;
}
}
return (
<Button type="submit" onClick={this.props.onSubmit} className={styles.primary}>
<FormattedMessage id="users-permissions.PopUpForm.button.save" />
</Button>
);
}
generateRedirectURL = (url) => {
return startsWith(url, 'https://') || startsWith(url, 'http://') || this.state.isEditing ? url : `${strapi.backendURL}${startsWith(url, '/') ? '' : '/'}${url}`;
}
handleChange = (e) => {
this.setState({ enabled: e.target.value });
this.props.onChange(e);
}
handleBlur = (e) => {
this.setState({ isEditing: false });
if (isEmpty(e.target.value)) {
const { name, type } = e.target;
const target = Object.assign({ name, type }, { value: `/auth/${this.props.dataToEdit}/callback` });
this.props.onChange({ target });
}
}
handleFocus = () => this.setState({ isEditing: true });
renderForm = () => {
if (this.props.settingType === 'providers') {
const { dataToEdit, settingType, values } = this.props;
const form = Object.keys(values.options || values || {}).reduce((acc, current) => {
const path = settingType === 'email-templates' ? ['options', current] : [ current ];
const name = settingType === 'email-templates' ? 'options.' : '';
if (isObject(get(values, path)) && !isArray(get(values, path))) {
return Object.keys(get(values, path, {}))
.reduce((acc, curr) => {
acc.push(`${name}${current}.${curr}`);
return acc;
}, []).concat(acc);
} else if (current !== 'icon' && current !== 'scope'){
acc.push(`${name}${current}`);
}
return acc;
}, []);
if (settingType === 'providers') {
return (
<div className="row">
<Input
autoFocus
label="users-permissions.PopUpForm.inputSelect.providers.label"
name="provider"
onChange={this.props.onChange}
selectOptions={[{ value: 'Email'}, { value: 'Facebook' }, { value: 'Google' }]}
type="select"
validations={{ required: true }}
value={get(this.props.values, 'provider')}
/>
<div className="col-md-6" />
<Input
inputDescription="users-permissions.PopUpForm.inputToggle.providers.description"
label="users-permissions.PopUpForm.inputToggle.providers.label"
name="enabled"
onChange={this.props.onChange}
inputDescription="users-permissions.PopUpForm.Providers.enabled.description"
label="users-permissions.PopUpForm.Providers.enabled.label"
name={`${dataToEdit}.enabled`}
onChange={this.handleChange}
type="toggle"
validations={{}}
value={get(this.props.values, 'enabled')}
value={get(this.props.values, 'enabled', this.state.enabled)}
/>
{form.length > 1 ? (
<div className={styles.separator} />
) : ''}
{map(tail(form), (value, key) => (
<Input
autoFocus={key === 0}
customBootstrapClass="col-md-12"
didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])}
key={value}
label={`users-permissions.PopUpForm.Providers.${ includes(value, 'callback') || includes(value, 'redirect_uri') ? 'redirectURL.front-end' : value}.label`}
name={`${dataToEdit}.${value}`}
onFocus={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.handleFocus : () => {}}
onBlur={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.handleBlur : false}
onChange={this.props.onChange}
type="text"
value={includes(value, 'callback') || includes(value, 'redirect_uri') ? this.generateRedirectURL(get(values, value)) : get(values, value)}
validations={{ required: true }}
/>
))}
{ dataToEdit !== 'email' ? (
<Input
customBootstrapClass="col-md-12"
disabled
label={`users-permissions.PopUpForm.Providers.${dataToEdit}.providerConfig.redirectURL`}
name="noName"
type="text"
onChange={() => {}}
value={this.getRedirectURIProviderConf()}
validations={{}}
/>
) : ''}
</div>
);
}
return (
<div className="row">
<Input
autoFocus
label="users-permissions.PopUpForm.inputText.shipperName.label"
name="shipperName"
onChange={this.props.onChange}
value={get(this.props.values, 'shipperName')}
placeholder="users-permissions.PopUpForm.inputText.shipperName.placeholder"
type="text"
validations={{}}
/>
<Input
label="users-permissions.PopUpForm.inputEmail.shipperEmail.label"
name="shipperEmail"
onChange={this.props.onChange}
placeholder="users-permissions.PopUpForm.inputEmail.placeholder"
type="email"
validations={{ required: true }}
value={get(this.props.values, 'shipperEmail')}
/>
<Input
label="users-permissions.PopUpForm.inputEmail.responseEmail.label"
name="responseEmail"
onChange={this.props.onChange}
placeholder="users-permissions.PopUpForm.inputEmail.placeholder"
type="email"
validations={{}}
value={get(this.props.values, 'responseEmail')}
/>
{map(take(form, 3), (value, key) => (
<Input
autoFocus={key === 0}
key={value}
didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])}
label={`users-permissions.PopUpForm.Email.${value}.label`}
name={`${dataToEdit}.${value}`}
onChange={this.props.onChange}
placeholder={`users-permissions.PopUpForm.Email.${value}.placeholder`}
type={includes(value, 'email') ? 'email' : 'text'}
value={get(values, value)}
validations={value !== 'options.response_email' ? { required: true } : {}}
/>
))}
<div className="col-md-6" />
<Input
customBootstrapClass="col-md-12"
label="users-permissions.PopUpForm.inputText.emailObject.label"
name="emailObject"
onChange={this.props.onChange}
placeholder="users-permissions.PopUpForm.inputText.emailObject.placeholder"
type="text"
validations={{}}
value={get(this.props.values, 'emailObject')}
/>
<Input
customBootstrapClass="col-md-12"
label="users-permissions.PopUpForm.inputTextArea.message.label"
name="message"
onChange={this.props.onChange}
placeholder="users-permissions.PopUpForm.inputTextArea.message.placeholder"
type="textarea"
validations={{}}
value={get(this.props.values, 'message')}
/>
{map(takeRight(form, 2), (value) => (
<Input
key={value}
customBootstrapClass="col-md-12"
didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], [])}
label={`users-permissions.PopUpForm.Email.${value}.label`}
name={`${dataToEdit}.${value}`}
inputDescription={includes(value, 'object') ? 'users-permissions.PopUpForm.Email.email_templates.inputDescription' : ''}
linkContent={includes(value, 'object') ? { link: 'https://strapi.io/documentation/plugin-development/ui-components.html', description: 'users-permissions.PopUpForm.Email.link.documentation' } : {}}
onChange={this.props.onChange}
placeholder={`users-permissions.PopUpForm.Email.${this.props.dataToEdit}.${value}.placeholder`}
type={includes(value, 'object') ? 'text' : 'textarea'}
validations={{ required: true }}
value={get(values, value)}
/>
))}
</div>
);
}
render() {
const { display } = this.props.values;
const { actionType, dataToEdit, settingType } = this.props;
let header = <span>{dataToEdit}</span>;
if (actionType) {
header = <FormattedMessage id={`users-permissions.PopUpForm.header.${actionType}.${settingType}`} values={{ provider: <i>{capitalize(dataToEdit)}</i> }} />;
}
if (display && en[display]) {
header = <FormattedMessage id={`users-permissions.${display}`} />;
}
return (
<div className={styles.popUpForm}>
<Modal isOpen={this.props.isOpen} toggle={this.toggleModal} className={`${styles.modalPosition}`}>
<ModalHeader toggle={this.toggleModal} className={styles.modalHeader} />
<Modal isOpen={this.props.isOpen} toggle={this.context.unsetDataToEdit} className={`${styles.modalPosition}`}>
<ModalHeader toggle={this.context.unsetDataToEdit} className={styles.modalHeader} />
<div className={styles.headerContainer}>
<div>
{this.props.actionType ? (
<FormattedMessage id={`users-permissions.PopUpForm.header.${this.props.actionType}.${this.props.settingType}`} />
) : <div />}
{header}
</div>
</div>
<form onSubmit={this.props.onSubmit}>
@ -138,10 +206,12 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
</div>
</ModalBody>
<ModalFooter className={styles.modalFooter}>
<Button onClick={() => router.push(router.location.pathname)} className={styles.secondary}>
<Button onClick={() => this.context.unsetDataToEdit()} className={styles.secondary}>
<FormattedMessage id="users-permissions.PopUpForm.button.cancel" />
</Button>
{this.renderButton()}
<Button type="submit" onClick={this.props.onSubmit} className={styles.primary}>
<FormattedMessage id="users-permissions.PopUpForm.button.save" />
</Button>
</ModalFooter>
</form>
</Modal>
@ -150,18 +220,25 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
}
}
PopUpForm.contextTypes = {
unsetDataToEdit: PropTypes.func.isRequired,
};
PopUpForm.defaultProps = {
settingType: 'providers',
showLoader: false,
// showLoader: false,
};
PopUpForm.propTypes = {
actionType: PropTypes.string.isRequired,
dataToEdit: PropTypes.string.isRequired,
didCheckErrors: PropTypes.bool.isRequired,
formErrors: PropTypes.array.isRequired,
isOpen: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
settingType: PropTypes.string,
showLoader: PropTypes.bool,
// showLoader: PropTypes.bool,
values: PropTypes.object.isRequired,
};

View File

@ -164,3 +164,9 @@
position: relative;
border-radius: 3px;
}
.separator {
width: 100%;
margin: 14px 15px 20px 15px;
border-bottom: 2px solid #F6F6F6;
}

View File

@ -3,17 +3,29 @@
* HomePage actions
*
*/
import { Map } from 'immutable';
import { fromJS } from 'immutable';
import { isArray } from 'lodash';
import {
CANCEL_CHANGES,
DELETE_DATA,
DELETE_DATA_SUCCEEDED,
FETCH_DATA,
FETCH_DATA_SUCCEEDED,
ON_CHANGE,
SET_DATA_TO_EDIT,
SET_FORM,
SET_FORM_ERRORS,
SUBMIT,
SUBMIT_SUCCEEDED,
UNSET_DATA_TO_EDIT,
} from './constants';
export function cancelChanges() {
return {
type: CANCEL_CHANGES,
};
}
export function deleteData(dataToDelete, deleteEndPoint) {
return {
type: DELETE_DATA,
@ -37,57 +49,72 @@ export function fetchData(endPoint) {
}
export function fetchDataSucceeded(data) {
if (!isArray(data)) {
const list = Object.keys(data).reduce((acc, current) => {
const obj = Object.assign({ name: current}, data[current]);
acc.push(obj);
return acc;
}, []);
return {
type: FETCH_DATA_SUCCEEDED,
data: list,
modifiedData: fromJS(data),
};
}
return {
type: FETCH_DATA_SUCCEEDED,
data,
modifiedData: fromJS({}),
};
}
export function onChange({ target }) {
return {
type: ON_CHANGE,
key: target.name,
keys: ['modifiedData'].concat(target.name.split('.')),
value: target.value,
};
}
export function setForm(formType) {
const form = generateForm(formType);
export function setDataToEdit(dataToEdit) {
return {
type: SET_FORM,
form,
type: SET_DATA_TO_EDIT,
dataToEdit,
};
}
// Utils
function generateForm(formType) {
let form = Map({});
switch (formType) {
case 'providers':
form = Map({
provider: 'Facebook',
enabled: false,
});
break;
case 'email-templates':
form = Map({
shipperName: '',
shipperEmail: '',
responseEmail: '',
emailObject: '',
message: '',
});
break;
case 'advanced-settings':
form = Map({
uniqueAccount: false,
subscriptions: '100',
durations: '24',
});
break;
default:
}
return form;
export function setForm(data) {
return {
type: SET_FORM,
form: fromJS(data),
};
}
export function setFormErrors(formErrors) {
return {
type: SET_FORM_ERRORS,
formErrors,
};
}
export function submit(endPoint) {
return {
type: SUBMIT,
endPoint,
};
}
export function submitSucceeded() {
return {
type: SUBMIT_SUCCEEDED,
};
}
export function unsetDataToEdit() {
return {
type: UNSET_DATA_TO_EDIT,
};
}

View File

@ -0,0 +1,39 @@
import { get, isEmpty, isObject } from 'lodash';
export default function checkFormValidity(settingType, data) {
const formErrors = [];
switch (settingType) {
case 'providers': {
const isProviderEnabled = get(data, 'enabled');
const keys = [ 'key', 'secret' ];
keys.map(key => {
if (isProviderEnabled && isEmpty(get(data, key))) {
formErrors.push({ name: key, errors: [{ id: 'components.Input.error.validation.required' }] });
}
});
break;
}
case 'email-templates': {
Object.keys(data.options).map((value) => {
if (isObject(data.options[value])) {
Object.keys(data.options[value]).map(subValue => {
if (isEmpty(get(data, ['options', value, subValue]))) {
formErrors.push({ name: `options.${value}.${subValue}`, errors: [{ id: 'components.Input.error.validation.required' }] });
}
});
}
if (value !== 'response_email' && isEmpty(get(data, ['options', value]))) {
formErrors.push({ name: `options.${value}`, errors: [{ id: 'components.Input.error.validation.required' }] });
}
});
break;
}
default:
}
return formErrors;
}

View File

@ -4,9 +4,15 @@
*
*/
export const CANCEL_CHANGES = 'UsersPermissions/HomePage/CANCEL_CHANGES';
export const DELETE_DATA = 'UsersPermissions/HomePage/DELETE_DATA';
export const DELETE_DATA_SUCCEEDED = 'UsersPermissions/HomePage/DELETE_DATA_SUCCEEDED';
export const FETCH_DATA = 'UsersPermissions/HomePage/FETCH_DATA';
export const FETCH_DATA_SUCCEEDED = 'UsersPermissions/HomePage/FETCH_DATA_SUCCEEDED';
export const ON_CHANGE = 'UsersPermissions/HomePage/ON_CHANGE';
export const SET_DATA_TO_EDIT = 'UsersPermissions/HomePage/SET_DATA_TO_EDIT';
export const SET_FORM = 'UsersPermissions/HomePage/SET_FORM';
export const SET_FORM_ERRORS = 'UsersPermissions/HomePage/SET_FORM_ERRORS';
export const SUBMIT = 'UsersPermissions/HomePage/SUBMIT';
export const SUBMIT_SUCCEEDED = 'UsersPermissions/HomePage/SUBMIT_SUCCEEDED';
export const UNSET_DATA_TO_EDIT = 'UsersPermissions/HomePage/UNSET_DATA_TO_EDIT';

View File

@ -10,7 +10,7 @@ import { connect } from 'react-redux';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import cn from 'classnames';
import { clone, includes, isEmpty, replace } from 'lodash';
import { clone, get, includes, isEqual, isEmpty } from 'lodash';
// Design
import EditForm from 'components/EditForm';
@ -31,18 +31,32 @@ import styles from './styles.scss';
// Actions
import {
cancelChanges,
deleteData,
fetchData,
onChange,
setDataToEdit,
setFormErrors,
submit,
unsetDataToEdit,
} from './actions';
import reducer from './reducer';
import saga from './saga';
import checkFormValidity from './checkFormValidity';
const keyBoardShortCuts = [18, 78];
export class HomePage extends React.Component {
state = { mapKey: {} };
state = { mapKey: {}, showModalEdit: false };
getChildContext = () => (
{
setDataToEdit: this.props.setDataToEdit,
unsetDataToEdit: this.props.unsetDataToEdit,
}
);
componentDidMount() {
this.props.fetchData(this.props.match.params.settingType);
@ -50,8 +64,14 @@ export class HomePage extends React.Component {
document.addEventListener('keyup', this.handleKeyBoardShortCut);
}
componentWillReceiveProps(nextProps) {
if (nextProps.dataToEdit !== this.props.dataToEdit) {
this.setState({ showModalEdit: !isEmpty(nextProps.dataToEdit) });
}
}
componentWillUpdate(nextProps) {
const allowedPaths = ['roles', 'providers', 'email-templates', 'advanced-settings'];
const allowedPaths = ['roles', 'providers', 'email-templates', 'advanced'];
const shouldRedirect = allowedPaths.filter(el => el === nextProps.match.params.settingType).length === 0;
if (shouldRedirect) {
@ -90,6 +110,7 @@ export class HomePage extends React.Component {
}
handleButtonClick = () => {
// TODO change open modal URL
if (this.props.match.params.settingType === 'roles') {
this.props.history.push(`${this.props.location.pathname}/create`);
} else if (this.props.match.params.settingType === 'providers') {
@ -97,44 +118,59 @@ export class HomePage extends React.Component {
}
}
handleSubmit = (e) => {
e.preventDefault();
const modifiedObject = get(this.props.modifiedData, this.props.dataToEdit);
const initObject = get(this.props.initialData, this.props.dataToEdit);
const formErrors = checkFormValidity(this.props.match.params.settingType, modifiedObject);
if (isEqual(initObject, modifiedObject)) {
return this.props.unsetDataToEdit();
}
if (isEmpty(formErrors)) {
this.setState({ showModalEdit: false });
this.props.submit(this.props.match.params.settingType);
} else {
this.props.setFormErrors(formErrors);
}
}
pluginHeaderActions = [
{
label: 'users-permissions.EditPage.cancel',
kind: 'secondary',
onClick: () => {},
onClick: () => this.props.cancelChanges(),
type: 'button',
},
{
kind: 'primary',
label: 'users-permissions.EditPage.submit',
onClick: () => {},
onClick: () => this.props.submit(this.props.match.params.settingType),
type: 'submit',
},
];
render() {
const headerActions = this.props.match.params.settingType === 'advanced-settings' && this.props.showButtons ?
const { didCheckErrors, formErrors, modifiedData, initialData, match, dataToEdit } = this.props;
const headerActions = match.params.settingType === 'advanced' && !isEqual(modifiedData, initialData) ?
this.pluginHeaderActions : [];
const noButtonList = this.props.match.params.settingType === 'email-templates';
const component = this.props.match.params.settingType === 'advanced-settings' ?
<EditForm onChange={this.props.onChange} values={this.props.modifiedData} /> : (
const noButtonList = match.params.settingType === 'email-templates' || match.params.settingType === 'providers';
const component = match.params.settingType === 'advanced' ?
<EditForm onChange={this.props.onChange} values={modifiedData} /> : (
<List
data={this.props.data}
deleteData={this.props.deleteData}
noButton={noButtonList}
onButtonClick={this.handleButtonClick}
settingType={this.props.match.params.settingType}
settingType={match.params.settingType}
values={modifiedData}
/>
);
const hashArray = replace(this.props.location.hash, '#', '').split('::');
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
}}
>
<form onSubmit={(e) => e.preventDefault()}>
<div className={cn('container-fluid', styles.containerFluid)}>
<PluginHeader
title={{ id: 'users-permissions.HomePage.header.title' }}
@ -145,14 +181,15 @@ export class HomePage extends React.Component {
{component}
</div>
<PopUpForm
actionType={hashArray[0]}
isOpen={!isEmpty(this.props.location.hash)}
actionType={'edit'}
isOpen={this.state.showModalEdit}
dataToEdit={dataToEdit}
didCheckErrors={didCheckErrors}
formErrors={formErrors}
onChange={this.props.onChange}
onSubmit={(e) => {
e.preventDefault();
}}
settingType={hashArray[1]}
values={this.props.modifiedData}
onSubmit={this.handleSubmit}
settingType={match.params.settingType}
values={modifiedData[dataToEdit] || {}}
/>
</form>
</div>
@ -160,28 +197,46 @@ export class HomePage extends React.Component {
}
}
HomePage.childContextTypes = {
setDataToEdit: PropTypes.func,
unsetDataToEdit: PropTypes.func,
};
HomePage.defaultProps = {};
HomePage.propTypes = {
cancelChanges: PropTypes.func.isRequired,
data: PropTypes.array.isRequired,
dataToEdit: PropTypes.string.isRequired,
deleteData: PropTypes.func.isRequired,
didCheckErrors: PropTypes.bool.isRequired,
didDeleteData: PropTypes.bool.isRequired,
fetchData: PropTypes.func.isRequired,
formErrors: PropTypes.array.isRequired,
history: PropTypes.object.isRequired,
initialData: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
modifiedData: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
showButtons: PropTypes.bool.isRequired,
setDataToEdit: PropTypes.func.isRequired,
setFormErrors: PropTypes.func.isRequired,
submit: PropTypes.func.isRequired,
unsetDataToEdit: PropTypes.func.isRequired,
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
cancelChanges,
deleteData,
fetchData,
onChange,
setDataToEdit,
setFormErrors,
submit,
unsetDataToEdit,
},
dispatch,
);

View File

@ -7,16 +7,22 @@
import { fromJS, List, Map } from 'immutable';
import {
CANCEL_CHANGES,
DELETE_DATA,
DELETE_DATA_SUCCEEDED,
FETCH_DATA_SUCCEEDED,
ON_CHANGE,
SET_DATA_TO_EDIT,
SET_FORM,
SET_FORM_ERRORS,
SUBMIT_SUCCEEDED,
UNSET_DATA_TO_EDIT,
} from './constants';
const initialState = fromJS({
data: List([]),
dataToDelete: Map({}),
dataToEdit: '',
deleteEndPoint: '',
initialData: Map({}),
modifiedData: Map({}),
@ -26,6 +32,10 @@ const initialState = fromJS({
function homePageReducer(state = initialState, action) {
switch (action.type) {
case CANCEL_CHANGES:
return state
.set('formErrors', List([]))
.update('modifiedData', () => state.get('initialData'));
case DELETE_DATA:
return state
.set('dataToDelete', Map(action.dataToDelete))
@ -37,15 +47,34 @@ function homePageReducer(state = initialState, action) {
.set('dataToDelete', Map({}))
.update('didDeleteData', (v) => !v);
case FETCH_DATA_SUCCEEDED:
return state.set('data', List(action.data));
return state
.set('data', List(action.data))
.set('initialData', action.modifiedData)
.set('modifiedData', action.modifiedData);
case ON_CHANGE:
return state
.updateIn(['modifiedData', action.key], () => action.value)
.set('showButtons', true);
.updateIn(action.keys, () => action.value);
case SET_DATA_TO_EDIT:
return state.update('dataToEdit', () => action.dataToEdit);
case SET_FORM:
return state
.set('formErrors', List([]))
.set('initialData', action.form)
.set('modifiedData', action.form);
case SET_FORM_ERRORS:
return state
.update('didCheckErrors', (v) => v = !v)
.set('formErrors', List(action.formErrors));
case SUBMIT_SUCCEEDED:
return state
.set('formErrors', List([]))
.update('dataToEdit', () => '')
.update('initialData', () => state.get('modifiedData'));
case UNSET_DATA_TO_EDIT:
return state
.set('formErrors', List([]))
.update('dataToEdit', () => '')
.update('modifiedData', () => state.get('initialData'));
default:
return state;
}

View File

@ -8,11 +8,13 @@ import {
deleteDataSucceeded,
fetchDataSucceeded,
setForm,
submitSucceeded,
} from './actions';
import {
DELETE_DATA,
FETCH_DATA,
SUBMIT,
} from './constants';
// TODO uncomment to test design providers and so on...
@ -22,6 +24,7 @@ import {
makeSelectAllData,
makeSelectDataToDelete,
makeSelectDeleteEndPoint,
makeSelectModifiedData,
} from './selectors';
export function* dataDelete() {
@ -50,22 +53,36 @@ export function* dataFetch(action) {
try {
const response = yield call(request, `/users-permissions/${action.endPoint}`, { method: 'GET' });
yield put(fetchDataSucceeded(response[action.endPoint]));
// To test other views
// const response = data[action.endPoint];
// yield put(fetchDataSucceeded(response));
yield put(setForm(action.endPoint));
if (action.endPoint === 'advanced') {
yield put(setForm(response));
} else {
const data = response[action.endPoint] || response;
yield put(fetchDataSucceeded(data));
}
} catch(err) {
console.log(err);
strapi.notification.error('users-permissions.notification.error.fetch');
}
}
export function* submitData(action) {
try {
const body = yield select(makeSelectModifiedData());
const opts = { method: 'PUT', body };
yield call(request, `/users-permissions/${action.endPoint}`, opts, true);
yield put(submitSucceeded());
} catch(error) {
strapi.notification.error('notification.error');
}
}
// Individual exports for testing
export function* defaultSaga() {
const loadDataWatcher = yield fork(takeLatest, FETCH_DATA, dataFetch);
yield fork(takeLatest, DELETE_DATA, dataDelete);
yield fork(takeLatest, SUBMIT, submitData);
yield take(LOCATION_CHANGE);
yield cancel(loadDataWatcher);
}

View File

@ -34,10 +34,15 @@ const makeSelectDeleteEndPoint = () => createSelector(
(substate) => substate.get('deleteEndPoint'),
);
export default selectHomePage;
const makeSelectModifiedData = () => createSelector(
selectHomePageDomain(),
(substate) => substate.get('modifiedData').toJS(),
);
export default selectHomePage;
export {
makeSelectAllData,
makeSelectDataToDelete,
makeSelectDeleteEndPoint,
makeSelectModifiedData,
};

View File

@ -60,8 +60,10 @@
"EditForm.inputSelect.durations.label": "Duration",
"EditForm.inputSelect.durations.description": "Number of hours during the user can't subscribe.",
"EditForm.inputToggle.label": "One account per email addres",
"EditForm.inputToggle.description": "Disallow the user to create multiple accounts using the same email address with different authentication providers.",
"EditForm.inputToggle.label.email": "One account per email addres",
"EditForm.inputToggle.label.sign-up": "Enable sign-up",
"EditForm.inputToggle.description.email": "Disallow the user to create multiple accounts using the same email address with different authentication providers.",
"EditForm.inputToggle.description.sign-up": "When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.",
"EditPage.cancel": "Cancel",
"EditPage.submit": "Save",
@ -123,9 +125,9 @@
"Policies.header.hint": "Select the application's actions or the plugin's actions and click on the cog icon to display the bounded route",
"Policies.header.title": "Advanced settings",
"Email.template.validation_email": "",
"Email.template.reset_password": "",
"Email.template.success_register": "",
"Email.template.validation_email": "Email address validation",
"Email.template.reset_password": "Reset password",
"Email.template.success_register": "Successfull registration",
"Auth.advanced.allow_register": "",
@ -133,17 +135,39 @@
"PopUpForm.button.save": "Save",
"PopUpForm.header.add.providers": "Add New Provider",
"PopUpForm.header.edit.email-templates": "Edit Email Templates",
"PopUpForm.header.edit.providers": "Edit Provider",
"PopUpForm.header.edit.providers": "Edit {provider} Provider",
"PopUpForm.inputSelect.providers.label": "Choose the provider",
"PopUpForm.inputToggle.providers.label": "Enable",
"PopUpForm.inputToggle.providers.description": "If disabled, the users won't be able to use this provider.",
"PopUpForm.inputText.shipperName.label": "Shipper name",
"PopUpForm.inputEmail.shipperEmail.label": "Shipper email",
"PopUpForm.inputEmail.responseEmail.label": "Response email",
"PopUpForm.inputText.emailObject.label": "Object",
"PopUpForm.inputText.emailObject.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.inputTextArea.message.label": "Message",
"PopUpForm.inputTextArea.message.placeholder": "<p>Please click on this link to validate your account</p>",
"PopUpForm.inputEmail.placeholder": "johndoe@gmail.com",
"PopUpForm.inputText.shipperName.placeholder": "John Doe"
"PopUpForm.Email.options.from.name.label": "Shipper name",
"PopUpForm.Email.options.from.email.label": "Shipper email",
"PopUpForm.Email.options.response_email.label": "Response email",
"PopUpForm.Email.options.object.label": "Object",
"PopUpForm.Email.options.message.label": "Message",
"PopUpForm.Email.validation_email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.reset_password.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.success_register.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.validation_email.options.message.placeholder": "<p>Please click on this link to validate your account</p>",
"PopUpForm.Email.reset_password.options.message.placeholder": "<p>Please click on this link to validate your account</p>",
"PopUpForm.Email.success_register.options.message.placeholder": "<p>Please click on this link to validate your account</p>",
"PopUpForm.Email.options.from.email.placeholder": "johndoe@gmail.com",
"PopUpForm.Email.options.response_email.placeholder": "johndoe@gmail.com",
"PopUpForm.Email.options.from.name.placeholder": "John Doe",
"PopUpForm.Providers.enabled.label": "Enable",
"PopUpForm.Providers.enabled.description": "If disabled, the users won't be able to use this provider.",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "The redirect URL to your front-end app",
"PopUpForm.Providers.facebook.providerConfig.redirectURL": "The redirect URL to add in your Facebook application configurations",
"PopUpForm.Providers.google.providerConfig.redirectURL": "The redirect URL to add in your Google application configurations",
"PopUpForm.Providers.github.providerConfig.redirectURL": "The redirect URL to add in your GitHub application configurations",
"PopUpForm.Providers.linkedin2.providerConfig.redirectURL": "The redirect URL to add in your Linkedin application configurations",
"PopUpForm.Providers.twitter.providerConfig.redirectURL": "The redirect URL to add in your Twitter application configurations",
"PopUpForm.Providers.callback.placeholder": "TEXT",
"PopUpForm.Email.email_templates.inputDescription": "Don't know to set variables",
"PopUpForm.Email.link.documentation": "check out our documentation"
}

View File

@ -60,7 +60,9 @@
"EditForm.inputSelect.durations.description": "Nombre d'heure pendant lesquelles un utilisateur ne peut souscrire.",
"EditForm.inputToggle.label": "Un compte par adresse email",
"EditForm.inputToggle.description": "Interdire l'utilisateur de créer de multiple comptes avec la même adresse email avec des providers différents",
"EditForm.inputToggle.label.sign-up": "Activer l'inscription",
"EditForm.inputToggle.description.email": "Interdire l'utilisateur de créer de multiple comptes avec la même adresse email avec des providers différents",
"EditForm.inputToggle.description.sign-up": "Quand l'inscription est désactivée (OFF), aucun utilisateur ne peut s'inscrire qu'importe le provider",
"EditPage.cancel": "Cancel",
"EditPage.submit": "Sauvegarder",
@ -123,27 +125,48 @@
"Policies.header.hint": "Sélectionnez les actions de l'application ou d'un plugin et cliquer sur l'icon de paramètres pour voir les routes associées à cette action",
"Policies.header.title": "Paramètres avancés",
"Email.template.validation_email": "",
"Email.template.reset_password": "",
"Email.template.success_register": "",
"Email.template.validation_email": "Email de validation d'adresse",
"Email.template.reset_password": "Modification de mot de passe",
"Email.template.success_register": "Inscription réussie",
"Auth.advanced.allow_register": "",
"popUpForm.button.cancel": "Annuler",
"popUpForm.button.save": "Sauvegarder",
"popUpForm.header.add.providers": "Ajouter un Nouveau Provider",
"popUpForm.header.edit.email-templates": "Editer Email Templates",
"popUpForm.header.edit.providers": "Editer Le Provider",
"popUpForm.inputSelect.providers.label": "Sélectionnez le provider",
"popUpForm.inputToggle.providers.label": "Activer",
"popUpForm.inputToggle.providers.description": "S'il est désactivé les utilisateurs ne pourront pas utiliser ce provider.",
"popUpForm.inputText.shipperName.label": "Nom de l'envoyeur",
"popUpForm.inputEmail.shipperEmail.label": "Email de l'envoyeur",
"popUpForm.inputEmail.responseEmail.label": "Email de réponse",
"popUpForm.inputText.emailObject.label": "Objet",
"popUpForm.inputText.emailObject.placeholder": "Merci de confirmer votre adresse email pour %APP_NAME%",
"popUpForm.inputTextArea.message.label": "Message",
"popUpForm.inputTextArea.message.placeholder": "<p>Merci de cliquer sur ce lien pour valider votre compte</p>",
"popUpForm.inputEmail.placeholder": "arthurdupont@gmail.com",
"popUpForm.inputText.shipperName.placeholder": "Arthur Dupont"
"PopUpForm.button.cancel": "Annuler",
"PopUpForm.button.save": "Sauvegarder",
"PopUpForm.header.add.providers": "Ajouter un Nouveau Provider",
"PopUpForm.header.edit.email-templates": "Editer Email Templates",
"PopUpForm.header.edit.providers": "Editer {provider} Provider",
"PopUpForm.inputSelect.providers.label": "Sélectionnez le provider",
"PopUpForm.Email.options.from.name.label": "Nom de l'envoyeur",
"PopUpForm.Email.options.from.email.label": "Email de l'envoyeur",
"PopUpForm.Email.options.response_email.label": "Email de réponse",
"PopUpForm.Email.options.object.label": "Objet",
"PopUpForm.Email.validation_email.options.object.placeholder": "Merci de confirmer votre adresse email pour %APP_NAME%",
"PopUpForm.Email.success_register.options.object.placeholder": "Merci de confirmer votre adresse email pour %APP_NAME%",
"PopUpForm.Email.reset_password.options.object.placeholder": "Merci de confirmer votre adresse email pour %APP_NAME%",
"PopUpForm.Email.options.message.label": "Message",
"PopUpForm.Email.validation_email.options.message.placeholder": "<p>Merci de cliquer sur ce lien pour valider votre compte</p>",
"PopUpForm.Email.success_register.options.message.placeholder": "<p>Merci de cliquer sur ce lien pour valider votre compte</p>",
"PopUpForm.Email.reset_password.options.message.placeholder": "<p>Merci de cliquer sur ce lien pour valider votre compte</p>",
"PopUpForm.Email.options.from.email.placeholder": "arthurdupont@gmail.com",
"PopUpForm.Email.options.response_email.placeholder": "arthurdupont@gmail.com",
"PopUpForm.Email.options.from.name.placeholder": "Arthur Dupont",
"PopUpForm.Providers.enabled.label": "Activer",
"PopUpForm.Providers.enabled.description": "S'il est désactivé les utilisateurs ne pourront pas utiliser ce provider.",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "L'URL de redirection de votre app front-end",
"PopUpForm.Providers.facebook.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations Facebook de votre application",
"PopUpForm.Providers.google.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations Google de votre application",
"PopUpForm.Providers.github.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations GitHub de votre application",
"PopUpForm.Providers.linkedin2.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations Linkedin de votre application",
"PopUpForm.Providers.twitter.providerConfig.redirectURL": "L'URL de redirection à ajouter dans les configurations Twitter de votre application",
"PopUpForm.Providers.callback.placeholder": "TEXT",
"PopUpForm.Email.email_templates.inputDescription": "Regardez la documentation des variables",
"PopUpForm.Email.link.documentation": "afin de templeter vos emails"
}

View File

@ -0,0 +1,6 @@
{
"advanced": {
"unique_email": true,
"allow_register": true
}
}

View File

@ -31,11 +31,13 @@ module.exports = cb => {
if (!_.get(strapi.plugins['users-permissions'], 'config.grant')) {
try {
const grant = {
local: {
enabled: true
email: {
enabled: true,
icon: 'envelope'
},
facebook: {
enabled: false,
icon: 'facebook-official',
key: '',
secret: '',
callback: '/auth/facebook/callback',
@ -43,6 +45,7 @@ module.exports = cb => {
},
google: {
enabled: false,
icon: 'google',
key: '',
secret: '',
callback: '/auth/google/callback',
@ -50,9 +53,10 @@ module.exports = cb => {
},
github: {
enabled: false,
icon: 'github',
key: '',
secret: '',
redirect_uri: '/auth/google/callback',
redirect_uri: '/auth/github/callback',
scope: [
'user',
'user:email'
@ -60,6 +64,7 @@ module.exports = cb => {
},
twitter: {
enabled: false,
icon: 'twitter',
key: '',
secret: '',
callback: '/auth/twitter/callback'
@ -84,10 +89,10 @@ module.exports = cb => {
icon: 'envelope',
options: {
from: {
email: '',
name: ''
name: 'Administration Panel',
email: 'no-reply@strapi.io'
},
respond: '',
response_email: '',
object: '',
message: ''
}
@ -97,10 +102,10 @@ module.exports = cb => {
icon: 'refresh',
options: {
from: {
email: '',
name: ''
name: 'Administration Panel',
email: 'no-reply@strapi.io'
},
respond: '',
response_email: '',
object: '­Reset password 🔑 ',
message: `<p>We heard that you lost your password. Sorry about that!</p>
@ -116,10 +121,10 @@ module.exports = cb => {
icon: 'check',
options: {
from: {
email: '',
name: ''
name: 'Administration Panel',
email: 'no-reply@strapi.io'
},
respond: '',
response_email: '',
object: '',
message: ''
}

View File

@ -66,7 +66,7 @@
},
{
"method": "GET",
"path": "/email-template",
"path": "/email-templates",
"handler": "UsersPermissions.getEmailTemplate",
"config": {
"policies": []
@ -74,7 +74,7 @@
},
{
"method": "PUT",
"path": "/email-template",
"path": "/email-templates",
"handler": "UsersPermissions.updateEmailTemplate",
"config": {
"policies": []
@ -96,6 +96,23 @@
"policies": []
}
},
{
"method": "GET",
"path": "/providers",
"handler": "UsersPermissions.getProviders",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/providers",
"handler": "UsersPermissions.updateProviders",
"config": {
"policies": []
}
},
{

View File

@ -17,7 +17,7 @@ module.exports = {
const params = ctx.request.body;
if (provider === 'local') {
if (!_.get(strapi.plugins['users-permissions'].config.grant[provider], 'enabled') && !ctx.request.admin) {
if (!_.get(strapi.plugins['users-permissions'].config.grant['email'], 'enabled') && !ctx.request.admin) {
return ctx.badRequest(null, 'This provider is disabled.');
}
@ -71,9 +71,9 @@ module.exports = {
}
} else {
// Connect the user thanks to the third-party provider.
const [user, error] = await strapi.plugins['users-permissions'].services.providers.connect(provider, ctx.query);
if (error) {
try {
const [user, error] = await strapi.plugins['users-permissions'].services.providers.connect(provider, ctx.query);
} catch([user, error]) {
return ctx.badRequest(null, (error === 'array') ? (ctx.request.admin ? error[0] : error[1]) : error);
}
@ -167,7 +167,7 @@ module.exports = {
await strapi.plugins['email'].services.email.send({
to: user.email,
from: (settings.from.email || settings.from.name) ? `"${settings.from.name}" <${settings.from.email}>` : undefined,
replyTo: settings.respond,
replyTo: settings.response_email,
subject: settings.object,
text: settings.message,
html: settings.message

View File

@ -179,13 +179,15 @@ module.exports = {
return ctx.badRequest(null, [{ messages: [{ id: 'Cannot be empty' }] }]);
}
strapi.plugins['users-permissions'].config.email = ctx.request.body;
strapi.reload.isWatching = false;
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'email.json'), JSON.stringify({
email: strapi.plugins['users-permissions'].config.email
email: ctx.request.body
}, null, 2), 'utf8');
return ctx.send({ ok: true });
ctx.send({ ok: true });
strapi.reload();
},
getAdvancedSettings: async (ctx) => {
@ -197,12 +199,35 @@ module.exports = {
return ctx.badRequest(null, [{ messages: [{ id: 'Cannot be empty' }] }]);
}
strapi.plugins['users-permissions'].config.advanced = ctx.request.body;
strapi.reload.isWatching = false;
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'advanced.json'), JSON.stringify({
email: strapi.plugins['users-permissions'].config.advanced
advanced: ctx.request.body
}, null, 2), 'utf8');
return ctx.send({ ok: true });
ctx.send({ ok: true });
strapi.reload();
},
getProviders: async (ctx) => {
ctx.send(strapi.plugins['users-permissions'].config.grant);
},
updateProviders: async (ctx) => {
if (_.isEmpty(ctx.request.body)) {
return ctx.badRequest(null, [{ messages: [{ id: 'Cannot be empty' }] }]);
}
strapi.reload.isWatching = false;
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'grant.json'), JSON.stringify({
grant: ctx.request.body
}, null, 2), 'utf8');
ctx.send({ ok: true });
strapi.reload();
}
};

View File

@ -0,0 +1,3 @@
# Templating emails
Documentation in progress....

View File

@ -63,8 +63,8 @@ exports.connect = (provider, query) => {
return reject([{
message: 'Email was not available.'
}, null]);
}
}
try {
const user = await strapi.query('user', 'users-permissions').findOne({email: profile.email});
@ -83,7 +83,8 @@ exports.connect = (provider, query) => {
if (!user || _.get(user, 'provider') !== provider) {
// Create the new user.
const params = _.assign(profile, {
provider: provider
provider: provider,
role: '1'
});
const createdUser = await strapi.query('user', 'users-permissions').create(params);