mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-26 16:52:06 +05:30
#26: forgot/restore password frontend logic
This commit is contained in:
parent
a584ef0d95
commit
3472c7b29f
@ -28,7 +28,7 @@
|
||||
"react-motion": "^0.4.0",
|
||||
"react-redux": "^4.0.0",
|
||||
"react-router": "^2.0.0",
|
||||
"react-router-redux": "^2.1.0",
|
||||
"react-router-redux": "^3.0.0",
|
||||
"redux": "^3.0.4",
|
||||
"redux-thunk": "^1.0.0",
|
||||
"whatwg-fetch": "^0.11.0"
|
||||
|
@ -219,7 +219,8 @@ class PanelTransition extends Component {
|
||||
activation: fromRight,
|
||||
permissions: fromLeft,
|
||||
changePassword: fromRight,
|
||||
forgotPassword: fromRight
|
||||
forgotPassword: [panelId, prevPanelId].includes('recoverPassword') ? fromLeft : fromRight,
|
||||
recoverPassword: fromRight
|
||||
};
|
||||
const sign = map[key];
|
||||
const transform = sign * 100;
|
||||
@ -240,7 +241,8 @@ class PanelTransition extends Component {
|
||||
activation: not('register') ? 'Y' : 'X',
|
||||
permissions: 'Y',
|
||||
changePassword: 'Y',
|
||||
forgotPassword: not('password') && not('login') ? 'Y' : 'X'
|
||||
forgotPassword: not('password') && not('login') ? 'Y' : 'X',
|
||||
recoverPassword: not('password') && not('login') && not('forgotPassword') ? 'Y' : 'X'
|
||||
};
|
||||
|
||||
return map[next];
|
||||
|
@ -33,12 +33,9 @@ export function login({login = '', password = '', rememberMe = false}) {
|
||||
if (resp.errors.login === LOGIN_REQUIRED && password) {
|
||||
dispatch(logout());
|
||||
}
|
||||
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
|
||||
dispatch(setError(errorMessage));
|
||||
return Promise.reject(errorMessage);
|
||||
}
|
||||
|
||||
// TODO: log unexpected errors
|
||||
return validationErrorsHandler(dispatch)(resp);
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -50,15 +47,44 @@ export function changePassword({
|
||||
}) {
|
||||
return wrapInLoader((dispatch) =>
|
||||
dispatch(changeUserPassword({password, newPassword, newRePassword, logoutAll : false}))
|
||||
.catch((resp) => {
|
||||
if (resp.errors) {
|
||||
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
|
||||
dispatch(setError(errorMessage));
|
||||
return Promise.reject(errorMessage);
|
||||
}
|
||||
.catch(validationErrorsHandler(dispatch))
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: log unexpected errors
|
||||
})
|
||||
export function forgotPassword({
|
||||
login = ''
|
||||
}) {
|
||||
return wrapInLoader((dispatch, getState) =>
|
||||
request.post(
|
||||
'/api/authentication/forgot-password',
|
||||
{login}
|
||||
)
|
||||
.then(({data = {}}) => dispatch(updateUser({
|
||||
maskedEmail: data.emailMask || getState().user.email
|
||||
})))
|
||||
.catch(validationErrorsHandler(dispatch))
|
||||
);
|
||||
}
|
||||
|
||||
export function recoverPassword({
|
||||
key = '',
|
||||
newPassword = '',
|
||||
newRePassword = ''
|
||||
}) {
|
||||
return wrapInLoader((dispatch) =>
|
||||
request.post(
|
||||
'/api/authentication/recover-password',
|
||||
{key, newPassword, newRePassword}
|
||||
)
|
||||
.then((resp) => {
|
||||
dispatch(updateUser({
|
||||
isGuest: false,
|
||||
isActive: true
|
||||
}));
|
||||
|
||||
return dispatch(authenticate(resp.jwt));
|
||||
})
|
||||
.catch(validationErrorsHandler(dispatch))
|
||||
);
|
||||
}
|
||||
|
||||
@ -82,18 +108,7 @@ export function register({
|
||||
dispatch(needActivation());
|
||||
dispatch(routeActions.push('/activation'));
|
||||
})
|
||||
.catch((resp) => {
|
||||
if (resp.errors) {
|
||||
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
|
||||
dispatch(setError(errorMessage));
|
||||
return Promise.reject(errorMessage);
|
||||
}
|
||||
|
||||
// TODO: log unexpected errors
|
||||
// We can get here something like:
|
||||
// code: 500
|
||||
// {"name":"Invalid Configuration","message":"","code":0,"type":"yii\\base\\InvalidConfigException","file":"/home/sleepwalker/www/account/api/components/ReCaptcha/Component.php","line":12,"stack-trace":["#0 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Object.php(107): api\\components\\ReCaptcha\\Component->init()","#1 [internal function]: yii\\base\\Object->__construct(Array)","#2 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(368): ReflectionClass->newInstanceArgs(Array)","#3 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(153): yii\\di\\Container->build('api\\\\components\\\\...', Array, Array)","#4 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/BaseYii.php(344): yii\\di\\Container->get('api\\\\components\\\\...', Array, Array)","#5 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/ServiceLocator.php(133): yii\\BaseYii::createObject(Array)","#6 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/ServiceLocator.php(71): yii\\di\\ServiceLocator->get('reCaptcha')","#7 /home/sleepwalker/www/account/api/components/ReCaptcha/Validator.php(20): yii\\di\\ServiceLocator->__get('reCaptcha')","#8 /home/sleepwalker/www/account/api/components/ReCaptcha/Validator.php(25): api\\components\\ReCaptcha\\Validator->getComponent()","#9 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Object.php(107): api\\components\\ReCaptcha\\Validator->init()","#10 [internal function]: yii\\base\\Object->__construct(Array)","#11 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(374): ReflectionClass->newInstanceArgs(Array)","#12 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(153): yii\\di\\Container->build('api\\\\components\\\\...', Array, Array)","#13 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/BaseYii.php(344): yii\\di\\Container->get('api\\\\components\\\\...', Array, Array)","#14 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/validators/Validator.php(209): yii\\BaseYii::createObject(Array)","#15 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(445): yii\\validators\\Validator::createValidator('api\\\\components\\\\...', Object(api\\models\\RegistrationForm), Array, Array)","#16 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(409): yii\\base\\Model->createValidators()","#17 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(185): yii\\base\\Model->getValidators()","#18 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(751): yii\\base\\Model->scenarios()","#19 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(695): yii\\base\\Model->safeAttributes()","#20 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(823): yii\\base\\Model->setAttributes(Array)","#21 /home/sleepwalker/www/account/api/controllers/SignupController.php(41): yii\\base\\Model->load(Array)","#22 [internal function]: api\\controllers\\SignupController->actionIndex()","#23 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/InlineAction.php(55): call_user_func_array(Array, Array)","#24 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Controller.php(154): yii\\base\\InlineAction->runWithParams(Array)","#25 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Module.php(454): yii\\base\\Controller->runAction('', Array)","#26 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/web/Application.php(84): yii\\base\\Module->runAction('signup', Array)","#27 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Application.php(375): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))","#28 /home/sleepwalker/www/account/api/web/index.php(18): yii\\base\\Application->run()","#29 {main}"]}
|
||||
})
|
||||
.catch(validationErrorsHandler(dispatch))
|
||||
);
|
||||
}
|
||||
|
||||
@ -111,13 +126,7 @@ export function activate({key = ''}) {
|
||||
|
||||
return dispatch(authenticate(resp.jwt));
|
||||
})
|
||||
.catch((resp) => {
|
||||
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
|
||||
dispatch(setError(errorMessage));
|
||||
return Promise.reject(errorMessage);
|
||||
|
||||
// TODO: log unexpected errors
|
||||
})
|
||||
.catch(validationErrorsHandler(dispatch))
|
||||
);
|
||||
}
|
||||
|
||||
@ -322,3 +331,21 @@ function needActivation() {
|
||||
isGuest: false
|
||||
});
|
||||
}
|
||||
|
||||
function validationErrorsHandler(dispatch) {
|
||||
return (resp) => {
|
||||
if (resp.errors) {
|
||||
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
|
||||
dispatch(setError(errorMessage));
|
||||
return Promise.reject(errorMessage);
|
||||
}
|
||||
|
||||
return Promise.reject(resp);
|
||||
|
||||
// TODO: log unexpected errors
|
||||
// We can get here something like:
|
||||
// code: 500
|
||||
// {"name":"Invalid Configuration","message":"","code":0,"type":"yii\\base\\InvalidConfigException","file":"/home/sleepwalker/www/account/api/components/ReCaptcha/Component.php","line":12,"stack-trace":["#0 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Object.php(107): api\\components\\ReCaptcha\\Component->init()","#1 [internal function]: yii\\base\\Object->__construct(Array)","#2 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(368): ReflectionClass->newInstanceArgs(Array)","#3 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(153): yii\\di\\Container->build('api\\\\components\\\\...', Array, Array)","#4 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/BaseYii.php(344): yii\\di\\Container->get('api\\\\components\\\\...', Array, Array)","#5 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/ServiceLocator.php(133): yii\\BaseYii::createObject(Array)","#6 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/ServiceLocator.php(71): yii\\di\\ServiceLocator->get('reCaptcha')","#7 /home/sleepwalker/www/account/api/components/ReCaptcha/Validator.php(20): yii\\di\\ServiceLocator->__get('reCaptcha')","#8 /home/sleepwalker/www/account/api/components/ReCaptcha/Validator.php(25): api\\components\\ReCaptcha\\Validator->getComponent()","#9 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Object.php(107): api\\components\\ReCaptcha\\Validator->init()","#10 [internal function]: yii\\base\\Object->__construct(Array)","#11 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(374): ReflectionClass->newInstanceArgs(Array)","#12 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/di/Container.php(153): yii\\di\\Container->build('api\\\\components\\\\...', Array, Array)","#13 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/BaseYii.php(344): yii\\di\\Container->get('api\\\\components\\\\...', Array, Array)","#14 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/validators/Validator.php(209): yii\\BaseYii::createObject(Array)","#15 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(445): yii\\validators\\Validator::createValidator('api\\\\components\\\\...', Object(api\\models\\RegistrationForm), Array, Array)","#16 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(409): yii\\base\\Model->createValidators()","#17 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(185): yii\\base\\Model->getValidators()","#18 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(751): yii\\base\\Model->scenarios()","#19 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(695): yii\\base\\Model->safeAttributes()","#20 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Model.php(823): yii\\base\\Model->setAttributes(Array)","#21 /home/sleepwalker/www/account/api/controllers/SignupController.php(41): yii\\base\\Model->load(Array)","#22 [internal function]: api\\controllers\\SignupController->actionIndex()","#23 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/InlineAction.php(55): call_user_func_array(Array, Array)","#24 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Controller.php(154): yii\\base\\InlineAction->runWithParams(Array)","#25 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Module.php(454): yii\\base\\Controller->runAction('', Array)","#26 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/web/Application.php(84): yii\\base\\Module->runAction('signup', Array)","#27 /home/sleepwalker/www/ely/vendor/yiisoft/yii2/base/Application.php(375): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))","#28 /home/sleepwalker/www/account/api/web/index.php(18): yii\\base\\Application->run()","#29 {main}"]}
|
||||
// We need here status code. Probably `request` module should add _request field en each resp
|
||||
};
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ export default class ActivationBody extends BaseAuthBody {
|
||||
<div className={styles.formRow}>
|
||||
<Input {...this.bindField('key')}
|
||||
color="blue"
|
||||
className={styles.activationCodeInput}
|
||||
style={{textAlign: 'center'}}
|
||||
required
|
||||
placeholder={messages.enterTheCode}
|
||||
/>
|
||||
|
@ -17,10 +17,3 @@
|
||||
line-height: 1.4;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.activationCodeInput {
|
||||
composes: darkTextField from 'components/ui/form/form.scss';
|
||||
composes: blueTextField from 'components/ui/form/form.scss';
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"forgotPasswordTitle": "Forgot password",
|
||||
"contactSupport": "Contact support",
|
||||
"title": "Forgot password",
|
||||
"sendMail": "Send mail",
|
||||
"forgotPasswordMessage": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"accountEmail": "Enter account E-mail"
|
||||
"specifyEmail": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"pleasePressButton": "Please press the button bellow to get an email with password recovery code.",
|
||||
"alreadyHaveCode": "Already have a code"
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ import Body from './ForgotPasswordBody';
|
||||
|
||||
export default function ForgotPassword() {
|
||||
return {
|
||||
Title: () => <AuthTitle title={messages.forgotPasswordTitle} />,
|
||||
Title: () => <AuthTitle title={messages.title} />,
|
||||
Body,
|
||||
Footer: () => <Button color="lightViolet" label={messages.sendMail} />,
|
||||
Links: () => <RejectionLink label={messages.contactSupport} />
|
||||
Footer: () => <Button color="lightViolet" autoFocus label={messages.sendMail} />,
|
||||
Links: () => <RejectionLink label={messages.alreadyHaveCode} />
|
||||
};
|
||||
}
|
||||
|
@ -13,27 +13,29 @@ export default class ForgotPasswordBody extends BaseAuthBody {
|
||||
static panelId = 'forgotPassword';
|
||||
static hasGoBack = true;
|
||||
|
||||
autoFocusField = 'email';
|
||||
|
||||
// Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить?
|
||||
render() {
|
||||
const {user} = this.context;
|
||||
const hasIdentity = user.email || user.username;
|
||||
const message = hasIdentity ? messages.pleasePressButton : messages.specifyEmail;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{this.renderErrors()}
|
||||
|
||||
<p className={styles.descriptionText}>
|
||||
<Message {...messages.forgotPasswordMessage} />
|
||||
<Message {...message} />
|
||||
</p>
|
||||
|
||||
<Input {...this.bindField('email')}
|
||||
icon="envelope"
|
||||
color="lightViolet"
|
||||
required
|
||||
placeholder={messages.accountEmail}
|
||||
defaultValue={user.email || user.username || ''}
|
||||
/>
|
||||
{hasIdentity ? null : (
|
||||
<Input {...this.bindField('email')}
|
||||
icon="envelope"
|
||||
color="lightViolet"
|
||||
required
|
||||
placeholder={messages.accountEmail}
|
||||
defaultValue={user.email || user.username}
|
||||
/>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
|
||||
import icons from 'components/ui/icons.scss';
|
||||
import { Input, Checkbox } from 'components/ui/form';
|
||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "Restore password",
|
||||
"contactSupport": "Contact support",
|
||||
"messageWasSentTo": "The recovery code was sent to your email {email}.",
|
||||
"enterCodeBelow": "Please enter the code received into the field below:",
|
||||
"enterNewPasswordBelow": "Enter and repeat new password below:",
|
||||
"enterTheCode": "Enter confirmation code"
|
||||
}
|
18
src/components/auth/recoverPassword/RecoverPassword.jsx
Normal file
18
src/components/auth/recoverPassword/RecoverPassword.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from 'components/ui/form';
|
||||
import RejectionLink from 'components/auth/RejectionLink';
|
||||
import AuthTitle from 'components/auth/AuthTitle';
|
||||
import changePassword from 'components/auth/changePassword/ChangePassword.intl.json';
|
||||
|
||||
import messages from './RecoverPassword.intl.json';
|
||||
import Body from './RecoverPasswordBody';
|
||||
|
||||
export default function RecoverPassword() {
|
||||
return {
|
||||
Title: () => <AuthTitle title={messages.title} />,
|
||||
Body,
|
||||
Footer: () => <Button color="lightViolet" label={changePassword.change} />,
|
||||
Links: () => <RejectionLink label={messages.contactSupport} />
|
||||
};
|
||||
}
|
78
src/components/auth/recoverPassword/RecoverPasswordBody.jsx
Normal file
78
src/components/auth/recoverPassword/RecoverPasswordBody.jsx
Normal file
@ -0,0 +1,78 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
|
||||
import { Input } from 'components/ui/form';
|
||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||
import changePassword from 'components/auth/changePassword/ChangePassword.intl.json';
|
||||
|
||||
import styles from './recoverPassword.scss';
|
||||
import messages from './RecoverPassword.intl.json';
|
||||
|
||||
// TODO: activation code field may be decoupled into common component and reused here and in activation panel
|
||||
// TODO: new password fields may be decoupled into common component and reused here and in changePassword panel
|
||||
|
||||
export default class RecoverPasswordBody extends BaseAuthBody {
|
||||
static displayName = 'RecoverPasswordBody';
|
||||
static panelId = 'recoverPassword';
|
||||
static hasGoBack = true;
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.shape({
|
||||
key: PropTypes.string
|
||||
})
|
||||
};
|
||||
|
||||
autoFocusField = this.props.params && this.props.params.key ? 'newPassword' : 'key';
|
||||
|
||||
// Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить?
|
||||
render() {
|
||||
const {user} = this.context;
|
||||
const {key} = this.props.params;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{this.renderErrors()}
|
||||
|
||||
<p className={styles.descriptionText}>
|
||||
{user.maskedEmail ? (
|
||||
<Message {...messages.messageWasSentTo} values={{
|
||||
email: <b>{user.maskedEmail}</b>
|
||||
}} />
|
||||
) : null}
|
||||
{' '}
|
||||
<Message {...messages.enterCodeBelow} />
|
||||
</p>
|
||||
|
||||
<Input {...this.bindField('key')}
|
||||
color="lightViolet"
|
||||
style={{textAlign: 'center'}}
|
||||
required
|
||||
value={key}
|
||||
readOnly={!!key}
|
||||
placeholder={messages.enterTheCode}
|
||||
/>
|
||||
|
||||
<p className={styles.descriptionText}>
|
||||
<Message {...messages.enterNewPasswordBelow} />
|
||||
</p>
|
||||
|
||||
<Input {...this.bindField('newPassword')}
|
||||
icon="key"
|
||||
color="lightViolet"
|
||||
type="password"
|
||||
required
|
||||
placeholder={changePassword.newPassword}
|
||||
/>
|
||||
|
||||
<Input {...this.bindField('newRePassword')}
|
||||
icon="key"
|
||||
color="lightViolet"
|
||||
type="password"
|
||||
required
|
||||
placeholder={changePassword.newRePassword}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
8
src/components/auth/recoverPassword/recoverPassword.scss
Normal file
8
src/components/auth/recoverPassword/recoverPassword.scss
Normal file
@ -0,0 +1,8 @@
|
||||
@import '~components/ui/colors.scss';
|
||||
|
||||
.descriptionText {
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
padding-bottom: 8px;
|
||||
color: #aaa;
|
||||
}
|
@ -37,7 +37,7 @@ export default class FormModel {
|
||||
|
||||
focus(fieldId) {
|
||||
if (!this.fields[fieldId]) {
|
||||
throw new Error(`The field with an id ${fieldId} does not exists`);
|
||||
throw new Error(`Can not focus. The field with an id ${fieldId} does not exists`);
|
||||
}
|
||||
|
||||
this.fields[fieldId].focus();
|
||||
@ -47,7 +47,7 @@ export default class FormModel {
|
||||
const field = this.fields[fieldId];
|
||||
|
||||
if (!field) {
|
||||
throw new Error(`The field with an id ${fieldId} does not exists`);
|
||||
throw new Error(`Can not get value. The field with an id ${fieldId} does not exists`);
|
||||
}
|
||||
|
||||
if (!field.getValue) {
|
||||
|
@ -21,6 +21,9 @@ export default class User {
|
||||
token: '',
|
||||
username: '',
|
||||
email: '',
|
||||
// will contain user's email or masked email
|
||||
// (e.g. ex**ple@em*il.c**) depending on what information user have already provided
|
||||
maskedEmail: '',
|
||||
avatar: '',
|
||||
lang: '',
|
||||
goal: null, // the goal with wich user entered site
|
||||
|
@ -26,11 +26,11 @@
|
||||
"components.auth.finish.copy": "Copy",
|
||||
"components.auth.finish.passCodeToApp": "To complete authorization process, please, provide the following code to {appName}",
|
||||
"components.auth.finish.waitAppReaction": "Please, wait till your application response",
|
||||
"components.auth.forgotPassword.accountEmail": "Enter account E-mail",
|
||||
"components.auth.forgotPassword.contactSupport": "Contact support",
|
||||
"components.auth.forgotPassword.forgotPasswordMessage": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"components.auth.forgotPassword.forgotPasswordTitle": "Forgot password",
|
||||
"components.auth.forgotPassword.alreadyHaveCode": "Already have a code",
|
||||
"components.auth.forgotPassword.pleasePressButton": "Please press the button bellow to get an email with password recovery code.",
|
||||
"components.auth.forgotPassword.sendMail": "Send mail",
|
||||
"components.auth.forgotPassword.specifyEmail": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"components.auth.forgotPassword.title": "Forgot password",
|
||||
"components.auth.login.emailOrUsername": "E-mail or username",
|
||||
"components.auth.login.loginTitle": "Sign in",
|
||||
"components.auth.login.next": "Next",
|
||||
@ -50,6 +50,12 @@
|
||||
"components.auth.permissions.theAppNeedsAccess1": "This application needs access",
|
||||
"components.auth.permissions.theAppNeedsAccess2": "to your data",
|
||||
"components.auth.permissions.youAuthorizedAs": "You authorized as:",
|
||||
"components.auth.recoverPassword.contactSupport": "Contact support",
|
||||
"components.auth.recoverPassword.enterCodeBelow": "Please enter the code received into the field below:",
|
||||
"components.auth.recoverPassword.enterNewPasswordBelow": "Enter and repeat new password below:",
|
||||
"components.auth.recoverPassword.enterTheCode": "Enter confirmation code",
|
||||
"components.auth.recoverPassword.messageWasSentTo": "The recovery code was sent to your email {email}.",
|
||||
"components.auth.recoverPassword.title": "Restore password",
|
||||
"components.auth.register.acceptRules": "I agree with {link}",
|
||||
"components.auth.register.accountPassword": "Account password",
|
||||
"components.auth.register.registerTitle": "Sign Up",
|
||||
@ -78,38 +84,40 @@
|
||||
"components.profile.preferencesDescription": "Here you can change the key preferences of your account. Please note that all actions must be confirmed by entering a password.",
|
||||
"components.profile.twoFactorAuth": "Two factor auth",
|
||||
"currentAccountEmail": "Current account E-mail address:",
|
||||
"emailInvalid": "Email is invalid",
|
||||
"emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"emailNotAvailable": "This email is already registered.",
|
||||
"emailRequired": "Email is required",
|
||||
"emailToLong": "Email is too long",
|
||||
"enterFinalizationCode": "The E-mail change confirmation code was sent to {email}. Please enter the code received into the field below:",
|
||||
"enterInitializationCode": "The E-mail with an initialization code for E-mail change procedure was sent to {email}. Please enter the code into the field below:",
|
||||
"enterNewEmail": "Then provide your new E-mail address, that you want to use with this account. You will be mailed with confirmation code.",
|
||||
"forgotYourPassword": "forgot your password",
|
||||
"invalidPassword": "You have entered wrong account password.",
|
||||
"keyNotExists": "The key is incorrect",
|
||||
"keyRequired": "Please, enter an activation key",
|
||||
"loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"loginRequired": "Please enter email or username",
|
||||
"logout": "Logout",
|
||||
"newEmailPlaceholder": "Enter new E-mail",
|
||||
"newPasswordRequired": "Please enter new password",
|
||||
"newRePasswordRequired": "Please repeat new password",
|
||||
"passwordRequired": "Please enter password",
|
||||
"passwordTooShort": "Your password is too short",
|
||||
"passwordsDoesNotMatch": "The passwords does not match",
|
||||
"pleaseEnterPassword": "Please, enter your current password",
|
||||
"pressButtonToStart": "Press the button below to send a message with the code for E-mail change initialization.",
|
||||
"rePasswordRequired": "Please retype your password",
|
||||
"register": "Join",
|
||||
"rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"sendEmailButton": "Send E-mail",
|
||||
"suggestResetPassword": "Are you have {link}?",
|
||||
"title": "Confirm your action",
|
||||
"usernameInvalid": "Username is invalid",
|
||||
"usernameRequired": "Username is required",
|
||||
"usernameTooLong": "Username is too long",
|
||||
"usernameTooShort": "Username is too short",
|
||||
"usernameUnavailable": "This username is already taken"
|
||||
"services.accountNotActivated": "The account is not activated",
|
||||
"services.emailFrequency": "Please cool down, you are requesting emails too often",
|
||||
"services.emailInvalid": "Email is invalid",
|
||||
"services.emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"services.emailNotAvailable": "This email is already registered.",
|
||||
"services.emailRequired": "Email is required",
|
||||
"services.emailToLong": "Email is too long",
|
||||
"services.forgotYourPassword": "forgot your password",
|
||||
"services.invalidPassword": "You have entered wrong account password.",
|
||||
"services.keyNotExists": "The key is incorrect",
|
||||
"services.keyRequired": "Please, enter an activation key",
|
||||
"services.loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"services.loginRequired": "Please enter email or username",
|
||||
"services.newPasswordRequired": "Please enter new password",
|
||||
"services.newRePasswordRequired": "Please repeat new password",
|
||||
"services.passwordRequired": "Please enter password",
|
||||
"services.passwordTooShort": "Your password is too short",
|
||||
"services.passwordsDoesNotMatch": "The passwords does not match",
|
||||
"services.rePasswordRequired": "Please retype your password",
|
||||
"services.rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"services.suggestResetPassword": "Are you have {link}?",
|
||||
"services.usernameInvalid": "Username is invalid",
|
||||
"services.usernameRequired": "Username is required",
|
||||
"services.usernameTooLong": "Username is too long",
|
||||
"services.usernameTooShort": "Username is too short",
|
||||
"services.usernameUnavailable": "This username is already taken",
|
||||
"title": "Confirm your action"
|
||||
}
|
||||
|
@ -26,11 +26,11 @@
|
||||
"components.auth.finish.copy": "Скопировать",
|
||||
"components.auth.finish.passCodeToApp": "Чтобы завершить процесс авторизации, пожалуйста, передай {appName} этот код",
|
||||
"components.auth.finish.waitAppReaction": "Пожалуйста, дождитесь реакции вашего приложения",
|
||||
"components.auth.forgotPassword.accountEmail": "Enter account E-mail",
|
||||
"components.auth.forgotPassword.contactSupport": "Contact support",
|
||||
"components.auth.forgotPassword.forgotPasswordMessage": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"components.auth.forgotPassword.forgotPasswordTitle": "Forgot password",
|
||||
"components.auth.forgotPassword.alreadyHaveCode": "Already have a code",
|
||||
"components.auth.forgotPassword.pleasePressButton": "Please press the button bellow to get an email with password recovery code.",
|
||||
"components.auth.forgotPassword.sendMail": "Send mail",
|
||||
"components.auth.forgotPassword.specifyEmail": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"components.auth.forgotPassword.title": "Forgot password",
|
||||
"components.auth.login.emailOrUsername": "E-mail or username",
|
||||
"components.auth.login.loginTitle": "Sign in",
|
||||
"components.auth.login.next": "Next",
|
||||
@ -50,6 +50,12 @@
|
||||
"components.auth.permissions.theAppNeedsAccess1": "This application needs access",
|
||||
"components.auth.permissions.theAppNeedsAccess2": "to your data",
|
||||
"components.auth.permissions.youAuthorizedAs": "You authorized as:",
|
||||
"components.auth.recoverPassword.contactSupport": "Contact support",
|
||||
"components.auth.recoverPassword.enterCodeBelow": "Please enter the code received into the field below:",
|
||||
"components.auth.recoverPassword.enterNewPasswordBelow": "Enter and repeat new password below:",
|
||||
"components.auth.recoverPassword.enterTheCode": "Enter confirmation code",
|
||||
"components.auth.recoverPassword.messageWasSentTo": "The recovery code was sent to your email {email}.",
|
||||
"components.auth.recoverPassword.title": "Restore password",
|
||||
"components.auth.register.acceptRules": "I agree with {link}",
|
||||
"components.auth.register.accountPassword": "Account password",
|
||||
"components.auth.register.registerTitle": "Sign Up",
|
||||
@ -78,38 +84,40 @@
|
||||
"components.profile.preferencesDescription": "Здесь вы можете сменить ключевые параметры вашего аккаунта. Обратите внимание, что для всех действий необходимо подтверждение при помощи ввода пароля.",
|
||||
"components.profile.twoFactorAuth": "Двухфакторная аутентификация",
|
||||
"currentAccountEmail": "Current account E-mail address:",
|
||||
"emailInvalid": "Email is invalid",
|
||||
"emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"emailNotAvailable": "This email is already registered.",
|
||||
"emailRequired": "Email is required",
|
||||
"emailToLong": "Email is too long",
|
||||
"enterFinalizationCode": "The E-mail change confirmation code was sent to {email}. Please enter the code received into the field below:",
|
||||
"enterInitializationCode": "The E-mail with an initialization code for E-mail change procedure was sent to {email}. Please enter the code into the field below:",
|
||||
"enterNewEmail": "Then provide your new E-mail address, that you want to use with this account. You will be mailed with confirmation code.",
|
||||
"forgotYourPassword": "forgot your password",
|
||||
"invalidPassword": "You have entered wrong account password.",
|
||||
"keyNotExists": "The key is incorrect",
|
||||
"keyRequired": "Please, enter an activation key",
|
||||
"loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"loginRequired": "Please enter email or username",
|
||||
"logout": "Logout",
|
||||
"newEmailPlaceholder": "Enter new E-mail",
|
||||
"newPasswordRequired": "Please enter new password",
|
||||
"newRePasswordRequired": "Please repeat new password",
|
||||
"passwordRequired": "Please enter password",
|
||||
"passwordTooShort": "Your password is too short",
|
||||
"passwordsDoesNotMatch": "The passwords does not match",
|
||||
"pleaseEnterPassword": "Please, enter your current password",
|
||||
"pressButtonToStart": "Press the button below to send a message with the code for E-mail change initialization.",
|
||||
"rePasswordRequired": "Please retype your password",
|
||||
"register": "Join",
|
||||
"rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"sendEmailButton": "Send E-mail",
|
||||
"suggestResetPassword": "Are you have {link}?",
|
||||
"title": "Confirm your action",
|
||||
"usernameInvalid": "Username is invalid",
|
||||
"usernameRequired": "Username is required",
|
||||
"usernameTooLong": "Username is too long",
|
||||
"usernameTooShort": "Username is too short",
|
||||
"usernameUnavailable": "This username is already taken"
|
||||
"services.accountNotActivated": "The account is not activated",
|
||||
"services.emailFrequency": "Please cool down, you are requesting emails too often",
|
||||
"services.emailInvalid": "Email is invalid",
|
||||
"services.emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"services.emailNotAvailable": "This email is already registered.",
|
||||
"services.emailRequired": "Email is required",
|
||||
"services.emailToLong": "Email is too long",
|
||||
"services.forgotYourPassword": "forgot your password",
|
||||
"services.invalidPassword": "You have entered wrong account password.",
|
||||
"services.keyNotExists": "The key is incorrect",
|
||||
"services.keyRequired": "Please, enter an activation key",
|
||||
"services.loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"services.loginRequired": "Please enter email or username",
|
||||
"services.newPasswordRequired": "Please enter new password",
|
||||
"services.newRePasswordRequired": "Please repeat new password",
|
||||
"services.passwordRequired": "Please enter password",
|
||||
"services.passwordTooShort": "Your password is too short",
|
||||
"services.passwordsDoesNotMatch": "The passwords does not match",
|
||||
"services.rePasswordRequired": "Please retype your password",
|
||||
"services.rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"services.suggestResetPassword": "Are you have {link}?",
|
||||
"services.usernameInvalid": "Username is invalid",
|
||||
"services.usernameRequired": "Username is required",
|
||||
"services.usernameTooLong": "Username is too long",
|
||||
"services.usernameTooShort": "Username is too short",
|
||||
"services.usernameUnavailable": "This username is already taken",
|
||||
"title": "Confirm your action"
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import Activation from 'components/auth/activation/Activation';
|
||||
import Password from 'components/auth/password/Password';
|
||||
import ChangePassword from 'components/auth/changePassword/ChangePassword';
|
||||
import ForgotPassword from 'components/auth/forgotPassword/ForgotPassword';
|
||||
import RecoverPassword from 'components/auth/recoverPassword/RecoverPassword';
|
||||
import Finish from 'components/auth/finish/Finish';
|
||||
|
||||
import authFlow from 'services/authFlow';
|
||||
@ -54,6 +55,7 @@ export default function routesFactory(store) {
|
||||
<Route path="/oauth/finish" component={Finish} {...startAuthFlow} />
|
||||
<Route path="/change-password" components={new ChangePassword()} {...startAuthFlow} />
|
||||
<Route path="/forgot-password" components={new ForgotPassword()} {...startAuthFlow} />
|
||||
<Route path="/recover-password(/:key)" components={new RecoverPassword()} {...startAuthFlow} />
|
||||
</Route>
|
||||
|
||||
<Route path="profile" component={ProfilePage} {...userOnly}>
|
||||
|
@ -4,6 +4,7 @@ import RegisterState from './RegisterState';
|
||||
import LoginState from './LoginState';
|
||||
import OAuthState from './OAuthState';
|
||||
import ForgotPasswordState from './ForgotPasswordState';
|
||||
import RecoverPasswordState from './RecoverPasswordState';
|
||||
|
||||
// TODO: a way to unload service (when we are on account page)
|
||||
|
||||
@ -81,7 +82,7 @@ export default class AuthFlow {
|
||||
this.run('setOAuthRequest', {});
|
||||
}
|
||||
|
||||
switch (path) {
|
||||
switch (path.replace(/(.)\/.+/, '$1')) { // use only first part of an url
|
||||
case '/oauth':
|
||||
this.setState(new OAuthState());
|
||||
break;
|
||||
@ -90,6 +91,10 @@ export default class AuthFlow {
|
||||
this.setState(new RegisterState());
|
||||
break;
|
||||
|
||||
case '/recover-password':
|
||||
this.setState(new RecoverPasswordState());
|
||||
break;
|
||||
|
||||
case '/forgot-password':
|
||||
this.setState(new ForgotPasswordState());
|
||||
break;
|
||||
|
@ -1,9 +1,26 @@
|
||||
import AbstractState from './AbstractState';
|
||||
import LoginState from './LoginState';
|
||||
import CompleteState from './CompleteState';
|
||||
import RecoverPasswordState from './RecoverPasswordState';
|
||||
|
||||
export default class ForgotPasswordState extends AbstractState {
|
||||
enter(context) {
|
||||
context.navigate('/forgot-password');
|
||||
const {user} = context.getState();
|
||||
|
||||
if (user.isGuest) {
|
||||
if (this.getLogin(context)) {
|
||||
context.navigate('/forgot-password');
|
||||
} else {
|
||||
context.setState(new LoginState());
|
||||
}
|
||||
} else {
|
||||
context.setState(new CompleteState());
|
||||
}
|
||||
}
|
||||
|
||||
resolve(context) {
|
||||
context.run('forgotPassword', {login: this.getLogin(context)})
|
||||
.then(() => context.setState(new RecoverPasswordState()));
|
||||
}
|
||||
|
||||
goBack(context) {
|
||||
@ -11,6 +28,12 @@ export default class ForgotPasswordState extends AbstractState {
|
||||
}
|
||||
|
||||
reject(context) {
|
||||
context.navigate('/send-message');
|
||||
context.setState(new RecoverPasswordState());
|
||||
}
|
||||
|
||||
getLogin(context) {
|
||||
const {user} = context.getState();
|
||||
|
||||
return user.email || user.username;
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ export default class PasswordState extends AbstractState {
|
||||
enter(context) {
|
||||
const {user} = context.getState();
|
||||
|
||||
if (!user.isGuest) {
|
||||
context.setState(new CompleteState());
|
||||
} else {
|
||||
if (user.isGuest) {
|
||||
context.navigate('/password');
|
||||
} else {
|
||||
context.setState(new CompleteState());
|
||||
}
|
||||
}
|
||||
|
||||
|
31
src/services/authFlow/RecoverPasswordState.js
Normal file
31
src/services/authFlow/RecoverPasswordState.js
Normal file
@ -0,0 +1,31 @@
|
||||
import AbstractState from './AbstractState';
|
||||
import LoginState from './LoginState';
|
||||
import CompleteState from './CompleteState';
|
||||
|
||||
export default class RecoverPasswordState extends AbstractState {
|
||||
enter(context) {
|
||||
const {user, routing} = context.getState();
|
||||
|
||||
if (user.isGuest) {
|
||||
const url = routing.location.pathname.indexOf('/recover-password') === 0
|
||||
? routing.location.pathname
|
||||
: '/recover-password';
|
||||
context.navigate(url);
|
||||
} else {
|
||||
context.setState(new CompleteState());
|
||||
}
|
||||
}
|
||||
|
||||
resolve(context, payload) {
|
||||
context.run('recoverPassword', payload)
|
||||
.then(() => context.setState(new CompleteState()));
|
||||
}
|
||||
|
||||
goBack(context) {
|
||||
context.setState(new LoginState());
|
||||
}
|
||||
|
||||
reject(context) {
|
||||
context.navigate('/send-message');
|
||||
}
|
||||
}
|
28
src/services/errorsDict.intl.json
Normal file
28
src/services/errorsDict.intl.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"invalidPassword": "You have entered wrong account password.",
|
||||
"suggestResetPassword": "Are you have {link}?",
|
||||
"forgotYourPassword": "forgot your password",
|
||||
"loginRequired": "Please enter email or username",
|
||||
"loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"passwordRequired": "Please enter password",
|
||||
"newPasswordRequired": "Please enter new password",
|
||||
"newRePasswordRequired": "Please repeat new password",
|
||||
"usernameRequired": "Username is required",
|
||||
"usernameInvalid": "Username is invalid",
|
||||
"usernameTooShort": "Username is too short",
|
||||
"usernameTooLong": "Username is too long",
|
||||
"usernameUnavailable": "This username is already taken",
|
||||
"emailRequired": "Email is required",
|
||||
"emailInvalid": "Email is invalid",
|
||||
"emailToLong": "Email is too long",
|
||||
"emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"emailNotAvailable": "This email is already registered.",
|
||||
"rePasswordRequired": "Please retype your password",
|
||||
"passwordTooShort": "Your password is too short",
|
||||
"passwordsDoesNotMatch": "The passwords does not match",
|
||||
"rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"keyRequired": "Please, enter an activation key",
|
||||
"keyNotExists": "The key is incorrect",
|
||||
"emailFrequency": "Please cool down, you are requesting emails too often",
|
||||
"accountNotActivated": "The account is not activated"
|
||||
}
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
|
||||
import messages from './errorsDict.messages';
|
||||
import messages from './errorsDict.intl.json';
|
||||
|
||||
export default {
|
||||
resolve(error) {
|
||||
@ -65,5 +65,9 @@ const errorsMap = {
|
||||
|
||||
'error.newPassword_required': () => <Message {...messages.newPasswordRequired} />,
|
||||
'error.newRePassword_required': () => <Message {...messages.newRePasswordRequired} />,
|
||||
'error.newRePassword_does_not_match': () => <Message {...messages.passwordsDoesNotMatch} />
|
||||
'error.newRePassword_does_not_match': () => <Message {...messages.passwordsDoesNotMatch} />,
|
||||
|
||||
'error.account_not_activated': () => <Message {...messages.accountNotActivated} />,
|
||||
|
||||
'error.email_frequency': () => <Message {...messages.emailFrequency} />
|
||||
};
|
||||
|
@ -1,123 +0,0 @@
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
export default defineMessages({
|
||||
invalidPassword: {
|
||||
id: 'invalidPassword',
|
||||
defaultMessage: 'You have entered wrong account password.'
|
||||
},
|
||||
|
||||
suggestResetPassword: {
|
||||
id: 'suggestResetPassword',
|
||||
defaultMessage: 'Are you have {link}?'
|
||||
},
|
||||
|
||||
forgotYourPassword: {
|
||||
id: 'forgotYourPassword',
|
||||
defaultMessage: 'forgot your password'
|
||||
},
|
||||
|
||||
loginRequired: {
|
||||
id: 'loginRequired',
|
||||
defaultMessage: 'Please enter email or username'
|
||||
},
|
||||
|
||||
loginNotExist: {
|
||||
id: 'loginNotExist',
|
||||
defaultMessage: 'Sorry, Ely doesn\'t recognise your login.'
|
||||
},
|
||||
|
||||
passwordRequired: {
|
||||
id: 'passwordRequired',
|
||||
defaultMessage: 'Please enter password'
|
||||
},
|
||||
|
||||
newPasswordRequired: {
|
||||
id: 'newPasswordRequired',
|
||||
defaultMessage: 'Please enter new password'
|
||||
},
|
||||
|
||||
newRePasswordRequired: {
|
||||
id: 'newRePasswordRequired',
|
||||
defaultMessage: 'Please repeat new password'
|
||||
},
|
||||
|
||||
usernameRequired: {
|
||||
id: 'usernameRequired',
|
||||
defaultMessage: 'Username is required'
|
||||
},
|
||||
|
||||
usernameInvalid: {
|
||||
id: 'usernameInvalid',
|
||||
defaultMessage: 'Username is invalid'
|
||||
},
|
||||
|
||||
usernameTooShort: {
|
||||
id: 'usernameTooShort',
|
||||
defaultMessage: 'Username is too short'
|
||||
},
|
||||
|
||||
usernameTooLong: {
|
||||
id: 'usernameTooLong',
|
||||
defaultMessage: 'Username is too long'
|
||||
},
|
||||
|
||||
usernameUnavailable: {
|
||||
id: 'usernameUnavailable',
|
||||
defaultMessage: 'This username is already taken'
|
||||
},
|
||||
|
||||
emailRequired: {
|
||||
id: 'emailRequired',
|
||||
defaultMessage: 'Email is required'
|
||||
},
|
||||
|
||||
emailInvalid: {
|
||||
id: 'emailInvalid',
|
||||
defaultMessage: 'Email is invalid'
|
||||
},
|
||||
|
||||
emailToLong: {
|
||||
id: 'emailToLong',
|
||||
defaultMessage: 'Email is too long'
|
||||
},
|
||||
|
||||
emailIsTempmail: {
|
||||
id: 'emailIsTempmail',
|
||||
defaultMessage: 'Tempmail E-mail addresses is not allowed'
|
||||
},
|
||||
|
||||
emailNotAvailable: {
|
||||
id: 'emailNotAvailable',
|
||||
defaultMessage: 'This email is already registered.'
|
||||
},
|
||||
|
||||
rePasswordRequired: {
|
||||
id: 'rePasswordRequired',
|
||||
defaultMessage: 'Please retype your password'
|
||||
},
|
||||
|
||||
passwordTooShort: {
|
||||
id: 'passwordTooShort',
|
||||
defaultMessage: 'Your password is too short'
|
||||
},
|
||||
|
||||
passwordsDoesNotMatch: {
|
||||
id: 'passwordsDoesNotMatch',
|
||||
defaultMessage: 'The passwords does not match'
|
||||
},
|
||||
|
||||
rulesAgreementRequired: {
|
||||
id: 'rulesAgreementRequired',
|
||||
defaultMessage: 'You must accept rules in order to create an account'
|
||||
},
|
||||
|
||||
keyRequired: {
|
||||
id: 'keyRequired',
|
||||
defaultMessage: 'Please, enter an activation key'
|
||||
},
|
||||
|
||||
keyNotExists: {
|
||||
id: 'keyNotExists',
|
||||
defaultMessage: 'The key is incorrect'
|
||||
}
|
||||
});
|
139
tests/services/authFlow/ForgotPasswordState.test.js
Normal file
139
tests/services/authFlow/ForgotPasswordState.test.js
Normal file
@ -0,0 +1,139 @@
|
||||
import ForgotPasswordState from 'services/authFlow/ForgotPasswordState';
|
||||
import RecoverPasswordState from 'services/authFlow/RecoverPasswordState';
|
||||
import CompleteState from 'services/authFlow/CompleteState';
|
||||
import LoginState from 'services/authFlow/LoginState';
|
||||
|
||||
import { bootstrap, expectState, expectNavigate, expectRun } from './helpers';
|
||||
|
||||
describe('ForgotPasswordState', () => {
|
||||
let state;
|
||||
let context;
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
state = new ForgotPasswordState();
|
||||
|
||||
const data = bootstrap();
|
||||
context = data.context;
|
||||
mock = data.mock;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
describe('#enter', () => {
|
||||
it('should navigate to /forgot-password if email set', () => {
|
||||
context.getState.returns({
|
||||
user: {isGuest: true, email: 'foo@bar.com'}
|
||||
});
|
||||
|
||||
expectNavigate(mock, '/forgot-password');
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
|
||||
it('should navigate to /forgot-password if username set', () => {
|
||||
context.getState.returns({
|
||||
user: {isGuest: true, username: 'foobar'}
|
||||
});
|
||||
|
||||
expectNavigate(mock, '/forgot-password');
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
|
||||
it('should transition to complete if not guest', () => {
|
||||
context.getState.returns({
|
||||
user: {isGuest: false}
|
||||
});
|
||||
|
||||
expectState(mock, CompleteState);
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
|
||||
it('should transition to login if no identity', () => {
|
||||
context.getState.returns({
|
||||
user: {isGuest: true}
|
||||
});
|
||||
|
||||
expectState(mock, LoginState);
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#resolve', () => {
|
||||
it('should call forgotPassword with email', () => {
|
||||
const expectedLogin = 'foo@bar.com';
|
||||
context.getState.returns({
|
||||
user: {
|
||||
email: expectedLogin
|
||||
}
|
||||
});
|
||||
|
||||
expectRun(
|
||||
mock,
|
||||
'forgotPassword',
|
||||
sinon.match({
|
||||
login: expectedLogin
|
||||
})
|
||||
).returns({then() {}});
|
||||
|
||||
state.resolve(context, {});
|
||||
});
|
||||
|
||||
it('should call forgotPassword with username', () => {
|
||||
const expectedLogin = 'foobar';
|
||||
context.getState.returns({
|
||||
user: {
|
||||
username: expectedLogin
|
||||
}
|
||||
});
|
||||
|
||||
expectRun(
|
||||
mock,
|
||||
'forgotPassword',
|
||||
sinon.match({
|
||||
login: expectedLogin
|
||||
})
|
||||
).returns({then() {}});
|
||||
|
||||
state.resolve(context, {});
|
||||
});
|
||||
|
||||
it('should transition to recoverPassword state on success', () => {
|
||||
const promise = Promise.resolve();
|
||||
const expectedLogin = 'foo@bar.com';
|
||||
context.getState.returns({
|
||||
user: {
|
||||
email: expectedLogin
|
||||
}
|
||||
});
|
||||
|
||||
mock.expects('run').returns(promise);
|
||||
expectState(mock, RecoverPasswordState);
|
||||
|
||||
state.resolve(context, {});
|
||||
|
||||
return promise;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reject', () => {
|
||||
it('should navigate to /send-message', () => {
|
||||
expectState(mock, RecoverPasswordState);
|
||||
|
||||
state.reject(context);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#goBack', () => {
|
||||
it('should transition to login state', () => {
|
||||
expectState(mock, LoginState);
|
||||
|
||||
state.goBack(context);
|
||||
});
|
||||
});
|
||||
});
|
@ -45,7 +45,7 @@ describe('PasswordState', () => {
|
||||
});
|
||||
|
||||
describe('#resolve', () => {
|
||||
(() => {
|
||||
(function() {
|
||||
const expectedLogin = 'login';
|
||||
const expectedPassword = 'password';
|
||||
|
||||
@ -78,7 +78,7 @@ describe('PasswordState', () => {
|
||||
email: expectedLogin,
|
||||
username: expectedLogin
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
it('should transition to complete state on successfull login', () => {
|
||||
const promise = Promise.resolve();
|
||||
|
104
tests/services/authFlow/RecoverPasswordState.test.js
Normal file
104
tests/services/authFlow/RecoverPasswordState.test.js
Normal file
@ -0,0 +1,104 @@
|
||||
import RecoverPasswordState from 'services/authFlow/RecoverPasswordState';
|
||||
import CompleteState from 'services/authFlow/CompleteState';
|
||||
import LoginState from 'services/authFlow/LoginState';
|
||||
|
||||
import { bootstrap, expectState, expectNavigate, expectRun } from './helpers';
|
||||
|
||||
describe('RecoverPasswordState', () => {
|
||||
let state;
|
||||
let context;
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
state = new RecoverPasswordState();
|
||||
|
||||
const data = bootstrap();
|
||||
context = data.context;
|
||||
mock = data.mock;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.verify();
|
||||
});
|
||||
|
||||
describe('#enter', () => {
|
||||
it('should navigate to /recover-password', () => {
|
||||
const expectedPath = '/recover-password';
|
||||
context.getState.returns({
|
||||
user: {isGuest: true},
|
||||
routing: {
|
||||
location: {pathname: expectedPath}
|
||||
}
|
||||
});
|
||||
|
||||
expectNavigate(mock, expectedPath);
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
|
||||
it('should navigate to /recover-password/key', () => {
|
||||
const expectedPath = '/recover-password/sasx5AS4d61';
|
||||
context.getState.returns({
|
||||
user: {isGuest: true},
|
||||
routing: {
|
||||
location: {pathname: expectedPath}
|
||||
}
|
||||
});
|
||||
|
||||
expectNavigate(mock, expectedPath);
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
|
||||
it('should transition to complete if not guest', () => {
|
||||
context.getState.returns({
|
||||
user: {isGuest: false}
|
||||
});
|
||||
|
||||
expectState(mock, CompleteState);
|
||||
|
||||
state.enter(context);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#resolve', () => {
|
||||
it('should call recoverPassword with provided payload', () => {
|
||||
const expectedPayload = {key: 123, newPassword: '123', newRePassword: '123'};
|
||||
|
||||
expectRun(
|
||||
mock,
|
||||
'recoverPassword',
|
||||
sinon.match(expectedPayload)
|
||||
).returns({then() {}});
|
||||
|
||||
state.resolve(context, expectedPayload);
|
||||
});
|
||||
|
||||
it('should transition to complete state on success', () => {
|
||||
const promise = Promise.resolve();
|
||||
|
||||
mock.expects('run').returns(promise);
|
||||
expectState(mock, CompleteState);
|
||||
|
||||
state.resolve(context, {});
|
||||
|
||||
return promise;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reject', () => {
|
||||
it('should navigate to /send-message', () => {
|
||||
expectNavigate(mock, '/send-message');
|
||||
|
||||
state.reject(context);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#goBack', () => {
|
||||
it('should transition to login state', () => {
|
||||
expectState(mock, LoginState);
|
||||
|
||||
state.goBack(context);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user