diff --git a/src/components/auth/OAuthInit.jsx b/src/components/auth/OAuthInit.jsx
index 48e9e07..858e327 100644
--- a/src/components/auth/OAuthInit.jsx
+++ b/src/components/auth/OAuthInit.jsx
@@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
-import { oAuthValidate } from 'components/auth/actions';
+import { oAuthValidate, oAuthComplete } from 'components/auth/actions';
class OAuthInit extends Component {
static displayName = 'OAuthInit';
@@ -27,7 +27,7 @@ class OAuthInit extends Component {
responseType: query.response_type,
scope: query.scope,
state: query.state
- });
+ }).then(this.props.complete);
}
render() {
@@ -38,5 +38,6 @@ class OAuthInit extends Component {
export default connect((state) => ({
query: state.routing.location.query
}), {
- validate: oAuthValidate
+ validate: oAuthValidate,
+ complete: oAuthComplete
})(OAuthInit);
diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx
index 6ac854b..34f1749 100644
--- a/src/components/auth/PanelTransition.jsx
+++ b/src/components/auth/PanelTransition.jsx
@@ -345,5 +345,6 @@ export default connect((state) => ({
register: actions.register,
activate: actions.activate,
clearErrors: actions.clearErrors,
+ oAuthComplete: actions.oAuthComplete,
setError: actions.setError
})(PanelTransition);
diff --git a/src/components/auth/Permissions.jsx b/src/components/auth/Permissions.jsx
index 102b782..7cc8f11 100644
--- a/src/components/auth/Permissions.jsx
+++ b/src/components/auth/Permissions.jsx
@@ -15,6 +15,7 @@ class Body extends BaseAuthBody {
static propTypes = {
...BaseAuthBody.propTypes,
login: PropTypes.func.isRequired,
+ oAuthComplete: PropTypes.func.isRequired,
auth: PropTypes.shape({
error: PropTypes.string,
login: PropTypes.shape({
@@ -24,6 +25,8 @@ class Body extends BaseAuthBody {
};
render() {
+ const {user} = this.props;
+
return (
{this.renderErrors()}
@@ -31,14 +34,16 @@ class Body extends BaseAuthBody {
- {/*
*/}
-
+ {user.avatar
+ ?
+ :
+ }
- {'erickskrauch@yandex.ru'}
+ {user.email}
@@ -59,7 +64,9 @@ class Body extends BaseAuthBody {
}
onFormSubmit() {
- // TODO
+ this.props.oAuthComplete({
+ accept: true
+ });
}
}
diff --git a/src/components/auth/actions.js b/src/components/auth/actions.js
index 6ed4d3a..c07ab9e 100644
--- a/src/components/auth/actions.js
+++ b/src/components/auth/actions.js
@@ -138,38 +138,78 @@ export function logout() {
// 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
-export function oAuthValidate({clientId, redirectUrl, responseType, scope, state}) {
+export function oAuthValidate(oauth) {
return (dispatch) =>
request.get(
'/api/oauth/validate',
- {
- client_id: clientId,
- redirect_uri: redirectUrl,
- response_type: responseType,
- scope,
- state
- }
+ getOAuthRequest(oauth)
)
.then((resp) => {
dispatch(setClient(resp.client));
- dispatch(routeActions.push('/oauth/permissions'));
+ dispatch(setOAuthRequest(resp.oAuth));
})
.catch((resp = {}) => { // TODO
- if (resp.statusCode === 400 && resp.error === 'invalid_request') {
- alert(`Invalid request (${resp.parameter} required).`);
- }
- if (resp.statusCode === 401 && resp.error === 'invalid_client') {
- alert('Can not find application you are trying to authorize.');
- }
- if (resp.statusCode === 400 && resp.error === 'unsupported_response_type') {
- alert(`Invalid response type '${resp.parameter}'.`);
- }
- if (resp.statusCode === 400 && resp.error === 'invalid_scope') {
- alert(`Invalid scope '${resp.parameter}'.`);
+ handleOauthParamsValidation(resp);
+ if (resp.statusCode === 401 && resp.error === 'accept_required') {
+ alert('Accept required.');
}
});
}
+export function oAuthComplete(params = {}) {
+ return (dispatch, getState) => {
+ 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}
+ )
+ .then((resp) => {
+ if (resp.redirectUri) {
+ location.href = resp.redirectUri;
+ }
+ })
+ .catch((resp = {}) => { // TODO
+ handleOauthParamsValidation(resp);
+
+ if (resp.statusCode === 401 && resp.error === 'accept_required') {
+ dispatch(routeActions.push('/oauth/permissions'));
+ }
+
+ if (resp.statusCode === 401 && resp.error === 'access_denied') {
+ // user declined permissions
+ location.href = resp.redirectUri;
+ }
+ });
+ };
+}
+
+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 = {}) {
+ if (resp.statusCode === 400 && resp.error === 'invalid_request') {
+ alert(`Invalid request (${resp.parameter} required).`);
+ }
+ if (resp.statusCode === 400 && resp.error === 'unsupported_response_type') {
+ alert(`Invalid response type '${resp.parameter}'.`);
+ }
+ if (resp.statusCode === 400 && resp.error === 'invalid_scope') {
+ alert(`Invalid scope '${resp.parameter}'.`);
+ }
+ if (resp.statusCode === 401 && resp.error === 'invalid_client') {
+ alert('Can not find application you are trying to authorize.');
+ }
+}
+
export const SET_CLIENT = 'set_client';
export function setClient({id, name, description}) {
return {
@@ -177,3 +217,17 @@ export function setClient({id, name, description}) {
payload: {id, name, description}
};
}
+
+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
+ }
+ };
+}
diff --git a/src/components/auth/reducer.js b/src/components/auth/reducer.js
index da79a42..55a6a42 100644
--- a/src/components/auth/reducer.js
+++ b/src/components/auth/reducer.js
@@ -1,10 +1,11 @@
import { combineReducers } from 'redux';
-import { ERROR, SET_CLIENT } from './actions';
+import { ERROR, SET_CLIENT, SET_OAUTH } from './actions';
export default combineReducers({
error,
- client
+ client,
+ oauth
});
function error(
@@ -39,3 +40,22 @@ function client(
return state;
}
}
+
+function oauth(
+ state = null,
+ {type, payload = {}}
+) {
+ switch (type) {
+ case SET_OAUTH:
+ return {
+ clientId: payload.clientId,
+ redirectUrl: payload.redirectUrl,
+ responseType: payload.responseType,
+ scope: payload.scope,
+ state: payload.state
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/src/routes.js b/src/routes.js
index 69db693..27d9888 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -37,6 +37,8 @@ export default function routesFactory(store) {
}
}
+ // TODO: validate that we have all required data on premissions page
+
if (forcePath && pathname !== forcePath) {
switch (pathname) {
case '/':
diff --git a/src/services/request.js b/src/services/request.js
index af3255c..511c023 100644
--- a/src/services/request.js
+++ b/src/services/request.js
@@ -1,4 +1,4 @@
-function serialize(data) {
+function buildQuery(data) {
return Object.keys(data)
.map(
(keyName) =>
@@ -33,7 +33,7 @@ export default {
...getDefaultHeaders(),
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
- body: serialize(data)
+ body: buildQuery(data)
})
.then(toJSON)
.then(handleResponse)
@@ -43,7 +43,7 @@ export default {
get(url, data) {
if (typeof data === 'object') {
const separator = url.indexOf('?') === -1 ? '?' : '&';
- url += separator + serialize(data);
+ url += separator + buildQuery(data);
}
return fetch(url, {
@@ -54,6 +54,8 @@ export default {
;
},
+ buildQuery,
+
setAuthToken(tkn) {
authToken = tkn;
}