accounts-frontend/src/components/auth/actions.js

313 lines
8.9 KiB
JavaScript
Raw Normal View History

import { routeActions } from 'react-router-redux';
import { updateUser, logout as logoutUser, changePassword as changeUserPassword, authenticate } from 'components/user/actions';
import request from 'services/request';
export function login({login = '', password = '', rememberMe = false}) {
const PASSWORD_REQUIRED = 'error.password_required';
const LOGIN_REQUIRED = 'error.login_required';
const ACTIVATION_REQUIRED = 'error.account_not_activated';
return wrapInLoader((dispatch) =>
request.post(
'/api/authentication/login',
{login, password, rememberMe}
)
2016-02-26 11:55:47 +05:30
.then((resp) => {
dispatch(updateUser({
2016-02-26 11:55:47 +05:30
isGuest: false,
token: resp.jwt
}));
2016-03-02 02:06:14 +05:30
return dispatch(authenticate(resp.jwt));
})
.catch((resp) => {
if (resp.errors.login === ACTIVATION_REQUIRED) {
2016-03-02 02:06:14 +05:30
return dispatch(updateUser({
isActive: false,
isGuest: false
}));
} else if (resp.errors.password === PASSWORD_REQUIRED) {
2016-03-02 02:06:14 +05:30
return dispatch(updateUser({
username: login,
email: login
}));
} else if (resp.errors) {
if (resp.errors.login === LOGIN_REQUIRED && password) {
dispatch(logout());
}
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
dispatch(setError(errorMessage));
2016-03-02 02:06:14 +05:30
throw new Error(errorMessage);
}
// TODO: log unexpected errors
})
);
}
export function changePassword({
password = '',
newPassword = '',
newRePassword = ''
}) {
return wrapInLoader((dispatch) =>
dispatch(changeUserPassword({password, newPassword, newRePassword}))
.catch((resp) => {
if (resp.errors) {
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
dispatch(setError(errorMessage));
throw new Error(errorMessage);
}
// TODO: log unexpected errors
})
);
}
export function register({
email = '',
username = '',
password = '',
rePassword = '',
rulesAgreement = false
}) {
return wrapInLoader((dispatch) =>
request.post(
'/api/signup',
{email, username, password, rePassword, rulesAgreement}
)
.then(() => {
dispatch(updateUser({
username,
email,
isGuest: false
}));
dispatch(routeActions.push('/activation'));
})
.catch((resp) => {
if (resp.errors) {
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
dispatch(setError(errorMessage));
throw new Error(errorMessage);
}
// TODO: log unexpected errors
})
);
}
export function activate({key = ''}) {
return wrapInLoader((dispatch) =>
request.post(
'/api/signup/confirm',
{key}
)
.then((resp) => {
dispatch(updateUser({
2016-03-02 02:06:14 +05:30
isGuest: false,
isActive: true
}));
2016-03-02 02:06:14 +05:30
return dispatch(authenticate(resp.jwt));
})
.catch((resp) => {
const errorMessage = resp.errors[Object.keys(resp.errors)[0]];
dispatch(setError(errorMessage));
2016-03-02 02:06:14 +05:30
throw new Error(errorMessage);
// TODO: log unexpected errors
})
);
}
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-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) {
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));
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);
if (resp.statusCode === 401 && resp.error === 'accept_required') {
alert('Accept required.');
2016-02-23 11:27:16 +05:30
}
})
);
2016-02-27 16:23:58 +05:30
}
export function oAuthComplete(params = {}) {
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 {
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;
throw error;
2016-02-23 11:27:16 +05:30
}
})
.then((resp) => {
if (resp.redirectUri.startsWith('static_page')) {
resp.code = resp.redirectUri.match(/code=(.+)&/)[1];
resp.redirectUri = resp.redirectUri.match(/^(.+)\?/)[1];
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-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-03-02 02:06:14 +05:30
const error = new Error('Error completing request');
2016-02-27 16:23:58 +05:30
if (resp.statusCode === 400 && resp.error === 'invalid_request') {
alert(`Invalid request (${resp.parameter} required).`);
2016-03-02 02:06:14 +05:30
throw error;
2016-02-27 16:23:58 +05:30
}
if (resp.statusCode === 400 && resp.error === 'unsupported_response_type') {
alert(`Invalid response type '${resp.parameter}'.`);
2016-03-02 02:06:14 +05:30
throw error;
2016-02-27 16:23:58 +05:30
}
if (resp.statusCode === 400 && resp.error === 'invalid_scope') {
alert(`Invalid scope '${resp.parameter}'.`);
2016-03-02 02:06:14 +05:30
throw error;
2016-02-27 16:23:58 +05:30
}
if (resp.statusCode === 401 && resp.error === 'invalid_client') {
alert('Can not find application you are trying to authorize.');
2016-03-02 02:06:14 +05:30
throw error;
2016-02-27 16:23:58 +05:30
}
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
}
};
}
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
}
};
}
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
};
}
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);
});
};
}