From 744ba7ffed1a6ad0cabf592cdc331db11eae4655 Mon Sep 17 00:00:00 2001 From: Mohamed El Mahallawy Date: Tue, 10 Jan 2017 11:43:44 -0800 Subject: [PATCH 1/2] Devise Token Auth for one quran --- src/components/FacebookTokenButton/index.js | 34 +++++++++++++++++++ src/components/FacebookTokenButton/style.scss | 6 ++++ src/components/IndexHeader/Nav/index.js | 2 +- src/containers/Login/index.js | 25 ++++++++++++-- src/containers/Profile/index.js | 2 +- src/helpers/ApiClient.js | 17 ++++++++-- src/locale/ar.js | 4 ++- src/locale/en.js | 6 ++-- src/locale/ur.js | 4 ++- src/redux/actions/auth.js | 9 +++-- src/redux/actions/bookmarks.js | 6 ++-- src/redux/constants/auth.js | 1 + src/redux/modules/auth.js | 19 ++++++++++- src/styles/main.scss | 4 +++ src/utils/checkValidSurah.js | 6 ++-- 15 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 src/components/FacebookTokenButton/index.js create mode 100644 src/components/FacebookTokenButton/style.scss diff --git a/src/components/FacebookTokenButton/index.js b/src/components/FacebookTokenButton/index.js new file mode 100644 index 000000000..bde0a3327 --- /dev/null +++ b/src/components/FacebookTokenButton/index.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +import { save } from 'redux/actions/auth'; +import { push } from 'react-router-redux'; + +const styles = require('./style.scss'); + +const FacebookTokenButton = ({ save, push }) => { // eslint-disable-line + let popup = null; + let interval = null; + + const handleClick = () => { + popup = window.open('/onequran/omniauth/facebook?omniauth_window_type=newWindow&resource_class=User', '_blank'); // eslint-disable-line + interval = setInterval(() => popup.postMessage('requestCredentials', '*'), 1000); + + window.addEventListener('message', (event) => { // eslint-disable-line + if (event.data.uid) { + save(event.data); + clearInterval(interval); + + return push('/'); + } + }, false); + }; + + return ( + + ); +}; + +export default connect(null, { save, push })(FacebookTokenButton); diff --git a/src/components/FacebookTokenButton/style.scss b/src/components/FacebookTokenButton/style.scss new file mode 100644 index 000000000..dbebfa10f --- /dev/null +++ b/src/components/FacebookTokenButton/style.scss @@ -0,0 +1,6 @@ +.button{ + background: #3B5998; + border-color: #3B5998; + color: #fff; + font-weight: 300; +} diff --git a/src/components/IndexHeader/Nav/index.js b/src/components/IndexHeader/Nav/index.js index 09759b452..d0b631592 100644 --- a/src/components/IndexHeader/Nav/index.js +++ b/src/components/IndexHeader/Nav/index.js @@ -75,7 +75,7 @@ export class IndexHeaderNav extends Component { user &&
  • - {user.firstName} + {user.firstName || user.name}
  • } diff --git a/src/containers/Login/index.js b/src/containers/Login/index.js index 16f8c67b2..618f687ba 100644 --- a/src/containers/Login/index.js +++ b/src/containers/Login/index.js @@ -1,9 +1,28 @@ import React from 'react'; -import FacebookButton from 'components/FacebookButton'; +import FacebookTokenButton from 'components/FacebookTokenButton'; +import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; + +const logo = require('../../../static/images/logo-lg.png'); export default () => ( -
    - +
    +
    +
    +
    +
    + logo +

    Quran.com

    +
    +

    + +

    + +
    +
    +
    ); diff --git a/src/containers/Profile/index.js b/src/containers/Profile/index.js index 5877ff712..acb4451b9 100644 --- a/src/containers/Profile/index.js +++ b/src/containers/Profile/index.js @@ -24,7 +24,7 @@ class Profile extends Component { // eslint-disable-line const { user, bookmarks } = this.props; return ( -
    +
    diff --git a/src/helpers/ApiClient.js b/src/helpers/ApiClient.js index dacf36671..0462f9461 100644 --- a/src/helpers/ApiClient.js +++ b/src/helpers/ApiClient.js @@ -38,8 +38,9 @@ export default class { })); } - if (cookie.load('accessToken')) { - request.set('Authorization', `Bearer ${cookie.load('accessToken')}`); + if (cookie.load('auth')) { + const headers = cookie.load('auth'); + Object.keys(headers).forEach(key => request.set(key, headers[key])); } if (__SERVER__ && req.get('cookie')) { @@ -50,11 +51,21 @@ export default class { request.send(decamelizeKeys(data)); } - request.end((err, { body } = {}) => { + request.end((err, { header, body } = {}) => { if (err) { return reject(body || err); } + if (header['access-token']) { + cookie.save('auth', { + 'access-token': header['access-token'], + client: header.client, + expiry: header.expiry, + uid: header.uid, + 'token-type': 'Bearer' + }); + } + return resolve(body); }); }); diff --git a/src/locale/ar.js b/src/locale/ar.js index 385b83cd0..81cebe42f 100644 --- a/src/locale/ar.js +++ b/src/locale/ar.js @@ -67,6 +67,8 @@ export default { 'nav.aboutQuranProject': 'Quran.com المعروف أيضا باسم القرآن الكريم، قناة القرآن الكريم، القرآن الكريم، القرآن الكريم) هو مشروع خيري)', // eslint-disable-line max-len 'nav.mobile': 'التليفون المحمول', 'nav.navigate': 'انتقل', - 'nav.legacySite': 'الموقع القديم' + 'nav.legacySite': 'الموقع القديم', + + 'login.message': 'تسجيل الدخول إلى Quran.com لتخزين كل ما تبذلونه من العناوين والملاحظات والأنشطة.' } }; diff --git a/src/locale/en.js b/src/locale/en.js index 5927fa3c1..4b5acc2b2 100644 --- a/src/locale/en.js +++ b/src/locale/en.js @@ -60,13 +60,15 @@ export default { 'nav.contribute': 'Contribute', 'nav.aboutUs': 'About us', - 'nav.developers': 'developers', + 'nav.developers': 'Developers', 'nav.usefulSites': 'Useful sites', 'nav.otherLinks': 'Other links', 'nav.contactUs': 'Contact us', 'nav.aboutQuranProject': 'Quran.com (also known as The Noble Quran, Al Quran, Holy Quran, Koran) is a pro bono project.', // eslint-disable-line max-len 'nav.mobile': 'Mobile', 'nav.navigate': 'Navigate', - 'nav.legacySite': 'Legacy Quran.com' + 'nav.legacySite': 'Legacy Quran.com', + + 'login.message': 'Sign in to Quran.com to store all your bookmarks, notes and activities.' } }; diff --git a/src/locale/ur.js b/src/locale/ur.js index f0d77d977..84f73e478 100644 --- a/src/locale/ur.js +++ b/src/locale/ur.js @@ -67,6 +67,8 @@ export default { 'nav.aboutQuranProject': 'قرآن کریم ایک فلاں عامہ (عوامی بہبود کے لئے) منصوبہ ہے', 'nav.mobile': 'موبائل', 'nav.navigate': 'تشریف لے جائیں', - 'nav.legacySite': 'پرانی سائٹ' + 'nav.legacySite': 'پرانی سائٹ', + + 'login.message': 'Quran.com کرنے کیلئے سائن ان سب کو اپنے بک مارکس، نوٹوں اور سرگرمیوں کو ذخیرہ کرنے.' } }; diff --git a/src/redux/actions/auth.js b/src/redux/actions/auth.js index 28e9bd834..732795bed 100644 --- a/src/redux/actions/auth.js +++ b/src/redux/actions/auth.js @@ -5,6 +5,7 @@ import { FACEBOOK_SUCCESS, FACEBOOK_FAILURE, LOGOUT_SUCCESS, + SAVE, LOAD, LOAD_SUCCESS, LOAD_FAILURE @@ -17,17 +18,21 @@ export function isLoaded(globalState) { export function load() { return { types: [LOAD, LOAD_SUCCESS, LOAD_FAILURE], - promise: client => client.get('/onequran/api/v1/auth/current') + promise: client => client.get('/onequran/auth/validate_token') }; } export function facebook() { return { types: [FACEBOOK, FACEBOOK_SUCCESS, FACEBOOK_FAILURE], - promise: client => client.get('/onequran/auth/facebook/callback') }; } +export const save = data => ({ + type: SAVE, + data +}); + export function logout() { return { type: LOGOUT_SUCCESS diff --git a/src/redux/actions/bookmarks.js b/src/redux/actions/bookmarks.js index 536ce5ad3..6f8bf7a5f 100644 --- a/src/redux/actions/bookmarks.js +++ b/src/redux/actions/bookmarks.js @@ -19,14 +19,14 @@ export function load() { return { types: [LOAD, LOAD_SUCCESS, LOAD_FAILURE], schema: [bookmarksSchema], - promise: client => client.get('/onequran/api/v1/bookmarks') + promise: client => client.get('/onequran/api/v1/bookmarks.json') }; } export function addBookmark(ayahKey) { return { types: [ADD_BOOKMARK, ADD_BOOKMARK_SUCCESS, ADD_BOOKMARK_FAILURE], - promise: client => client.post('/onequran/api/v1/bookmarks', { + promise: client => client.post('/onequran/api/v1/bookmarks.json', { data: { bookmark: { ayahKey } } @@ -38,7 +38,7 @@ export function addBookmark(ayahKey) { export function removeBookmark(ayahKey) { return { types: [REMOVE_BOOKMARK, REMOVE_BOOKMARK_SUCCESS, REMOVE_BOOKMARK_FAILURE], - promise: client => client.del(`/onequran/api/v1/bookmarks/${ayahKey}`), + promise: client => client.del(`/onequran/api/v1/bookmarks/${ayahKey}.json`), ayahKey }; } diff --git a/src/redux/constants/auth.js b/src/redux/constants/auth.js index 1e6f3eb9a..57bba262f 100644 --- a/src/redux/constants/auth.js +++ b/src/redux/constants/auth.js @@ -2,6 +2,7 @@ export const FACEBOOK = '@@quran/auth/FACEBOOK'; export const FACEBOOK_SUCCESS = '@@quran/auth/FACEBOOK_SUCCESS'; export const FACEBOOK_FAILURE = '@@quran/auth/FACEBOOK_FAILURE'; export const LOGOUT_SUCCESS = '@@quran/auth/LOGOUT_SUCCESS'; +export const SAVE = '@@quran/auth/SAVE'; export const LOAD = '@@quran/auth/LOAD'; export const LOAD_SUCCESS = '@@quran/auth/LOAD_SUCCESS'; export const LOAD_FAILURE = '@@quran/auth/LOAD_FAILURE'; diff --git a/src/redux/modules/auth.js b/src/redux/modules/auth.js index ab786e860..d91bb5c9b 100644 --- a/src/redux/modules/auth.js +++ b/src/redux/modules/auth.js @@ -5,7 +5,8 @@ import { FACEBOOK_FAILURE, LOGOUT_SUCCESS, LOAD_SUCCESS, - LOAD_FAILURE + LOAD_FAILURE, + SAVE } from 'redux/constants/auth'; const initialState = { @@ -14,6 +15,22 @@ const initialState = { export default function reducer(state = initialState, action = {}) { switch (action.type) { + case SAVE: { + cookie.save('auth', { + client: action.data.client_id, + 'access-token': action.data.auth_token, + expiry: action.data.expiry, + uid: action.data.uid, + 'token-type': 'Bearer' + }); + + return { + ...state, + loading: false, + loaded: true, + user: action.data + }; + } case LOAD_SUCCESS: return { ...state, diff --git a/src/styles/main.scss b/src/styles/main.scss index fe32fe638..159913400 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -28,6 +28,10 @@ html,body{ } } +.min-container{ + min-height: 80vh; +} + .highlight { background-color: #F5FBF7; } diff --git a/src/utils/checkValidSurah.js b/src/utils/checkValidSurah.js index 1e88257a2..1af7bef27 100644 --- a/src/utils/checkValidSurah.js +++ b/src/utils/checkValidSurah.js @@ -1,9 +1,9 @@ export default function isValidSurah(nextState, replaceState) { const surahId = parseInt(nextState.params.surahId, 10); - if (isNaN(surahId) || surahId > 114 || surahId < 1) { - replaceState('/error/invalid-surah'); - } + // if (isNaN(surahId) || surahId > 114 || surahId < 1) { + // replaceState('/error/invalid-surah'); + // } if (nextState.params.range) { if (nextState.params.range.includes('-')) { From e006e441646ddd36c7e866b5d8963ed6e5f3450f Mon Sep 17 00:00:00 2001 From: Mohamed El Mahallawy Date: Tue, 10 Jan 2017 14:38:14 -0800 Subject: [PATCH 2/2] pr comments --- src/redux/modules/auth.js | 2 +- src/utils/checkValidSurah.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/redux/modules/auth.js b/src/redux/modules/auth.js index d91bb5c9b..9cdfe23e1 100644 --- a/src/redux/modules/auth.js +++ b/src/redux/modules/auth.js @@ -18,9 +18,9 @@ export default function reducer(state = initialState, action = {}) { case SAVE: { cookie.save('auth', { client: action.data.client_id, - 'access-token': action.data.auth_token, expiry: action.data.expiry, uid: action.data.uid, + 'access-token': action.data.auth_token, 'token-type': 'Bearer' }); diff --git a/src/utils/checkValidSurah.js b/src/utils/checkValidSurah.js index 1af7bef27..1e88257a2 100644 --- a/src/utils/checkValidSurah.js +++ b/src/utils/checkValidSurah.js @@ -1,9 +1,9 @@ export default function isValidSurah(nextState, replaceState) { const surahId = parseInt(nextState.params.surahId, 10); - // if (isNaN(surahId) || surahId > 114 || surahId < 1) { - // replaceState('/error/invalid-surah'); - // } + if (isNaN(surahId) || surahId > 114 || surahId < 1) { + replaceState('/error/invalid-surah'); + } if (nextState.params.range) { if (nextState.params.range.includes('-')) {