2016-02-13 20:58:47 +05:30
|
|
|
import { routeActions } from 'react-router-redux';
|
|
|
|
|
2016-03-16 11:24:42 +05:30
|
|
|
import { updateUser, logout as logoutUser, changePassword as changeUserPassword, authenticate } from 'components/user/actions';
|
2016-02-13 20:58:47 +05:30
|
|
|
import request from 'services/request';
|
2016-06-04 19:16:39 +05:30
|
|
|
import authentication from 'services/api/authentication';
|
2016-02-13 20:58:47 +05:30
|
|
|
|
|
|
|
export function login({login = '', password = '', rememberMe = false}) {
|
|
|
|
const PASSWORD_REQUIRED = 'error.password_required';
|
|
|
|
const LOGIN_REQUIRED = 'error.login_required';
|
2016-02-28 16:54:47 +05:30
|
|
|
const ACTIVATION_REQUIRED = 'error.account_not_activated';
|
2016-02-13 20:58:47 +05:30
|
|
|
|
2016-04-02 16:28:54 +05:30
|
|
|
return wrapInLoader((dispatch) =>
|
2016-06-04 19:16:39 +05:30
|
|
|
authentication.login(
|
2016-02-13 20:58:47 +05:30
|
|
|
{login, password, rememberMe}
|
|
|
|
)
|
2016-06-04 19:16:39 +05:30
|
|
|
.then(authHandler(dispatch))
|
2016-02-13 20:58:47 +05:30
|
|
|
.catch((resp) => {
|
2016-06-04 19:16:39 +05:30
|
|
|
if (resp.errors) {
|
|
|
|
if (resp.errors.password === PASSWORD_REQUIRED) {
|
|
|
|
return dispatch(updateUser({
|
|
|
|
username: login,
|
|
|
|
email: login
|
|
|
|
}));
|
|
|
|
} else if (resp.errors.login === ACTIVATION_REQUIRED) {
|
|
|
|
return dispatch(needActivation());
|
|
|
|
} else if (resp.errors.login === LOGIN_REQUIRED && password) {
|
|
|
|
// return to the first step
|
2016-02-13 20:58:47 +05:30
|
|
|
dispatch(logout());
|
|
|
|
}
|
|
|
|
}
|
2016-02-26 23:43:41 +05:30
|
|
|
|
2016-05-15 02:23:58 +05:30
|
|
|
return validationErrorsHandler(dispatch)(resp);
|
2016-02-13 20:58:47 +05:30
|
|
|
})
|
2016-04-02 16:28:54 +05:30
|
|
|
);
|
2016-02-13 20:58:47 +05:30
|
|
|
}
|
|
|
|
|
2016-03-16 11:24:42 +05:30
|
|
|
export function changePassword({
|
|
|
|
password = '',
|
|
|
|
newPassword = '',
|
|
|
|
newRePassword = ''
|
|
|
|
}) {
|
2016-04-02 16:28:54 +05:30
|
|
|
return wrapInLoader((dispatch) =>
|
2016-06-04 14:47:06 +05:30
|
|
|
dispatch(changeUserPassword({password, newPassword, newRePassword, logoutAll: false}))
|
2016-05-15 02:23:58 +05:30
|
|
|
.catch(validationErrorsHandler(dispatch))
|
|
|
|
);
|
|
|
|
}
|
2016-03-16 11:24:42 +05:30
|
|
|
|
2016-05-15 02:23:58 +05:30
|
|
|
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}
|
|
|
|
)
|
2016-06-04 19:16:39 +05:30
|
|
|
.then(authHandler(dispatch))
|
2016-05-22 20:46:51 +05:30
|
|
|
.catch(validationErrorsHandler(dispatch, '/forgot-password'))
|
2016-04-02 16:28:54 +05:30
|
|
|
);
|
2016-03-16 11:24:42 +05:30
|
|
|
}
|
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
export function register({
|
|
|
|
email = '',
|
|
|
|
username = '',
|
|
|
|
password = '',
|
|
|
|
rePassword = '',
|
|
|
|
rulesAgreement = false
|
|
|
|
}) {
|
2016-05-14 18:30:14 +05:30
|
|
|
return wrapInLoader((dispatch, getState) =>
|
2016-02-13 20:58:47 +05:30
|
|
|
request.post(
|
2016-02-24 03:50:10 +05:30
|
|
|
'/api/signup',
|
2016-05-14 18:30:14 +05:30
|
|
|
{email, username, password, rePassword, rulesAgreement, lang: getState().user.lang}
|
2016-02-13 20:58:47 +05:30
|
|
|
)
|
|
|
|
.then(() => {
|
2016-02-13 21:04:29 +05:30
|
|
|
dispatch(updateUser({
|
|
|
|
username,
|
2016-04-15 09:39:04 +05:30
|
|
|
email
|
2016-02-13 21:04:29 +05:30
|
|
|
}));
|
2016-04-15 09:39:04 +05:30
|
|
|
dispatch(needActivation());
|
2016-02-13 20:58:47 +05:30
|
|
|
dispatch(routeActions.push('/activation'));
|
|
|
|
})
|
2016-05-15 02:23:58 +05:30
|
|
|
.catch(validationErrorsHandler(dispatch))
|
2016-04-02 16:28:54 +05:30
|
|
|
);
|
2016-02-13 20:58:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
export function activate({key = ''}) {
|
2016-04-02 16:28:54 +05:30
|
|
|
return wrapInLoader((dispatch) =>
|
2016-02-13 20:58:47 +05:30
|
|
|
request.post(
|
|
|
|
'/api/signup/confirm',
|
|
|
|
{key}
|
|
|
|
)
|
2016-06-04 19:16:39 +05:30
|
|
|
.then(authHandler(dispatch))
|
2016-05-23 00:28:43 +05:30
|
|
|
.catch(validationErrorsHandler(dispatch, '/resend-activation'))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function resendActivation({email = ''}) {
|
|
|
|
return wrapInLoader((dispatch) =>
|
|
|
|
request.post(
|
|
|
|
'/api/signup/repeat-message',
|
|
|
|
{email}
|
|
|
|
)
|
2016-07-23 18:13:37 +05:30
|
|
|
.then((resp) => {
|
|
|
|
dispatch(updateUser({
|
|
|
|
email
|
|
|
|
}));
|
|
|
|
|
|
|
|
return resp;
|
|
|
|
})
|
2016-05-23 00:28:43 +05:30
|
|
|
.catch(validationErrorsHandler(dispatch))
|
2016-04-02 16:28:54 +05:30
|
|
|
);
|
2016-02-13 20:58:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
export const ERROR = 'error';
|
|
|
|
export function setError(error) {
|
|
|
|
return {
|
|
|
|
type: ERROR,
|
|
|
|
payload: error,
|
|
|
|
error: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function clearErrors() {
|
|
|
|
return setError(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function logout() {
|
2016-03-02 02:06:14 +05:30
|
|
|
return logoutUser();
|
2016-02-13 20:58:47 +05:30
|
|
|
}
|
2016-02-23 11:27:16 +05:30
|
|
|
|
|
|
|
// TODO: move to oAuth actions?
|
|
|
|
// test request: /oauth?client_id=ely&redirect_uri=http%3A%2F%2Fely.by&response_type=code&scope=minecraft_server_session
|
2016-02-27 16:23:58 +05:30
|
|
|
export function oAuthValidate(oauth) {
|
2016-04-02 16:28:54 +05:30
|
|
|
return wrapInLoader((dispatch) =>
|
2016-02-23 11:27:16 +05:30
|
|
|
request.get(
|
|
|
|
'/api/oauth/validate',
|
2016-02-27 16:23:58 +05:30
|
|
|
getOAuthRequest(oauth)
|
2016-02-23 11:27:16 +05:30
|
|
|
)
|
|
|
|
.then((resp) => {
|
|
|
|
dispatch(setClient(resp.client));
|
2016-02-27 16:23:58 +05:30
|
|
|
dispatch(setOAuthRequest(resp.oAuth));
|
2016-02-29 23:46:33 +05:30
|
|
|
dispatch(setScopes(resp.session.scopes));
|
2016-02-23 11:27:16 +05:30
|
|
|
})
|
|
|
|
.catch((resp = {}) => { // TODO
|
2016-02-27 16:23:58 +05:30
|
|
|
handleOauthParamsValidation(resp);
|
2016-04-02 16:28:54 +05:30
|
|
|
})
|
|
|
|
);
|
2016-02-27 16:23:58 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
export function oAuthComplete(params = {}) {
|
2016-04-02 16:28:54 +05:30
|
|
|
return wrapInLoader((dispatch, getState) => {
|
2016-02-27 16:23:58 +05:30
|
|
|
const oauth = getState().auth.oauth;
|
|
|
|
const query = request.buildQuery(getOAuthRequest(oauth));
|
|
|
|
|
|
|
|
return request.post(
|
|
|
|
`/api/oauth/complete?${query}`,
|
|
|
|
typeof params.accept === 'undefined' ? {} : {accept: params.accept}
|
|
|
|
)
|
2016-03-02 02:06:14 +05:30
|
|
|
.catch((resp = {}) => { // TODO
|
|
|
|
if (resp.statusCode === 401 && resp.error === 'access_denied') {
|
|
|
|
// user declined permissions
|
|
|
|
return {
|
2016-03-15 12:06:13 +05:30
|
|
|
success: false,
|
2016-03-02 02:06:14 +05:30
|
|
|
redirectUri: resp.redirectUri
|
|
|
|
};
|
2016-02-28 01:28:36 +05:30
|
|
|
}
|
|
|
|
|
2016-02-27 16:23:58 +05:30
|
|
|
handleOauthParamsValidation(resp);
|
|
|
|
|
2016-03-02 02:06:14 +05:30
|
|
|
if (resp.status === 401 && resp.name === 'Unauthorized') {
|
|
|
|
const error = new Error('Unauthorized');
|
|
|
|
error.unauthorized = true;
|
|
|
|
throw error;
|
2016-02-23 11:27:16 +05:30
|
|
|
}
|
2016-02-27 16:23:58 +05:30
|
|
|
|
2016-03-02 02:06:14 +05:30
|
|
|
if (resp.statusCode === 401 && resp.error === 'accept_required') {
|
|
|
|
const error = new Error('Permissions accept required');
|
|
|
|
error.acceptRequired = true;
|
2016-04-15 01:24:35 +05:30
|
|
|
dispatch(requirePermissionsAccept());
|
2016-03-02 02:06:14 +05:30
|
|
|
throw error;
|
2016-02-23 11:27:16 +05:30
|
|
|
}
|
2016-03-15 12:06:13 +05:30
|
|
|
})
|
|
|
|
.then((resp) => {
|
2016-03-21 01:06:30 +05:30
|
|
|
if (resp.redirectUri.startsWith('static_page')) {
|
|
|
|
resp.code = resp.redirectUri.match(/code=(.+)&/)[1];
|
|
|
|
resp.redirectUri = resp.redirectUri.match(/^(.+)\?/)[1];
|
2016-03-15 12:06:13 +05:30
|
|
|
resp.displayCode = resp.redirectUri === 'static_page_with_code';
|
|
|
|
dispatch(setOAuthCode({
|
|
|
|
success: resp.success,
|
|
|
|
code: resp.code,
|
|
|
|
displayCode: resp.displayCode
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp;
|
2016-02-23 11:27:16 +05:30
|
|
|
});
|
2016-04-02 16:28:54 +05:30
|
|
|
});
|
2016-02-27 16:23:58 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
function getOAuthRequest(oauth) {
|
|
|
|
return {
|
|
|
|
client_id: oauth.clientId,
|
|
|
|
redirect_uri: oauth.redirectUrl,
|
|
|
|
response_type: oauth.responseType,
|
|
|
|
scope: oauth.scope,
|
|
|
|
state: oauth.state
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleOauthParamsValidation(resp = {}) {
|
2016-06-04 14:47:06 +05:30
|
|
|
let userMessage;
|
2016-02-27 16:23:58 +05:30
|
|
|
if (resp.statusCode === 400 && resp.error === 'invalid_request') {
|
2016-06-04 14:47:06 +05:30
|
|
|
userMessage = `Invalid request (${resp.parameter} required).`;
|
|
|
|
} else if (resp.statusCode === 400 && resp.error === 'unsupported_response_type') {
|
|
|
|
userMessage = `Invalid response type '${resp.parameter}'.`;
|
|
|
|
} else if (resp.statusCode === 400 && resp.error === 'invalid_scope') {
|
|
|
|
userMessage = `Invalid scope '${resp.parameter}'.`;
|
|
|
|
} else if (resp.statusCode === 401 && resp.error === 'invalid_client') {
|
|
|
|
userMessage = 'Can not find application you are trying to authorize.';
|
|
|
|
} else {
|
|
|
|
return;
|
2016-02-27 16:23:58 +05:30
|
|
|
}
|
2016-06-04 14:47:06 +05:30
|
|
|
|
|
|
|
/* eslint no-alert: "off" */
|
|
|
|
alert(userMessage);
|
|
|
|
throw new Error('Error completing request');
|
2016-02-23 11:27:16 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
export const SET_CLIENT = 'set_client';
|
|
|
|
export function setClient({id, name, description}) {
|
|
|
|
return {
|
|
|
|
type: SET_CLIENT,
|
|
|
|
payload: {id, name, description}
|
|
|
|
};
|
|
|
|
}
|
2016-02-27 16:23:58 +05:30
|
|
|
|
|
|
|
export const SET_OAUTH = 'set_oauth';
|
|
|
|
export function setOAuthRequest(oauth) {
|
|
|
|
return {
|
|
|
|
type: SET_OAUTH,
|
|
|
|
payload: {
|
|
|
|
clientId: oauth.client_id,
|
|
|
|
redirectUrl: oauth.redirect_uri,
|
|
|
|
responseType: oauth.response_type,
|
|
|
|
scope: oauth.scope,
|
|
|
|
state: oauth.state
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2016-02-29 23:46:33 +05:30
|
|
|
|
2016-03-15 12:06:13 +05:30
|
|
|
export const SET_OAUTH_RESULT = 'set_oauth_result';
|
|
|
|
export function setOAuthCode(oauth) {
|
|
|
|
return {
|
|
|
|
type: SET_OAUTH_RESULT,
|
|
|
|
payload: {
|
|
|
|
success: oauth.success,
|
|
|
|
code: oauth.code,
|
|
|
|
displayCode: oauth.displayCode
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-04-15 01:24:35 +05:30
|
|
|
export const REQUIRE_PERMISSIONS_ACCEPT = 'require_permissions_accept';
|
|
|
|
export function requirePermissionsAccept() {
|
|
|
|
return {
|
|
|
|
type: REQUIRE_PERMISSIONS_ACCEPT
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-02-29 23:46:33 +05:30
|
|
|
export const SET_SCOPES = 'set_scopes';
|
|
|
|
export function setScopes(scopes) {
|
|
|
|
if (!(scopes instanceof Array)) {
|
|
|
|
throw new Error('Scopes must be array');
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
type: SET_SCOPES,
|
|
|
|
payload: scopes
|
|
|
|
};
|
|
|
|
}
|
2016-04-02 16:28:54 +05:30
|
|
|
|
|
|
|
|
|
|
|
export const SET_LOADING_STATE = 'set_loading_state';
|
|
|
|
export function setLoadingState(isLoading) {
|
|
|
|
return {
|
|
|
|
type: SET_LOADING_STATE,
|
|
|
|
payload: isLoading
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function wrapInLoader(fn) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
dispatch(setLoadingState(true));
|
|
|
|
const endLoading = () => dispatch(setLoadingState(false));
|
|
|
|
|
|
|
|
return Reflect.apply(fn, null, [dispatch, getState]).then((resp) => {
|
|
|
|
endLoading();
|
|
|
|
|
|
|
|
return resp;
|
|
|
|
}, (resp) => {
|
|
|
|
endLoading();
|
|
|
|
|
|
|
|
return Promise.reject(resp);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
2016-04-15 09:39:04 +05:30
|
|
|
|
|
|
|
function needActivation() {
|
|
|
|
return updateUser({
|
|
|
|
isActive: false,
|
|
|
|
isGuest: false
|
|
|
|
});
|
|
|
|
}
|
2016-05-15 02:23:58 +05:30
|
|
|
|
2016-06-04 19:16:39 +05:30
|
|
|
function authHandler(dispatch) {
|
|
|
|
return (resp) => dispatch(authenticate(resp.access_token, resp.refresh_token));
|
|
|
|
}
|
|
|
|
|
2016-05-22 20:46:51 +05:30
|
|
|
function validationErrorsHandler(dispatch, repeatUrl) {
|
2016-05-15 02:23:58 +05:30
|
|
|
return (resp) => {
|
|
|
|
if (resp.errors) {
|
2016-05-22 20:46:51 +05:30
|
|
|
const error = {
|
|
|
|
type: resp.errors[Object.keys(resp.errors)[0]],
|
|
|
|
payload: {
|
|
|
|
isGuest: true
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-05-22 19:31:31 +05:30
|
|
|
if (resp.data) {
|
2016-05-22 20:46:51 +05:30
|
|
|
Object.assign(error.payload, resp.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (['error.key_not_exists', 'error.key_expire'].includes(error.type) && repeatUrl) {
|
|
|
|
Object.assign(error.payload, {
|
|
|
|
repeatUrl
|
|
|
|
});
|
2016-05-22 19:31:31 +05:30
|
|
|
}
|
|
|
|
|
2016-05-22 20:46:51 +05:30
|
|
|
dispatch(setError(error));
|
2016-05-15 02:23:58 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
}
|