Skip to content

Commit

Permalink
Merge pull request #8 from FoxComm/sync/use-api-js-for-auth
Browse files Browse the repository at this point in the history
Using api-js in auth, fixed login behaviour
  • Loading branch information
arodionova authored Jun 22, 2016
2 parents fcfcfa4 + 460fa7c commit a4a30fc
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 204 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"watchify": "^3.7.0"
},
"dependencies": {
"api-js": "github:foxcomm/api-js#v0.2.1",
"classnames": "^2.2.3",
"core-decorators": "^0.11.0",
"currency-symbol-map": "^2.2.0",
Expand Down
6 changes: 3 additions & 3 deletions src/components/auth/auth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import React, { Component } from 'react';
import { Link } from 'react-router';
import { authBlockTypes } from 'paragons/auth';
import { assoc } from 'sprout-data';
import { assoc, dissoc } from 'sprout-data';
import { autobind } from 'core-decorators';

import styles from './auth.css';
Expand Down Expand Up @@ -43,8 +43,8 @@ class Auth extends Component {
}

@autobind
getPath(newType: string): Object {
return assoc(this.props.path, ['query', 'auth'], newType);
getPath(newType: ?string): Object {
return newType ? assoc(this.props.path, ['query', 'auth'], newType) : dissoc(this.props.path, ['query', 'auth']);
}

render(): HTMLElement {
Expand Down
2 changes: 1 addition & 1 deletion src/components/auth/login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Login extends Component {
this.props.authenticate({email, password, kind}).then(() => {
this.props.fetchCart();
browserHistory.push(this.props.getPath());
}).catch(() => {
}, () => {
this.setState({error: 'Email or password is invalid'});
});
}
Expand Down
174 changes: 4 additions & 170 deletions src/core/lib/api.js
Original file line number Diff line number Diff line change
@@ -1,174 +1,8 @@

/* @flow weak */

import fetch from 'isomorphic-fetch';
import type { Promise as PromiseType } from 'types/promise';

import Api from 'api-js';
const isServer: boolean = typeof self === 'undefined';

export function appendQueryString(url: string, queryString: ?string): string {
if (!queryString) {
return url;
}
const joinWith = url.indexOf('?') != -1 ? '&' : '?';

return `${url}${joinWith}${queryString}`;
}

type Params = {
[key: string]: string|Object|number|boolean;
};

function serialize(data: Params): string {
const params: string[] = [];
for (const param in data) {
if (data.hasOwnProperty(param)) {
const value = data[param];
if (value != null) {
const asString: string = typeof value != 'string' ? JSON.stringify(value) : value;
params.push(`${encodeURIComponent(param)}'='${encodeURIComponent(asString)}`);
}
}
}
return params.join('&');
}

// Removing this will BREAK Demo Storefront because we use
// basic auth to protect access to the frontend since it is publically
// accessible
function demoAuthHeader(): string|void {
const demoToken = process.env.DEMO_AUTH_TOKEN;
return demoToken ? `Basic ${demoToken}` : void 0;
}

type RequestOptions = {
method?: string;
headers?: {[key: string]: string|void};
body?: string;
};

type ResponseError = {
response: any;
responseJson: any;
};

/* eslint-disable no-param-reassign */

export function request(method: string, uri: string, data: ?Params, options: ?RequestOptions): PromiseType {
const defaultHeaders = {
'Content-Type': 'application/json;charset=UTF-8',
Authorization: demoAuthHeader(),
};

options = {
...options || {},
credentials: 'same-origin',
method: method.toUpperCase(),
headers: {
...defaultHeaders,
...(options && options.headers || {}),
},
};

if (data) {
if (method.toUpperCase() === 'GET') {
const queryString = serialize(data);
if (queryString) {
uri = appendQueryString(uri, queryString);
}
} else {
options.body = JSON.stringify(data);
}
}

// $FlowFixMe
let error: ?ResponseError = null;

return fetch(uri, options)
.then(response => {
if (response.status < 200 || response.status >= 300) {
error = new Error(response.statusText);
// $FlowFixMe
error.response = response;
}

return response;
})
.then(response => response.text())
.then(responseText => {
let json = null;
if (responseText) {
try {
json = JSON.parse(responseText);
} catch (ex) {
// invalid json
}
}

if (error) {
error.responseJson = json;
throw error;
}

return json;
});
}

/* eslint-enable no-param-reassign */


class Api {
prefix: string;
headers: ?Object;

constructor(prefix: ?string = '') {
// $FlowFixMe: flow why you don't count default values
this.prefix = prefix;
}

addHeaders(headers) {
this.headers = headers;

return this;
}

addAuth(jwt) {
this.headers = {
...this.headers,
JWT: jwt,
};

return this;
}

request(method: string, uri: string, data: ?Params, options: RequestOptions = {}): PromiseType {
const finalUrl = `${this.prefix}${uri}`;

if (this.headers) {
options.headers = { // eslint-disable-line no-param-reassign
...this.headers,
...(options.headers || {}),
};
}

return request(method, finalUrl, data, options);
}

get(...args: Array<any>): PromiseType {
return this.request('get', ...args);
}

post(...args: Array<any>): PromiseType {
return this.request('post', ...args);
}

patch(...args: Array<any>): PromiseType {
return this.request('patch', ...args);
}

delete(...args: Array<any>): PromiseType {
return this.request('delete', ...args);
}
}

export const api = new Api(isServer ? `${process.env.API_URL}/api` : '/api');
export const api = new Api({
api_url: isServer ? `${process.env.API_URL}/api` : '/api',
});
39 changes: 9 additions & 30 deletions src/core/modules/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { createAction, createReducer } from 'redux-act';
import createAsyncActions from './async-utils';
import fetch from 'isomorphic-fetch';
import { dissoc } from 'sprout-data';
import { api } from 'lib/api';

Expand All @@ -26,56 +25,36 @@ export const setUser = createAction('USER_SET');
export const removeUser = createAction('REMOVE_USER');
export const setJwt = createAction('AUTH_SET_JWT');

const headers = {'Content-Type': 'application/json;charset=UTF-8'};

export const signUp = createAsyncActions('auth-signup', function signUp(payload: SignUpPayload): Promise {
return api.post('/v1/public/registrations/new', payload);
const {email, name, password} = payload;
return api.auth.signup(email, name, password);
}).perform;

export const authenticate = createAsyncActions('auth-login', function authenticate(payload: LoginPayload): Promise {
return fetch('/api/v1/public/login', {
method: 'POST',
body: JSON.stringify(payload),
credentials: 'same-origin',
headers,
})
.then(response => {
const jwt = response.headers.get('jwt');
if (response.status == 200 && jwt) {
localStorage.setItem('jwt', jwt);
this.dispatch(setJwt(jwt));
return response.json();
}
throw new Error('Server error, try again later. Sorry for inconvenience :(');
})
.then((token) => {
if (token.email && token.name) {
localStorage.setItem('user', JSON.stringify(token));
this.dispatch(setUser(token));
return;
}
throw new Error('Server error, try again later. Sorry for inconvenience :(');
const {email, password, kind} = payload;
return api.auth.login(email, password, kind)
.then(({jwt, user}) => {
this.dispatch(setJwt(jwt));
this.dispatch(setUser(user));
});
}).perform;

export function googleSignin(): asyncAction<void> {
return () => {
api.get('/v1/public/signin/google/customer').then(urlInfo => {
api.auth.googleSignin().then(urlInfo => {
window.location.href = urlInfo.url;
});
};
}

export const logout = createAsyncActions('auth-logout', function logout(): Promise {
return api.post('/v1/public/logout')
return api.auth.logout()
.then(() => {
this.dispatch(removeUser());
localStorage.removeItem('user');
});
}).perform;

const initialState = {
inProgress: false,
};

const reducer = createReducer({
Expand Down

0 comments on commit a4a30fc

Please sign in to comment.