From 87ada30eff70bd580ae6fdb6885a682b22563a35 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 19 May 2017 17:32:16 -0300 Subject: [PATCH 01/36] =?UTF-8?q?=C3=81dding=20Stream=20Slot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Embed.js | 11 +-- .../src/components/Stream.js | 94 +++++++++---------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index 0d26cf740..2e050e836 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -1,13 +1,12 @@ import React from 'react'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from 'coral-framework/translations'; const lang = new I18n(translations); - -import {TabBar, Tab, TabContent, Button} from 'coral-ui'; - import Stream from '../containers/Stream'; -import Count from 'coral-plugin-comment-count/CommentCount'; +import Slot from 'coral-framework/components/Slot'; +import I18n from 'coral-framework/modules/i18n/i18n'; import UserBox from 'coral-sign-in/components/UserBox'; +import translations from 'coral-framework/translations'; +import {TabBar, Tab, TabContent, Button} from 'coral-ui'; +import Count from 'coral-plugin-comment-count/CommentCount'; import ProfileContainer from 'coral-settings/containers/ProfileContainer'; import RestrictedContent from 'coral-framework/components/RestrictedContent'; import ConfigureStreamContainer from 'coral-configure/containers/ConfigureStreamContainer'; diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js index 90fa0aca8..e0c541341 100644 --- a/client/coral-embed-stream/src/components/Stream.js +++ b/client/coral-embed-stream/src/components/Stream.js @@ -4,6 +4,7 @@ import {Button} from 'coral-ui'; import LoadMore from './LoadMore'; import NewCount from './NewCount'; import Comment from '../containers/Comment'; +import Slot from 'coral-framework/components/Slot'; import InfoBox from 'coral-plugin-infobox/InfoBox'; import {ModerationLink} from 'coral-plugin-moderation'; import CommentBox from 'coral-plugin-commentbox/CommentBox'; @@ -15,7 +16,7 @@ import ChangeUsernameContainer from 'coral-sign-in/containers/ChangeUsernameContainer'; class Stream extends React.Component { - setActiveReplyBox = (reactKey) => { + setActiveReplyBox = reactKey => { if (!this.props.auth.user) { this.props.showSignInDialog(); } else { @@ -58,11 +59,20 @@ class Stream extends React.Component { const firstCommentDate = asset.comments[0] ? asset.comments[0].created_at : new Date(Date.now() - 1000 * 60 * 60 * 24 * 7).toISOString(); - const commentIsIgnored = (comment) => { - return me && me.ignoredUsers && me.ignoredUsers.find((u) => u.id === comment.user.id); + const commentIsIgnored = comment => { + return ( + me && + me.ignoredUsers && + me.ignoredUsers.find(u => u.id === comment.user.id) + ); }; return (
+ + + {open ?
:

{asset.settings.closedMessage}

} - {!loggedIn && - } {loggedIn && user && } {loggedIn && } - {/* the highlightedComment is isolated after the user followed a permalink */} {highlightedComment ?
- {comments.map( - (comment) => { - return (commentIsIgnored(comment) - ? - : - ); - } - )} + {comments.map(comment => { + return commentIsIgnored(comment) + ? + : ; + })}
Date: Fri, 19 May 2017 17:32:54 -0300 Subject: [PATCH 02/36] Adding coral-plugin-auth --- .gitignore | 1 + plugins/coral-plugin-auth/client/.babelrc | 14 +++++++++++ .../coral-plugin-auth/client/.eslintrc.json | 23 +++++++++++++++++++ .../client/components/SignInButton.js | 22 ++++++++++++++++++ plugins/coral-plugin-auth/client/index.js | 7 ++++++ .../client/translations.json | 10 ++++++++ plugins/coral-plugin-auth/index.js | 1 + 7 files changed, 78 insertions(+) create mode 100644 plugins/coral-plugin-auth/client/.babelrc create mode 100644 plugins/coral-plugin-auth/client/.eslintrc.json create mode 100644 plugins/coral-plugin-auth/client/components/SignInButton.js create mode 100644 plugins/coral-plugin-auth/client/index.js create mode 100644 plugins/coral-plugin-auth/client/translations.json create mode 100644 plugins/coral-plugin-auth/index.js diff --git a/.gitignore b/.gitignore index f0c3b2a4b..11e738d57 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ coverage/ plugins.json plugins/* !plugins/coral-plugin-facebook-auth +!plugins/coral-plugin-auth !plugins/coral-plugin-respect !plugins/coral-plugin-offtopic !plugins/coral-plugin-like diff --git a/plugins/coral-plugin-auth/client/.babelrc b/plugins/coral-plugin-auth/client/.babelrc new file mode 100644 index 000000000..60be246eb --- /dev/null +++ b/plugins/coral-plugin-auth/client/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "add-module-exports", + "transform-class-properties", + "transform-decorators-legacy", + "transform-object-assign", + "transform-object-rest-spread", + "transform-async-to-generator", + "transform-react-jsx" + ] +} \ No newline at end of file diff --git a/plugins/coral-plugin-auth/client/.eslintrc.json b/plugins/coral-plugin-auth/client/.eslintrc.json new file mode 100644 index 000000000..9fe56bd14 --- /dev/null +++ b/plugins/coral-plugin-auth/client/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "rules": { + "react/jsx-uses-react": "error", + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] + } +} diff --git a/plugins/coral-plugin-auth/client/components/SignInButton.js b/plugins/coral-plugin-auth/client/components/SignInButton.js new file mode 100644 index 000000000..fb58eeb9b --- /dev/null +++ b/plugins/coral-plugin-auth/client/components/SignInButton.js @@ -0,0 +1,22 @@ +import React from 'react'; +import {Button} from 'coral-ui'; +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import {showSignInDialog} from 'coral-framework/actions/auth'; + +class SignInButton extends React.Component { + render() { + return ( + + ); + } +} + +const mapStateToProps = ({auth}) => ({auth}); + +const mapDispatchToProps = dispatch => + bindActionCreators({showSignInDialog}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(SignInButton); diff --git a/plugins/coral-plugin-auth/client/index.js b/plugins/coral-plugin-auth/client/index.js new file mode 100644 index 000000000..ff601992b --- /dev/null +++ b/plugins/coral-plugin-auth/client/index.js @@ -0,0 +1,7 @@ +import SignInButton from './components/SignInButton'; + +export default { + slots: { + stream: [SignInButton] + } +}; \ No newline at end of file diff --git a/plugins/coral-plugin-auth/client/translations.json b/plugins/coral-plugin-auth/client/translations.json new file mode 100644 index 000000000..93d73d3a2 --- /dev/null +++ b/plugins/coral-plugin-auth/client/translations.json @@ -0,0 +1,10 @@ +{ + "en": { + "like": "Like", + "liked": "Liked" + }, + "es": { + "like": "Me Gusta", + "liked": "Me Gustó" + } +} diff --git a/plugins/coral-plugin-auth/index.js b/plugins/coral-plugin-auth/index.js new file mode 100644 index 000000000..a09954537 --- /dev/null +++ b/plugins/coral-plugin-auth/index.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file From 3af49de0cefc45c43d1226ff2654b87cd0bb6d5f Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 19 May 2017 18:04:54 -0300 Subject: [PATCH 03/36] New login slots and auth plugins --- client/coral-embed-stream/src/AppRouter.js | 6 +- .../containers/LoginContainer.js | 6 + .../containers/SignInContainer.js | 223 +----------------- .../client/components/SignInContainer.js | 210 +++++++++++++++++ plugins/coral-plugin-auth/client/index.js | 4 +- 5 files changed, 226 insertions(+), 223 deletions(-) create mode 100644 client/coral-sign-in/containers/LoginContainer.js create mode 100644 plugins/coral-plugin-auth/client/components/SignInContainer.js diff --git a/client/coral-embed-stream/src/AppRouter.js b/client/coral-embed-stream/src/AppRouter.js index e2553889c..6ee63caab 100644 --- a/client/coral-embed-stream/src/AppRouter.js +++ b/client/coral-embed-stream/src/AppRouter.js @@ -2,12 +2,12 @@ import React from 'react'; import {Router, Route, browserHistory} from 'react-router'; import Embed from './containers/Embed'; -import SignInContainer from 'coral-sign-in/containers/SignInContainer'; +import {LoginContainer} from 'coral-sign-in/containers/LoginContainer'; const routes = (
- - + +
); diff --git a/client/coral-sign-in/containers/LoginContainer.js b/client/coral-sign-in/containers/LoginContainer.js new file mode 100644 index 000000000..fa20de4ed --- /dev/null +++ b/client/coral-sign-in/containers/LoginContainer.js @@ -0,0 +1,6 @@ +import React from 'react'; +import Slot from 'coral-framework/components/Slot'; + +export const LoginContainer = () => ( + +) \ No newline at end of file diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js index de1d2086e..b473626db 100644 --- a/client/coral-sign-in/containers/SignInContainer.js +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -1,220 +1,5 @@ -import React, {Component, PropTypes} from 'react'; -import {connect} from 'react-redux'; -import SignDialog from '../components/SignDialog'; -import validate from 'coral-framework/helpers/validate'; -import errorMsj from 'coral-framework/helpers/error'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations'; -import {pym} from 'coral-framework'; -const lang = new I18n(translations); +import React from 'react'; -import { - changeView, - fetchSignUp, - fetchSignIn, - hideSignInDialog, - fetchSignInFacebook, - fetchSignUpFacebook, - fetchForgotPassword, - requestConfirmEmail, - facebookCallback, - invalidForm, - validForm, - checkLogin -} from 'coral-framework/actions/auth'; - -class SignInContainer extends Component { - initialState = { - formData: { - email: '', - username: '', - password: '', - confirmPassword: '' - }, - emailToBeResent: '', - errors: {}, - showErrors: false - }; - - constructor(props) { - super(props); - this.state = this.initialState; - this.addError = this.addError.bind(this); - this.handleAuth = this.handleAuth.bind(this); - this.handleSignUp = this.handleSignUp.bind(this); - this.handleSignIn = this.handleSignIn.bind(this); - this.handleChange = this.handleChange.bind(this); - this.handleChangeEmail = this.handleChangeEmail.bind(this); - this.handleResendVerification = this.handleResendVerification.bind(this); - } - - static propTypes = { - requireEmailConfirmation: PropTypes.bool.isRequired - }; - - componentWillMount() { - this.props.checkLogin(); - } - - componentDidMount() { - window.addEventListener('storage', this.handleAuth); - - const {formData} = this.state; - const errors = Object.keys(formData).reduce((map, prop) => { - map[prop] = lang.t('signIn.requiredField'); - return map; - }, {}); - this.setState({errors}); - } - - componentWillUnmount() { - window.removeEventListener('storage', this.handleAuth); - } - - handleAuth(e) { - - // Listening to FB changes - // FB localStorage key is 'auth' - const authCallback = this.props.facebookCallback; - - if (e.key === 'auth') { - const {err, data} = JSON.parse(e.newValue); - authCallback(err, data); - } - } - - handleChange(e) { - const {name, value} = e.target; - this.setState( - (state) => ({ - ...state, - formData: { - ...state.formData, - [name]: value - } - }), - () => { - this.validation(name, value); - } - ); - } - - handleChangeEmail(e) { - const {value} = e.target; - this.setState({emailToBeResent: value}); - } - - handleResendVerification(e) { - e.preventDefault(); - this.props - .requestConfirmEmail( - this.state.emailToBeResent, - pym.parentUrl || location.href - ) - .then(() => { - setTimeout(() => { - - // allow success UI to be shown for a second, and then close the modal - this.props.handleClose(); - }, 2500); - }); - } - - addError(name, error) { - return this.setState((state) => ({ - errors: { - ...state.errors, - [name]: error - } - })); - } - - validation(name, value) { - const {addError} = this; - const {formData} = this.state; - - if (!value.length) { - addError(name, lang.t('signIn.requiredField')); - } else if ( - name === 'confirmPassword' && - formData.confirmPassword !== formData.password - ) { - addError('confirmPassword', lang.t('signIn.passwordsDontMatch')); - } else if (!validate[name](value)) { - addError(name, errorMsj[name]); - } else { - const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line - // Removes Error - this.setState((state) => ({...state, errors})); - } - } - - isCompleted() { - const {formData} = this.state; - return !Object.keys(formData).filter((prop) => !formData[prop].length).length; - } - - displayErrors(show = true) { - this.setState({showErrors: show}); - } - - handleSignUp(e) { - e.preventDefault(); - const {errors} = this.state; - const {fetchSignUp, validForm, invalidForm} = this.props; - this.displayErrors(); - if (this.isCompleted() && !Object.keys(errors).length) { - fetchSignUp(this.state.formData, pym.parentUrl || location.href); - validForm(); - } else { - invalidForm(lang.t('signIn.checkTheForm')); - } - } - - handleSignIn(e) { - e.preventDefault(); - this.props.fetchSignIn(this.state.formData); - } - - render() { - const {auth, requireEmailConfirmation} = this.props; - const {emailVerificationLoading, emailVerificationSuccess} = auth; - - return ( -
- -
- ); - } -} - -const mapStateToProps = (state) => ({ - auth: state.auth.toJS() -}); - -const mapDispatchToProps = (dispatch) => ({ - checkLogin: () => dispatch(checkLogin()), - facebookCallback: (err, data) => dispatch(facebookCallback(err, data)), - fetchSignUp: (formData, url) => dispatch(fetchSignUp(formData, url)), - fetchSignIn: (formData) => dispatch(fetchSignIn(formData)), - fetchSignInFacebook: () => dispatch(fetchSignInFacebook()), - fetchSignUpFacebook: () => dispatch(fetchSignUpFacebook()), - fetchForgotPassword: (formData) => dispatch(fetchForgotPassword(formData)), - requestConfirmEmail: (email, url) => - dispatch(requestConfirmEmail(email, url)), - changeView: (view) => dispatch(changeView(view)), - handleClose: () => dispatch(hideSignInDialog()), - invalidForm: (error) => dispatch(invalidForm(error)), - validForm: () => dispatch(validForm()) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(SignInContainer); +export const SignInContainer = () => ( + +) \ No newline at end of file diff --git a/plugins/coral-plugin-auth/client/components/SignInContainer.js b/plugins/coral-plugin-auth/client/components/SignInContainer.js new file mode 100644 index 000000000..06a747556 --- /dev/null +++ b/plugins/coral-plugin-auth/client/components/SignInContainer.js @@ -0,0 +1,210 @@ +import React, {Component, PropTypes} from 'react'; +import {connect} from 'react-redux'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from '../translations'; +import {pym} from 'coral-framework'; +const lang = new I18n(translations); + +import { + changeView, + fetchSignUp, + fetchSignIn, + hideSignInDialog, + fetchSignInFacebook, + fetchSignUpFacebook, + fetchForgotPassword, + requestConfirmEmail, + facebookCallback, + invalidForm, + validForm, + checkLogin +} from 'coral-framework/actions/auth'; + +class SignInContainer extends Component { + initialState = { + formData: { + email: '', + username: '', + password: '', + confirmPassword: '' + }, + emailToBeResent: '', + errors: {}, + showErrors: false + }; + + constructor(props) { + super(props); + this.state = this.initialState; + this.addError = this.addError.bind(this); + this.handleAuth = this.handleAuth.bind(this); + this.handleSignUp = this.handleSignUp.bind(this); + this.handleSignIn = this.handleSignIn.bind(this); + this.handleChange = this.handleChange.bind(this); + this.handleChangeEmail = this.handleChangeEmail.bind(this); + this.handleResendVerification = this.handleResendVerification.bind(this); + } + + static propTypes = { + requireEmailConfirmation: PropTypes.bool.isRequired + }; + + componentWillMount() { + this.props.checkLogin(); + } + + componentDidMount() { + window.addEventListener('storage', this.handleAuth); + + const {formData} = this.state; + const errors = Object.keys(formData).reduce((map, prop) => { + map[prop] = lang.t('signIn.requiredField'); + return map; + }, {}); + this.setState({errors}); + } + + componentWillUnmount() { + window.removeEventListener('storage', this.handleAuth); + } + + handleAuth(e) { + + // Listening to FB changes + // FB localStorage key is 'auth' + const authCallback = this.props.facebookCallback; + + if (e.key === 'auth') { + const {err, data} = JSON.parse(e.newValue); + authCallback(err, data); + } + } + + handleChange(e) { + const {name, value} = e.target; + this.setState( + (state) => ({ + ...state, + formData: { + ...state.formData, + [name]: value + } + }), + () => { + this.validation(name, value); + } + ); + } + + handleChangeEmail(e) { + const {value} = e.target; + this.setState({emailToBeResent: value}); + } + + handleResendVerification(e) { + e.preventDefault(); + this.props + .requestConfirmEmail( + this.state.emailToBeResent, + pym.parentUrl || location.href + ) + .then(() => { + setTimeout(() => { + + // allow success UI to be shown for a second, and then close the modal + this.props.handleClose(); + }, 2500); + }); + } + + addError(name, error) { + return this.setState((state) => ({ + errors: { + ...state.errors, + [name]: error + } + })); + } + + validation(name, value) { + const {addError} = this; + const {formData} = this.state; + + if (!value.length) { + addError(name, lang.t('signIn.requiredField')); + } else if ( + name === 'confirmPassword' && + formData.confirmPassword !== formData.password + ) { + addError('confirmPassword', lang.t('signIn.passwordsDontMatch')); + } else if (!validate[name](value)) { + addError(name, errorMsj[name]); + } else { + const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line + // Removes Error + this.setState((state) => ({...state, errors})); + } + } + + isCompleted() { + const {formData} = this.state; + return !Object.keys(formData).filter((prop) => !formData[prop].length).length; + } + + displayErrors(show = true) { + this.setState({showErrors: show}); + } + + handleSignUp(e) { + e.preventDefault(); + const {errors} = this.state; + const {fetchSignUp, validForm, invalidForm} = this.props; + this.displayErrors(); + if (this.isCompleted() && !Object.keys(errors).length) { + fetchSignUp(this.state.formData, pym.parentUrl || location.href); + validForm(); + } else { + invalidForm(lang.t('signIn.checkTheForm')); + } + } + + handleSignIn(e) { + e.preventDefault(); + this.props.fetchSignIn(this.state.formData); + } + + render() { + const {auth, requireEmailConfirmation} = this.props; + const {emailVerificationLoading, emailVerificationSuccess} = auth; + + return ( +
+ This is my login +
+ ); + } +} + +const mapStateToProps = (state) => ({ + auth: state.auth.toJS() +}); + +const mapDispatchToProps = (dispatch) => ({ + checkLogin: () => dispatch(checkLogin()), + facebookCallback: (err, data) => dispatch(facebookCallback(err, data)), + fetchSignUp: (formData, url) => dispatch(fetchSignUp(formData, url)), + fetchSignIn: (formData) => dispatch(fetchSignIn(formData)), + fetchSignInFacebook: () => dispatch(fetchSignInFacebook()), + fetchSignUpFacebook: () => dispatch(fetchSignUpFacebook()), + fetchForgotPassword: (formData) => dispatch(fetchForgotPassword(formData)), + requestConfirmEmail: (email, url) => + dispatch(requestConfirmEmail(email, url)), + changeView: (view) => dispatch(changeView(view)), + handleClose: () => dispatch(hideSignInDialog()), + invalidForm: (error) => dispatch(invalidForm(error)), + validForm: () => dispatch(validForm()) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SignInContainer); diff --git a/plugins/coral-plugin-auth/client/index.js b/plugins/coral-plugin-auth/client/index.js index ff601992b..8d2eecc3c 100644 --- a/plugins/coral-plugin-auth/client/index.js +++ b/plugins/coral-plugin-auth/client/index.js @@ -1,7 +1,9 @@ import SignInButton from './components/SignInButton'; +import SignInContainer from './components/SignInContainer'; export default { slots: { - stream: [SignInButton] + stream: [SignInButton], + login: [SignInContainer] } }; \ No newline at end of file From dbfd2aff7cdc2a8987f7740586d1d689ba4f6e48 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 19 May 2017 19:29:50 -0300 Subject: [PATCH 04/36] SignInButton --- .../src/components/Embed.js | 1 - .../src/components/Stream.js | 10 ++++----- .../containers/LoginContainer.js | 2 +- .../containers/SignInContainer.js | 2 +- .../client/components/SignInButton.js | 22 ++++++++++--------- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index 2e050e836..3a898295f 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -1,7 +1,6 @@ import React from 'react'; const lang = new I18n(translations); import Stream from '../containers/Stream'; -import Slot from 'coral-framework/components/Slot'; import I18n from 'coral-framework/modules/i18n/i18n'; import UserBox from 'coral-sign-in/components/UserBox'; import translations from 'coral-framework/translations'; diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js index e0c541341..60747e1a2 100644 --- a/client/coral-embed-stream/src/components/Stream.js +++ b/client/coral-embed-stream/src/components/Stream.js @@ -1,6 +1,4 @@ import React, {PropTypes} from 'react'; - -import {Button} from 'coral-ui'; import LoadMore from './LoadMore'; import NewCount from './NewCount'; import Comment from '../containers/Comment'; @@ -16,7 +14,7 @@ import ChangeUsernameContainer from 'coral-sign-in/containers/ChangeUsernameContainer'; class Stream extends React.Component { - setActiveReplyBox = reactKey => { + setActiveReplyBox = (reactKey) => { if (!this.props.auth.user) { this.props.showSignInDialog(); } else { @@ -59,11 +57,11 @@ class Stream extends React.Component { const firstCommentDate = asset.comments[0] ? asset.comments[0].created_at : new Date(Date.now() - 1000 * 60 * 60 * 24 * 7).toISOString(); - const commentIsIgnored = comment => { + const commentIsIgnored = (comment) => { return ( me && me.ignoredUsers && - me.ignoredUsers.find(u => u.id === comment.user.id) + me.ignoredUsers.find((u) => u.id === comment.user.id) ); }; return ( @@ -151,7 +149,7 @@ class Stream extends React.Component { setCommentCountCache={this.props.setCommentCountCache} />
- {comments.map(comment => { + {comments.map((comment) => { return commentIsIgnored(comment) ? : ( -) \ No newline at end of file +); diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js index b473626db..4e883c765 100644 --- a/client/coral-sign-in/containers/SignInContainer.js +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -2,4 +2,4 @@ import React from 'react'; export const SignInContainer = () => ( -) \ No newline at end of file +); diff --git a/plugins/coral-plugin-auth/client/components/SignInButton.js b/plugins/coral-plugin-auth/client/components/SignInButton.js index fb58eeb9b..b5a88431f 100644 --- a/plugins/coral-plugin-auth/client/components/SignInButton.js +++ b/plugins/coral-plugin-auth/client/components/SignInButton.js @@ -4,17 +4,19 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {showSignInDialog} from 'coral-framework/actions/auth'; -class SignInButton extends React.Component { - render() { - return ( - - ); - } -} +const SignInButton = ({loggedIn, showSignInDialog}) => ( +
+ { + !loggedIn ? ( + + ) : null + } +
+); -const mapStateToProps = ({auth}) => ({auth}); +const mapStateToProps = ({auth}) => ({loggedIn: auth.loggedIn}); const mapDispatchToProps = dispatch => bindActionCreators({showSignInDialog}, dispatch); From 801a6f8a534f23b59968d8e64c152ccb3db9dad3 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 19 May 2017 20:00:33 -0300 Subject: [PATCH 05/36] External plugin auth fully working, now refactor --- .../src/components/Embed.js | 10 +- .../src/components/Stream.js | 5 - client/coral-sign-in/components/UserBox.js | 15 --- .../containers/SignInContainer.js | 5 - .../components}/ChangeUsernameContainer.js | 51 ++++----- .../components/CreateUsernameDialog.js | 0 .../client}/components/FakeComment.js | 0 .../client}/components/ForgotContent.js | 0 .../client}/components/SignDialog.js | 0 .../client/components/SignInButton.js | 4 +- .../client/components/SignInContainer.js | 12 ++- .../client}/components/SignInContent.js | 0 .../client}/components/SignUpContent.js | 0 .../client/components/UserBox.js | 34 ++++++ .../client}/components/styles.css | 0 plugins/coral-plugin-auth/client/index.js | 4 +- .../client/translations.json | 100 +++++++++++++++++- 17 files changed, 177 insertions(+), 63 deletions(-) delete mode 100644 client/coral-sign-in/components/UserBox.js delete mode 100644 client/coral-sign-in/containers/SignInContainer.js rename {client/coral-sign-in/containers => plugins/coral-plugin-auth/client/components}/ChangeUsernameContainer.js (73%) rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/CreateUsernameDialog.js (100%) rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/FakeComment.js (100%) rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/ForgotContent.js (100%) rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/SignDialog.js (100%) rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/SignInContent.js (100%) rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/SignUpContent.js (100%) create mode 100644 plugins/coral-plugin-auth/client/components/UserBox.js rename {client/coral-sign-in => plugins/coral-plugin-auth/client}/components/styles.css (100%) diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index 3a898295f..e6ae3f367 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -1,8 +1,8 @@ import React from 'react'; const lang = new I18n(translations); import Stream from '../containers/Stream'; +import Slot from 'coral-framework/components/Slot'; import I18n from 'coral-framework/modules/i18n/i18n'; -import UserBox from 'coral-sign-in/components/UserBox'; import translations from 'coral-framework/translations'; import {TabBar, Tab, TabContent, Button} from 'coral-ui'; import Count from 'coral-plugin-comment-count/CommentCount'; @@ -34,12 +34,10 @@ export default class Embed extends React.Component { handleShowProfile = () => this.props.setActiveTab('profile'); render () { - const {activeTab, logout, viewAllComments, commentId} = this.props; + const {activeTab, viewAllComments, commentId} = this.props; const {asset: {totalCommentCount}} = this.props.root; const {loggedIn, isAdmin, user} = this.props.auth; - const userBox = ; - return (
@@ -48,6 +46,7 @@ export default class Embed extends React.Component { {lang.t('myProfile')} Configure Stream + { commentId &&
:

{asset.settings.closedMessage}

} - {loggedIn && - user && - } {loggedIn && } {highlightedComment diff --git a/client/coral-sign-in/components/UserBox.js b/client/coral-sign-in/components/UserBox.js deleted file mode 100644 index a44c3d4fb..000000000 --- a/client/coral-sign-in/components/UserBox.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import styles from './styles.css'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations'; -const lang = new I18n(translations); - -const UserBox = ({className, user, onLogout, onShowProfile}) => ( -
- {lang.t('signIn.loggedInAs')} - {user.username}. {lang.t('signIn.notYou')} - {lang.t('signIn.logout')} -
-); - -export default UserBox; diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js deleted file mode 100644 index 4e883c765..000000000 --- a/client/coral-sign-in/containers/SignInContainer.js +++ /dev/null @@ -1,5 +0,0 @@ -import React from 'react'; - -export const SignInContainer = () => ( - -); diff --git a/client/coral-sign-in/containers/ChangeUsernameContainer.js b/plugins/coral-plugin-auth/client/components/ChangeUsernameContainer.js similarity index 73% rename from client/coral-sign-in/containers/ChangeUsernameContainer.js rename to plugins/coral-plugin-auth/client/components/ChangeUsernameContainer.js index 12a9a75b8..4f0ad9895 100644 --- a/client/coral-sign-in/containers/ChangeUsernameContainer.js +++ b/plugins/coral-plugin-auth/client/components/ChangeUsernameContainer.js @@ -4,7 +4,7 @@ import {connect} from 'react-redux'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; -import CreateUsernameDialog from '../components/CreateUsernameDialog'; +import CreateUsernameDialog from './CreateUsernameDialog'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; @@ -16,12 +16,12 @@ import { invalidForm, validForm, createUsername -} from '../../coral-framework/actions/auth'; +} from 'coral-framework/actions/auth'; class ChangeUsernameContainer extends Component { initialState = { formData: { - username: '', + username: '' }, errors: {}, showErrors: false @@ -39,19 +39,22 @@ class ChangeUsernameContainer extends Component { handleChange(e) { const {name, value} = e.target; - this.setState((state) => ({ - ...state, - formData: { - ...state.formData, - [name]: value + this.setState( + state => ({ + ...state, + formData: { + ...state.formData, + [name]: value + } + }), + () => { + this.validation(name, value); } - }), () => { - this.validation(name, value); - }); + ); } addError(name, error) { - return this.setState((state) => ({ + return this.setState(state => ({ errors: { ...state.errors, [name]: error @@ -67,15 +70,15 @@ class ChangeUsernameContainer extends Component { } else if (!validate[name](value)) { addError(name, errorMsj[name]); } else { - const { [name]: prop, ...errors } = this.state.errors; // eslint-disable-line + const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line // Removes Error - this.setState((state) => ({...state, errors})); + this.setState(state => ({...state, errors})); } } isCompleted() { const {formData} = this.state; - return !Object.keys(formData).filter((prop) => !formData[prop].length).length; + return !Object.keys(formData).filter(prop => !formData[prop].length).length; } displayErrors(show = true) { @@ -117,19 +120,17 @@ class ChangeUsernameContainer extends Component { } } -const mapStateToProps = (state) => ({ - auth: state.auth.toJS() -}); +const mapStateToProps = ({auth, user}) => ({auth, user}); -const mapDispatchToProps = (dispatch) => ({ - createUsername: (userid, formData) => dispatch(createUsername(userid, formData)), +const mapDispatchToProps = dispatch => ({ + createUsername: (userid, formData) => + dispatch(createUsername(userid, formData)), showCreateUsernameDialog: () => dispatch(showCreateUsernameDialog()), hideCreateUsernameDialog: () => dispatch(hideCreateUsernameDialog()), - invalidForm: (error) => dispatch(invalidForm(error)), + invalidForm: error => dispatch(invalidForm(error)), validForm: () => dispatch(validForm()) }); -export default connect( - mapStateToProps, - mapDispatchToProps -)(ChangeUsernameContainer); +export default connect(mapStateToProps, mapDispatchToProps)( + ChangeUsernameContainer +); diff --git a/client/coral-sign-in/components/CreateUsernameDialog.js b/plugins/coral-plugin-auth/client/components/CreateUsernameDialog.js similarity index 100% rename from client/coral-sign-in/components/CreateUsernameDialog.js rename to plugins/coral-plugin-auth/client/components/CreateUsernameDialog.js diff --git a/client/coral-sign-in/components/FakeComment.js b/plugins/coral-plugin-auth/client/components/FakeComment.js similarity index 100% rename from client/coral-sign-in/components/FakeComment.js rename to plugins/coral-plugin-auth/client/components/FakeComment.js diff --git a/client/coral-sign-in/components/ForgotContent.js b/plugins/coral-plugin-auth/client/components/ForgotContent.js similarity index 100% rename from client/coral-sign-in/components/ForgotContent.js rename to plugins/coral-plugin-auth/client/components/ForgotContent.js diff --git a/client/coral-sign-in/components/SignDialog.js b/plugins/coral-plugin-auth/client/components/SignDialog.js similarity index 100% rename from client/coral-sign-in/components/SignDialog.js rename to plugins/coral-plugin-auth/client/components/SignDialog.js diff --git a/plugins/coral-plugin-auth/client/components/SignInButton.js b/plugins/coral-plugin-auth/client/components/SignInButton.js index b5a88431f..b4497bc92 100644 --- a/plugins/coral-plugin-auth/client/components/SignInButton.js +++ b/plugins/coral-plugin-auth/client/components/SignInButton.js @@ -16,7 +16,9 @@ const SignInButton = ({loggedIn, showSignInDialog}) => (
); -const mapStateToProps = ({auth}) => ({loggedIn: auth.loggedIn}); +const mapStateToProps = ({auth}) => ({ + loggedIn: auth.toJS().loggedIn +}); const mapDispatchToProps = dispatch => bindActionCreators({showSignInDialog}, dispatch); diff --git a/plugins/coral-plugin-auth/client/components/SignInContainer.js b/plugins/coral-plugin-auth/client/components/SignInContainer.js index 06a747556..73094920e 100644 --- a/plugins/coral-plugin-auth/client/components/SignInContainer.js +++ b/plugins/coral-plugin-auth/client/components/SignInContainer.js @@ -1,5 +1,6 @@ import React, {Component, PropTypes} from 'react'; import {connect} from 'react-redux'; +import SignDialog from './SignDialog'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; import I18n from 'coral-framework/modules/i18n/i18n'; @@ -181,7 +182,16 @@ class SignInContainer extends Component { return (
- This is my login +
); } diff --git a/client/coral-sign-in/components/SignInContent.js b/plugins/coral-plugin-auth/client/components/SignInContent.js similarity index 100% rename from client/coral-sign-in/components/SignInContent.js rename to plugins/coral-plugin-auth/client/components/SignInContent.js diff --git a/client/coral-sign-in/components/SignUpContent.js b/plugins/coral-plugin-auth/client/components/SignUpContent.js similarity index 100% rename from client/coral-sign-in/components/SignUpContent.js rename to plugins/coral-plugin-auth/client/components/SignUpContent.js diff --git a/plugins/coral-plugin-auth/client/components/UserBox.js b/plugins/coral-plugin-auth/client/components/UserBox.js new file mode 100644 index 000000000..a4a0e1c99 --- /dev/null +++ b/plugins/coral-plugin-auth/client/components/UserBox.js @@ -0,0 +1,34 @@ +import React from 'react'; +import styles from './styles.css'; +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import translations from '../translations'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import {showSignInDialog, logout} from 'coral-framework/actions/auth'; +const lang = new I18n(translations); + +const UserBox = ({loggedIn, user, logout, onShowProfile}) => ( +
+ { + loggedIn ? ( +
+ {lang.t('signIn.loggedInAs')} + {user.username}. {lang.t('signIn.notYou')} + logout()}> + {lang.t('signIn.logout')} + +
+ ) : null + } +
+); + +const mapStateToProps = ({auth, user}) => ({ + loggedIn: auth.toJS().loggedIn, + user: user.toJS() +}); + +const mapDispatchToProps = dispatch => + bindActionCreators({logout}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(UserBox); diff --git a/client/coral-sign-in/components/styles.css b/plugins/coral-plugin-auth/client/components/styles.css similarity index 100% rename from client/coral-sign-in/components/styles.css rename to plugins/coral-plugin-auth/client/components/styles.css diff --git a/plugins/coral-plugin-auth/client/index.js b/plugins/coral-plugin-auth/client/index.js index 8d2eecc3c..3bf9e58f0 100644 --- a/plugins/coral-plugin-auth/client/index.js +++ b/plugins/coral-plugin-auth/client/index.js @@ -1,9 +1,11 @@ import SignInButton from './components/SignInButton'; import SignInContainer from './components/SignInContainer'; +import UserBox from './components/UserBox'; +import ChangeUserNameContainer from './components/ChangeUserNameContainer'; export default { slots: { - stream: [SignInButton], + stream: [UserBox, SignInButton, ChangeUserNameContainer], login: [SignInContainer] } }; \ No newline at end of file diff --git a/plugins/coral-plugin-auth/client/translations.json b/plugins/coral-plugin-auth/client/translations.json index 93d73d3a2..7ae84b2ff 100644 --- a/plugins/coral-plugin-auth/client/translations.json +++ b/plugins/coral-plugin-auth/client/translations.json @@ -1,10 +1,102 @@ { "en": { - "like": "Like", - "liked": "Liked" + "signIn": { + "emailVerifyCTA": "Please verify your email address.", + "requestNewVerifyEmail": "Request another email:", + "verifyEmail": "Thank you for creating an account! We sent an email to the address you provided to verify your account.", + "verifyEmail2": "You must verify your account before engaging with the community.", + "notYou": "Not you?", + "loggedInAs": "Logged in as", + "facebookSignIn": "Sign in with Facebook", + "facebookSignUp": "Sign up with Facebook", + "logout": "Logout", + "signIn": "Sign in to join the conversation", + "or": "Or", + "email": "E-mail Address", + "password": "Password", + "forgotYourPass": "Forgot your password?", + "needAnAccount": "Need an account?", + "register": "Register", + "signUp": "Sign Up", + "confirmPassword": "Confirm Password", + "username": "Username", + "alreadyHaveAnAccount": "Already have an account?", + "recoverPassword": "Recover password", + "emailInUse": "Email address already in use", + "emailORusernameInUse": "Email address or Username already in use", + "requiredField": "This field is required", + "passwordsDontMatch": "Passwords don't match.", + "specialCharacters": "Usernames can contain letters, numbers and _ only", + "checkTheForm": "Invalid Form. Please, check the fields" + }, + "createdisplay": { + "writeyourusername": "Edit your username", + "yourusername": "Your username appears on every comment you post.", + "ifyoudontchangeyourname": "If you don't change your username at this step, your Facebook display name will appear alongside of all your comments.", + "username": "Username", + "continue": "Continue with the same Facebook username", + "save": "Save", + "fakecommentdate": "1 minute ago", + "fakecommentbody": "This is an example comment. Readers can share their thoughts and opinions with newsrooms in the comments section.", + "requiredField": "Required field", + "errorCreate": "Error when changing username", + "checkTheForm": "Invalid Form. Please, check the fields", + "specialCharacters": "Usernames can contain letters, numbers and _ only" + }, + "permalink": { + "permalink": "Link" + }, + "report": "Report", + "like": "Like" }, "es": { - "like": "Me Gusta", - "liked": "Me Gustó" + "signIn": { + "emailVerifyCTA": "Por favor verifique su e-mail.", + "requestNewVerifyEmail": "Enviar otro correo:", + "verifyEmail": "¡Gracias por crear una cuenta! Le enviamos un correo a la dirección que dio para verificar su cuenta.", + "verifyEmail2": "Debe verificarla antes de poder involucrarse en la comunidad.", + "notYou": "¿No eres tu?", + "loggedInAs": "Entraste como", + "facebookSignIn": "Entrar con Facebook", + "facebookSignUp": "Regístrate con Facebook", + "logout": "Salir", + "signIn": "Entrar para Unirte a la Conversación", + "or": "o", + "email": "E-mail", + "password": "Contraseña", + "forgotYourPass": "¿Has olvidado tu contraseña?", + "needAnAccount": "¿Necesitas una cuenta?", + "register": "Regístrate", + "signUp": "Registro", + "confirmPassword": "Confirmar Contraseña", + "username": "Nombre", + "alreadyHaveAnAccount": "¿Ya tienes una cuenta?", + "recoverPassword": "Recuperar contraseña", + "emailInUse": "Este e-mail se encuentra en uso", + "emailORusernameInUse": "Este e-mail ó nombre de usuario se encuentran en uso", + "requiredField": "Este campo es requerido", + "passwordsDontMatch": "Las contraseñas no coinciden", + "specialCharacters": "Los nombres pueden contener letras, números y _", + "checkTheForm": "Formulario Inválido. Por favor, completa los campos" + }, + "createdisplay": { + "writeyourusername": "Edita tu nombre", + "yourusername": "Tu nombre aparece en cada comentario que publiques.", + "ifyoudontchangeyourname": "Si no modificas tu nombre de usuario en este paso, tu nombre de Facebook aparecera al lado de cada comentario que publiques.", + "username": "Nombre", + "continue": "Continuar con nombre de Facebook", + "save": "Guardar", + "fakecommentdate": "hace un minuto", + "fakecommentbody": "Este es un comentario de ejemplo. Las lectoras pueden compartir sus ideas y opiniones con los periodistas en la sección de comentarios.", + "requiredField": "Campo necesario", + "errorCreate": "Hubo un error al cambiar el nombre de usuario", + "checkTheForm": "Formulario Inválido. Por favor, verifica los campos", + "specialCharacters": "Sólo pueden contener letras, números y _" + }, + "permalink": { + "permalink": "Enlace" + }, + "report": "Marcar", + "like": "Me gusta" } } From 1aacb565d4d90b8b1a6562266ba0185e987ec20c Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 19 May 2017 20:10:49 -0300 Subject: [PATCH 06/36] linting --- client/coral-embed-stream/src/components/Embed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index e6ae3f367..2c22cc8a0 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -36,7 +36,7 @@ export default class Embed extends React.Component { render () { const {activeTab, viewAllComments, commentId} = this.props; const {asset: {totalCommentCount}} = this.props.root; - const {loggedIn, isAdmin, user} = this.props.auth; + const {loggedIn, isAdmin} = this.props.auth; return (
From f364a1e0a12015843f35a4884f5bc1822459b6e9 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 22 May 2017 08:23:58 -0300 Subject: [PATCH 07/36] Refactor --- .../client/components/SignInContainer.js | 140 +++++++++--------- .../client/components/SignInContent.js | 47 +++--- .../client/components/SignUpContent.js | 91 ++++++------ plugins/coral-plugin-auth/client/index.js | 2 +- 4 files changed, 139 insertions(+), 141 deletions(-) diff --git a/plugins/coral-plugin-auth/client/components/SignInContainer.js b/plugins/coral-plugin-auth/client/components/SignInContainer.js index 73094920e..5a8ffa11a 100644 --- a/plugins/coral-plugin-auth/client/components/SignInContainer.js +++ b/plugins/coral-plugin-auth/client/components/SignInContainer.js @@ -1,11 +1,13 @@ -import React, {Component, PropTypes} from 'react'; +import React from 'react'; import {connect} from 'react-redux'; -import SignDialog from './SignDialog'; -import validate from 'coral-framework/helpers/validate'; -import errorMsj from 'coral-framework/helpers/error'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations'; import {pym} from 'coral-framework'; +import SignDialog from './SignDialog'; +import {bindActionCreators} from 'redux'; +import translations from '../translations'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import errorMsj from 'coral-framework/helpers/error'; +import validate from 'coral-framework/helpers/validate'; + const lang = new I18n(translations); import { @@ -23,34 +25,22 @@ import { checkLogin } from 'coral-framework/actions/auth'; -class SignInContainer extends Component { - initialState = { - formData: { - email: '', - username: '', - password: '', - confirmPassword: '' - }, - emailToBeResent: '', - errors: {}, - showErrors: false - }; - +class SignInContainer extends React.Component { constructor(props) { super(props); - this.state = this.initialState; - this.addError = this.addError.bind(this); - this.handleAuth = this.handleAuth.bind(this); - this.handleSignUp = this.handleSignUp.bind(this); - this.handleSignIn = this.handleSignIn.bind(this); - this.handleChange = this.handleChange.bind(this); - this.handleChangeEmail = this.handleChangeEmail.bind(this); - this.handleResendVerification = this.handleResendVerification.bind(this); - } - static propTypes = { - requireEmailConfirmation: PropTypes.bool.isRequired - }; + this.state = { + formData: { + email: '', + username: '', + password: '', + confirmPassword: '' + }, + emailToBeResent: '', + errors: {}, + showErrors: false + }; + } componentWillMount() { this.props.checkLogin(); @@ -71,8 +61,7 @@ class SignInContainer extends Component { window.removeEventListener('storage', this.handleAuth); } - handleAuth(e) { - + handleAuth = e => { // Listening to FB changes // FB localStorage key is 'auth' const authCallback = this.props.facebookCallback; @@ -81,12 +70,12 @@ class SignInContainer extends Component { const {err, data} = JSON.parse(e.newValue); authCallback(err, data); } - } + }; - handleChange(e) { + handleChange = e => { const {name, value} = e.target; this.setState( - (state) => ({ + state => ({ ...state, formData: { ...state.formData, @@ -97,14 +86,14 @@ class SignInContainer extends Component { this.validation(name, value); } ); - } + }; - handleChangeEmail(e) { + handleChangeEmail = e => { const {value} = e.target; this.setState({emailToBeResent: value}); - } + }; - handleResendVerification(e) { + handleResendVerification = e => { e.preventDefault(); this.props .requestConfirmEmail( @@ -113,23 +102,22 @@ class SignInContainer extends Component { ) .then(() => { setTimeout(() => { - // allow success UI to be shown for a second, and then close the modal - this.props.handleClose(); + this.props.hideSignInDialog(); }, 2500); }); - } + }; - addError(name, error) { - return this.setState((state) => ({ + addError = (name, error) => { + return this.setState(state => ({ errors: { ...state.errors, [name]: error } })); - } + }; - validation(name, value) { + validation = (name, value) => { const {addError} = this; const {formData} = this.state; @@ -145,20 +133,20 @@ class SignInContainer extends Component { } else { const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line // Removes Error - this.setState((state) => ({...state, errors})); + this.setState(state => ({...state, errors})); } - } + }; - isCompleted() { + isCompleted = () => { const {formData} = this.state; - return !Object.keys(formData).filter((prop) => !formData[prop].length).length; - } + return !Object.keys(formData).filter(prop => !formData[prop].length).length; + }; - displayErrors(show = true) { + displayErrors = (show = true) => { this.setState({showErrors: show}); - } + }; - handleSignUp(e) { + handleSignUp = e => { e.preventDefault(); const {errors} = this.state; const {fetchSignUp, validForm, invalidForm} = this.props; @@ -169,12 +157,12 @@ class SignInContainer extends Component { } else { invalidForm(lang.t('signIn.checkTheForm')); } - } + }; - handleSignIn(e) { + handleSignIn = e => { e.preventDefault(); this.props.fetchSignIn(this.state.formData); - } + }; render() { const {auth, requireEmailConfirmation} = this.props; @@ -197,24 +185,28 @@ class SignInContainer extends Component { } } -const mapStateToProps = (state) => ({ +const mapStateToProps = state => ({ auth: state.auth.toJS() }); -const mapDispatchToProps = (dispatch) => ({ - checkLogin: () => dispatch(checkLogin()), - facebookCallback: (err, data) => dispatch(facebookCallback(err, data)), - fetchSignUp: (formData, url) => dispatch(fetchSignUp(formData, url)), - fetchSignIn: (formData) => dispatch(fetchSignIn(formData)), - fetchSignInFacebook: () => dispatch(fetchSignInFacebook()), - fetchSignUpFacebook: () => dispatch(fetchSignUpFacebook()), - fetchForgotPassword: (formData) => dispatch(fetchForgotPassword(formData)), - requestConfirmEmail: (email, url) => - dispatch(requestConfirmEmail(email, url)), - changeView: (view) => dispatch(changeView(view)), - handleClose: () => dispatch(hideSignInDialog()), - invalidForm: (error) => dispatch(invalidForm(error)), - validForm: () => dispatch(validForm()) -}); +const mapDispatchToProps = dispatch => + bindActionCreators( + { + checkLogin, + facebookCallback, + fetchSignUp, + fetchSignUp, + fetchSignIn, + fetchSignInFacebook, + fetchSignUpFacebook, + fetchForgotPassword, + requestConfirmEmail, + changeView, + hideSignInDialog, + invalidForm, + validForm + }, + dispatch + ); export default connect(mapStateToProps, mapDispatchToProps)(SignInContainer); diff --git a/plugins/coral-plugin-auth/client/components/SignInContent.js b/plugins/coral-plugin-auth/client/components/SignInContent.js index 7460efb97..6f0027084 100644 --- a/plugins/coral-plugin-auth/client/components/SignInContent.js +++ b/plugins/coral-plugin-auth/client/components/SignInContent.js @@ -18,17 +18,17 @@ const SignInContent = ({ auth, fetchSignInFacebook }) => { - return (

- {auth.emailVerificationFailure ? lang.t('signIn.emailVerifyCTA') : lang.t('signIn.signIn')} + {auth.emailVerificationFailure + ? lang.t('signIn.emailVerifyCTA') + : lang.t('signIn.signIn')}

- { auth.error && {auth.error} } - { - auth.emailVerificationFailure + {auth.error && {auth.error}} + {auth.emailVerificationFailure ?

{lang.t('signIn.requestNewVerifyEmail')}

- + onChange={handleChangeEmail} + /> + {emailVerificationLoading && } {emailVerificationSuccess && } @@ -70,23 +73,29 @@ const SignInContent = ({ onChange={handleChange} />
- { - !auth.isLoading ? - - : - - } + {!auth.isLoading + ? + : }
-
- } +
}
- changeView('FORGOT')}>{lang.t('signIn.forgotYourPass')} + + changeView('FORGOT')}> + {lang.t('signIn.forgotYourPass')} + + {lang.t('signIn.needAnAccount')} - changeView('SIGNUP')} id='coralRegister'> + changeView('SIGNUP')} id="coralRegister"> {lang.t('signIn.register')} diff --git a/plugins/coral-plugin-auth/client/components/SignUpContent.js b/plugins/coral-plugin-auth/client/components/SignUpContent.js index 921f045be..5f2dd36ea 100644 --- a/plugins/coral-plugin-auth/client/components/SignUpContent.js +++ b/plugins/coral-plugin-auth/client/components/SignUpContent.js @@ -1,39 +1,21 @@ -import React, {PropTypes} from 'react'; -import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; import styles from './styles.css'; -import I18n from 'coral-framework/modules/i18n/i18n'; +import React, {PropTypes} from 'react'; import translations from '../translations'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; + const lang = new I18n(translations); class SignUpContent extends React.Component { + constructor() { + super(); - constructor (props) { - super(props); - this.successfulSignup = false; + this.state = { + successfulSignup: false + }; } - static propTypes = { - emailVerificationEnabled: PropTypes.bool.isRequired, - fetchSignUpFacebook: PropTypes.func.isRequired, - changeView: PropTypes.func.isRequired, - handleSignUp: PropTypes.func.isRequired, - showErrors: PropTypes.bool, - errors: PropTypes.shape({ - email: PropTypes.string, - username: PropTypes.string, - password: PropTypes.string, - confirmPassword: PropTypes.string, - }), - formData: PropTypes.shape({ - email: PropTypes.string, - username: PropTypes.string, - password: PropTypes.string, - confirmPassword: PropTypes.string - }) - } - - render () { - + render() { const { handleChange, formData, @@ -43,17 +25,20 @@ class SignUpContent extends React.Component { showErrors, changeView, handleSignUp, - fetchSignUpFacebook} = this.props; + fetchSignUpFacebook + } = this.props; const beforeSignup = !auth.isLoading && !auth.successSignUp; const successfulSignup = !auth.isLoading && auth.successSignUp; // the first time we render a successfulSignup, trigger a timer - if ((this.successfulSignup ^ successfulSignup) && !emailVerificationEnabled) { + if (this.successfulSignup ^ successfulSignup && !emailVerificationEnabled) { setTimeout(() => { changeView('SIGNIN'); }, 1000); - this.successfulSignup = true; + this.setState({ + successfulSignup: true + }); } return ( @@ -64,8 +49,8 @@ class SignUpContent extends React.Component {
- { auth.error && {auth.error} } - { beforeSignup && + {auth.error && {auth.error}} + {beforeSignup &&
- { auth.isLoading && } + {auth.isLoading && }
-
- } - { - successfulSignup && +
} + {successfulSignup &&
- { - emailVerificationEnabled && -

{lang.t('signIn.verifyEmail')}

{lang.t('signIn.verifyEmail2')}

- } -
- } + {emailVerificationEnabled && +

+ {lang.t('signIn.verifyEmail')} +
+
+ {lang.t('signIn.verifyEmail2')} +

} +
}
- {lang.t('signIn.alreadyHaveAnAccount')} changeView('SIGNIN')}> + {lang.t('signIn.alreadyHaveAnAccount')} changeView('SIGNIN')} + > {lang.t('signIn.signIn')}
diff --git a/plugins/coral-plugin-auth/client/index.js b/plugins/coral-plugin-auth/client/index.js index 3bf9e58f0..867849cac 100644 --- a/plugins/coral-plugin-auth/client/index.js +++ b/plugins/coral-plugin-auth/client/index.js @@ -1,6 +1,6 @@ +import UserBox from './components/UserBox'; import SignInButton from './components/SignInButton'; import SignInContainer from './components/SignInContainer'; -import UserBox from './components/UserBox'; import ChangeUserNameContainer from './components/ChangeUserNameContainer'; export default { From 9d00a27f1de3b5c0a170c885c9adb5b19bba47a6 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 22 May 2017 08:40:45 -0300 Subject: [PATCH 08/36] Auth as a plugin --- ...UsernameContainer.js => ChangeUsername.js} | 82 ++++++------ .../client/components/CreateUsernameDialog.js | 49 ++++--- .../client/components/FakeComment.js | 124 +++++++++--------- .../client/components/ForgotContent.js | 62 +++++---- .../client/components/SignDialog.js | 9 +- .../client/components/SignInButton.js | 8 +- .../client/components/SignInContainer.js | 22 ++-- plugins/coral-plugin-auth/client/index.js | 2 +- 8 files changed, 190 insertions(+), 168 deletions(-) rename plugins/coral-plugin-auth/client/components/{ChangeUsernameContainer.js => ChangeUsername.js} (69%) diff --git a/plugins/coral-plugin-auth/client/components/ChangeUsernameContainer.js b/plugins/coral-plugin-auth/client/components/ChangeUsername.js similarity index 69% rename from plugins/coral-plugin-auth/client/components/ChangeUsernameContainer.js rename to plugins/coral-plugin-auth/client/components/ChangeUsername.js index 4f0ad9895..9b0cbb1a6 100644 --- a/plugins/coral-plugin-auth/client/components/ChangeUsernameContainer.js +++ b/plugins/coral-plugin-auth/client/components/ChangeUsername.js @@ -1,13 +1,12 @@ -import React, {Component} from 'react'; +import React from 'react'; import {connect} from 'react-redux'; - -import validate from 'coral-framework/helpers/validate'; +import {bindActionCreators} from 'redux'; +import translations from '../translations'; +import I18n from 'coral-framework/modules/i18n/i18n'; import errorMsj from 'coral-framework/helpers/error'; - +import validate from 'coral-framework/helpers/validate'; import CreateUsernameDialog from './CreateUsernameDialog'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations'; const lang = new I18n(translations); import { @@ -18,26 +17,20 @@ import { createUsername } from 'coral-framework/actions/auth'; -class ChangeUsernameContainer extends Component { - initialState = { - formData: { - username: '' - }, - errors: {}, - showErrors: false - }; - +class ChangeUsernameContainer extends React.Component { constructor(props) { super(props); - this.initialState.formData.username = props.user.username; - this.state = this.initialState; - this.handleChange = this.handleChange.bind(this); - this.handleSubmitUsername = this.handleSubmitUsername.bind(this); - this.handleClose = this.handleClose.bind(this); - this.addError = this.addError.bind(this); + + this.state = { + formData: { + username: props.user.username + }, + errors: {}, + showErrors: false + }; } - handleChange(e) { + handleChange = e => { const {name, value} = e.target; this.setState( state => ({ @@ -51,18 +44,18 @@ class ChangeUsernameContainer extends Component { this.validation(name, value); } ); - } + }; - addError(name, error) { + addError = (name, error) => { return this.setState(state => ({ errors: { ...state.errors, [name]: error } })); - } + }; - validation(name, value) { + validation = (name, value) => { const {addError} = this; if (!value.length) { @@ -74,18 +67,18 @@ class ChangeUsernameContainer extends Component { // Removes Error this.setState(state => ({...state, errors})); } - } + }; - isCompleted() { + isCompleted = () => { const {formData} = this.state; return !Object.keys(formData).filter(prop => !formData[prop].length).length; - } + }; - displayErrors(show = true) { + displayErrors = (show = true) => { this.setState({showErrors: show}); - } + }; - handleSubmitUsername(e) { + handleSubmitUsername = e => { e.preventDefault(); const {errors} = this.state; const {validForm, invalidForm} = this.props; @@ -96,11 +89,11 @@ class ChangeUsernameContainer extends Component { } else { invalidForm(lang.t('createdisplay.checkTheForm')); } - } + }; - handleClose() { + handleClose = () => { this.props.hideCreateUsernameDialog(); - } + }; render() { const {loggedIn, auth} = this.props; @@ -122,14 +115,17 @@ class ChangeUsernameContainer extends Component { const mapStateToProps = ({auth, user}) => ({auth, user}); -const mapDispatchToProps = dispatch => ({ - createUsername: (userid, formData) => - dispatch(createUsername(userid, formData)), - showCreateUsernameDialog: () => dispatch(showCreateUsernameDialog()), - hideCreateUsernameDialog: () => dispatch(hideCreateUsernameDialog()), - invalidForm: error => dispatch(invalidForm(error)), - validForm: () => dispatch(validForm()) -}); +const mapDispatchToProps = dispatch => + bindActionCreators( + { + createUsername, + showCreateUsernameDialog, + hideCreateUsernameDialog, + invalidForm, + validForm + }, + dispatch + ); export default connect(mapStateToProps, mapDispatchToProps)( ChangeUsernameContainer diff --git a/plugins/coral-plugin-auth/client/components/CreateUsernameDialog.js b/plugins/coral-plugin-auth/client/components/CreateUsernameDialog.js index b94b47c42..c352552ae 100644 --- a/plugins/coral-plugin-auth/client/components/CreateUsernameDialog.js +++ b/plugins/coral-plugin-auth/client/components/CreateUsernameDialog.js @@ -1,21 +1,26 @@ import React from 'react'; -import TextField from 'coral-ui/components/TextField'; -import Button from 'coral-ui/components/Button'; -import {Dialog, Alert} from 'coral-ui'; -import FakeComment from './FakeComment'; - import styles from './styles.css'; - -import I18n from 'coral-framework/modules/i18n/i18n'; +import {Dialog, Alert, TextField} from 'coral-ui'; +import {FakeComment} from './FakeComment'; import translations from '../translations'; +import Button from 'coral-ui/components/Button'; +import I18n from 'coral-framework/modules/i18n/i18n'; + const lang = new I18n(translations); -const CreateUsernameDialog = ({open, handleClose, formData, handleSubmitUsername, handleChange, ...props}) => { - return ( +const CreateUsernameDialog = ({ + open, + handleClose, + formData, + handleSubmitUsername, + handleChange, + ...props +}) => ( + open={open} + > ×
@@ -24,17 +29,24 @@ const CreateUsernameDialog = ({open, handleClose, formData, handleSubmitUsername
-

{lang.t('createdisplay.yourusername')}

+

+ {lang.t('createdisplay.yourusername')} +

-

{lang.t('createdisplay.ifyoudontchangeyourname')}

- { props.auth.error && {props.auth.error} } +

+ {lang.t('createdisplay.ifyoudontchangeyourname')} +

+ {props.auth.error && {props.auth.error}}
- { props.errors.username && {lang.t('createdisplay.specialCharacters')} } + {props.errors.username && + + {' '}{lang.t('createdisplay.specialCharacters')}{' '} + }
- +
-
+
- ); -}; +); export default CreateUsernameDialog; diff --git a/plugins/coral-plugin-auth/client/components/FakeComment.js b/plugins/coral-plugin-auth/client/components/FakeComment.js index 37630383d..01cc6863e 100644 --- a/plugins/coral-plugin-auth/client/components/FakeComment.js +++ b/plugins/coral-plugin-auth/client/components/FakeComment.js @@ -1,66 +1,72 @@ import React from 'react'; -import styles from 'coral-embed-stream/src/components/Comment.css'; - +import translations from '../translations'; +import {ReplyButton} from 'coral-plugin-replies'; +import PubDate from 'coral-plugin-pubdate/PubDate'; +import I18n from 'coral-framework/modules/i18n/i18n'; import AuthorName from 'coral-plugin-author-name/AuthorName'; import Content from 'coral-plugin-commentcontent/CommentContent'; -import PubDate from 'coral-plugin-pubdate/PubDate'; -import {ReplyButton} from 'coral-plugin-replies'; - -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations'; +import styles from 'coral-embed-stream/src/components/Comment.css'; const lang = new I18n(translations); -class FakeComment extends React.Component { - constructor (props) { - super(props); - } - - render () { - const {username, created_at, body} = this.props; - - return ( -
-
- - - -
-
- -
- {}} - parentCommentId={'commentID'} - currentUserId={{}} - banned={false} - /> -
-
-
- -
-
- -
-
+export const FakeComment = ({username, created_at, body}) => ( +
+
+ + + +
+
+
- ); - } -} - -export default FakeComment; + {}} + parentCommentId={'commentID'} + currentUserId={{}} + banned={false} + /> +
+
+
+ +
+
+ +
+
+
+); \ No newline at end of file diff --git a/plugins/coral-plugin-auth/client/components/ForgotContent.js b/plugins/coral-plugin-auth/client/components/ForgotContent.js index 76246fa00..2099330bc 100644 --- a/plugins/coral-plugin-auth/client/components/ForgotContent.js +++ b/plugins/coral-plugin-auth/client/components/ForgotContent.js @@ -1,22 +1,18 @@ import React from 'react'; import styles from './styles.css'; +import translations from '../translations'; import Button from 'coral-ui/components/Button'; import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations'; + const lang = new I18n(translations); class ForgotContent extends React.Component { - constructor (props) { - super(props); - this.handleSubmit = this.handleSubmit.bind(this); - } - - handleSubmit (e) { + handleSubmit = e => { e.preventDefault(); this.props.fetchForgotPassword(this.emailInput.value); - } + }; - render () { + render() { const {changeView, auth} = this.props; const {passwordRequestSuccess, passwordRequestFailure} = auth; @@ -29,29 +25,47 @@ class ForgotContent extends React.Component {
this.emailInput = input} + ref={input => (this.emailInput = input)} type="text" style={{fontSize: 16}} id="email" - name="email" /> + name="email" + />
- - { - passwordRequestSuccess - ?

{passwordRequestSuccess}

- : null - } - { - passwordRequestFailure - ?

{passwordRequestFailure}

- : null - } + {passwordRequestSuccess + ?

+ {passwordRequestSuccess} +

+ : null} + {passwordRequestFailure + ?

+ {passwordRequestFailure} +

+ : null}
- {lang.t('signIn.needAnAccount')} changeView('SIGNUP')}>{lang.t('signIn.register')} - {lang.t('signIn.alreadyHaveAnAccount')} changeView('SIGNIN')}>{lang.t('signIn.signIn')} + + {lang.t('signIn.needAnAccount')} + {' '} + changeView('SIGNUP')}> + {lang.t('signIn.register')} + + + + {lang.t('signIn.alreadyHaveAnAccount')} + {' '} + changeView('SIGNIN')}> + {lang.t('signIn.signIn')} + +
); diff --git a/plugins/coral-plugin-auth/client/components/SignDialog.js b/plugins/coral-plugin-auth/client/components/SignDialog.js index ff2464f7c..7f05889a0 100644 --- a/plugins/coral-plugin-auth/client/components/SignDialog.js +++ b/plugins/coral-plugin-auth/client/components/SignDialog.js @@ -6,12 +6,9 @@ import SignInContent from './SignInContent'; import SignUpContent from './SignUpContent'; import ForgotContent from './ForgotContent'; -const SignDialog = ({open, view, handleClose, ...props}) => ( - - × +const SignDialog = ({open, view, hideSignInDialog, ...props}) => ( + + × {view === 'SIGNIN' && } {view === 'SIGNUP' && } {view === 'FORGOT' && } diff --git a/plugins/coral-plugin-auth/client/components/SignInButton.js b/plugins/coral-plugin-auth/client/components/SignInButton.js index b4497bc92..b54cbfedd 100644 --- a/plugins/coral-plugin-auth/client/components/SignInButton.js +++ b/plugins/coral-plugin-auth/client/components/SignInButton.js @@ -6,13 +6,11 @@ import {showSignInDialog} from 'coral-framework/actions/auth'; const SignInButton = ({loggedIn, showSignInDialog}) => (
- { - !loggedIn ? ( - - ) : null - } + : null}
); diff --git a/plugins/coral-plugin-auth/client/components/SignInContainer.js b/plugins/coral-plugin-auth/client/components/SignInContainer.js index 5a8ffa11a..cbff000ee 100644 --- a/plugins/coral-plugin-auth/client/components/SignInContainer.js +++ b/plugins/coral-plugin-auth/client/components/SignInContainer.js @@ -169,18 +169,16 @@ class SignInContainer extends React.Component { const {emailVerificationLoading, emailVerificationSuccess} = auth; return ( -
- -
+ ); } } diff --git a/plugins/coral-plugin-auth/client/index.js b/plugins/coral-plugin-auth/client/index.js index 867849cac..41fa3adbe 100644 --- a/plugins/coral-plugin-auth/client/index.js +++ b/plugins/coral-plugin-auth/client/index.js @@ -1,7 +1,7 @@ import UserBox from './components/UserBox'; import SignInButton from './components/SignInButton'; import SignInContainer from './components/SignInContainer'; -import ChangeUserNameContainer from './components/ChangeUserNameContainer'; +import ChangeUserNameContainer from './components/ChangeUsername'; export default { slots: { From 9936b6ec47c6e1ec4c3e9a8fb95c8263ff3a12a0 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 22 May 2017 08:59:34 -0300 Subject: [PATCH 09/36] Prettier --- .../src/components/Stream.js | 141 +++++++++--------- 1 file changed, 74 insertions(+), 67 deletions(-) diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js index a82d7e639..bdf00c46c 100644 --- a/client/coral-embed-stream/src/components/Stream.js +++ b/client/coral-embed-stream/src/components/Stream.js @@ -19,7 +19,7 @@ import ChangeUsernameContainer const lang = new I18n(translations); class Stream extends React.Component { - setActiveReplyBox = (reactKey) => { + setActiveReplyBox = reactKey => { if (!this.props.auth.user) { this.props.showSignInDialog(); } else { @@ -53,7 +53,10 @@ class Stream extends React.Component { : comment; const banned = user && user.status === 'BANNED'; - const temporarilySuspended = user && user.suspension.until && new Date(user.suspension.until) > new Date(); + const temporarilySuspended = + user && + user.suspension.until && + new Date(user.suspension.until) > new Date(); const hasOlderComments = !!(asset && asset.lastComment && @@ -63,8 +66,12 @@ class Stream extends React.Component { const firstCommentDate = asset.comments[0] ? asset.comments[0].created_at : new Date(Date.now() - 1000 * 60 * 60 * 24 * 7).toISOString(); - const commentIsIgnored = (comment) => { - return me && me.ignoredUsers && me.ignoredUsers.find((u) => u.id === comment.user.id); + const commentIsIgnored = comment => { + return ( + me && + me.ignoredUsers && + me.ignoredUsers.find(u => u.id === comment.user.id) + ); }; return (
@@ -81,38 +88,37 @@ class Stream extends React.Component { content={asset.settings.questionBoxContent} enable={asset.settings.questionBoxEnable} /> - {!banned && temporarilySuspended && + {!banned && + temporarilySuspended && - { - lang.t('temporarilySuspended', - this.props.root.settings.organizationName, - lang.timeago(user.suspension.until), - ) - } - - } + {lang.t( + 'temporarilySuspended', + this.props.root.settings.organizationName, + lang.timeago(user.suspension.until) + )} + } {banned && - } - {loggedIn && !banned && !temporarilySuspended && + />} + {loggedIn && + !banned && + !temporarilySuspended && - } + addNotification={this.props.addNotification} + postComment={this.props.postComment} + appendItemArray={this.props.appendItemArray} + updateItem={this.props.updateItem} + setCommentCountCache={this.props.setCommentCountCache} + commentCountCache={commentCountCache} + assetId={asset.id} + premod={asset.settings.moderation} + isReply={false} + authorId={user.id} + charCountEnable={asset.settings.charCountEnable} + maxCharCount={asset.settings.charCount} + />}
:

{asset.settings.closedMessage}

} {!loggedIn && @@ -126,7 +132,11 @@ class Stream extends React.Component { {loggedIn && user && } - {loggedIn && } + {loggedIn && + } {/* the highlightedComment is isolated after the user followed a permalink */} {highlightedComment @@ -164,41 +174,38 @@ class Stream extends React.Component { setCommentCountCache={this.props.setCommentCountCache} />
- {comments.map( - (comment) => { - return (commentIsIgnored(comment) - ? - : - ); - } - )} + {comments.map(comment => { + return commentIsIgnored(comment) + ? + : ; + })}
Date: Mon, 22 May 2017 09:03:10 -0300 Subject: [PATCH 10/36] linting --- client/coral-embed-stream/src/components/Stream.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js index bdf00c46c..ab551e33e 100644 --- a/client/coral-embed-stream/src/components/Stream.js +++ b/client/coral-embed-stream/src/components/Stream.js @@ -19,7 +19,7 @@ import ChangeUsernameContainer const lang = new I18n(translations); class Stream extends React.Component { - setActiveReplyBox = reactKey => { + setActiveReplyBox = (reactKey) => { if (!this.props.auth.user) { this.props.showSignInDialog(); } else { @@ -66,11 +66,11 @@ class Stream extends React.Component { const firstCommentDate = asset.comments[0] ? asset.comments[0].created_at : new Date(Date.now() - 1000 * 60 * 60 * 24 * 7).toISOString(); - const commentIsIgnored = comment => { + const commentIsIgnored = (comment) => { return ( me && me.ignoredUsers && - me.ignoredUsers.find(u => u.id === comment.user.id) + me.ignoredUsers.find((u) => u.id === comment.user.id) ); }; return ( @@ -174,7 +174,7 @@ class Stream extends React.Component { setCommentCountCache={this.props.setCommentCountCache} />
- {comments.map(comment => { + {comments.map((comment) => { return commentIsIgnored(comment) ? : Date: Mon, 22 May 2017 09:39:04 -0300 Subject: [PATCH 11/36] Merge Conflicts --- .../coral-embed-stream/src/components/Stream.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js index ab551e33e..53f716954 100644 --- a/client/coral-embed-stream/src/components/Stream.js +++ b/client/coral-embed-stream/src/components/Stream.js @@ -13,8 +13,6 @@ import translations from 'coral-framework/translations'; import CommentBox from 'coral-plugin-commentbox/CommentBox'; import QuestionBox from 'coral-plugin-questionbox/QuestionBox'; import IgnoredCommentTombstone from './IgnoredCommentTombstone'; -import ChangeUsernameContainer - from 'coral-sign-in/containers/ChangeUsernameContainer'; const lang = new I18n(translations); @@ -75,9 +73,7 @@ class Stream extends React.Component { }; return (
- - {open ?
}
:

{asset.settings.closedMessage}

} - {!loggedIn && - } - {loggedIn && - user && - } {loggedIn && Date: Wed, 24 May 2017 17:20:23 -0300 Subject: [PATCH 12/36] Handling non safari browsers --- client/coral-admin/src/actions/auth.js | 42 +++++++++++++++------- client/coral-framework/actions/auth.js | 24 ++++++++----- client/coral-framework/helpers/response.js | 27 ++++++++------ package.json | 1 + yarn.lock | 4 +++ 5 files changed, 67 insertions(+), 31 deletions(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 29971e294..00ab46910 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,28 +1,44 @@ +import browser from 'detect-browser'; import * as actions from '../constants/auth'; -import * as Storage from 'coral-framework/helpers/storage'; import coralApi from 'coral-framework/helpers/response'; +import * as Storage from 'coral-framework/helpers/storage'; import {handleAuthToken} from 'coral-framework/actions/auth'; //============================================================================== // SIGN IN //============================================================================== -export const handleLogin = (email, password, recaptchaResponse) => (dispatch) => { +export const handleLogin = (email, password, recaptchaResponse) => dispatch => { dispatch({type: actions.LOGIN_REQUEST}); - const params = {method: 'POST', body: {email, password}}; + + const params = { + method: 'POST', + body: { + email, + password + } + }; + if (recaptchaResponse) { - params.headers = {'X-Recaptcha-Response': recaptchaResponse}; + params.headers = { + 'X-Recaptcha-Response': recaptchaResponse + }; } + return coralApi('/auth/local', params) .then(({user, token}) => { + if (!user) { - Storage.removeItem('token'); + if (!browser || browser.name !== 'safari') { + Storage.removeItem('token'); + } return dispatch(checkLoginFailure('not logged in')); } + dispatch(handleAuthToken(token)); dispatch(checkLoginSuccess(user)); }) - .catch((error) => { + .catch(error => { if (error.translation_key === 'LOGIN_MAXIMUM_EXCEEDED') { dispatch({ type: actions.LOGIN_MAXIMUM_EXCEEDED, @@ -50,11 +66,11 @@ const forgotPassowordFailure = () => ({ type: actions.FETCH_FORGOT_PASSWORD_FAILURE }); -export const requestPasswordReset = (email) => (dispatch) => { +export const requestPasswordReset = email => dispatch => { dispatch(forgotPassowordRequest(email)); return coralApi('/account/password/reset', {method: 'POST', body: {email}}) .then(() => dispatch(forgotPassowordSuccess())) - .catch((error) => dispatch(forgotPassowordFailure(error))); + .catch(error => dispatch(forgotPassowordFailure(error))); }; //============================================================================== @@ -71,23 +87,25 @@ const checkLoginSuccess = (user, isAdmin) => ({ isAdmin }); -const checkLoginFailure = (error) => ({ +const checkLoginFailure = error => ({ type: actions.CHECK_LOGIN_FAILURE, error }); -export const checkLogin = () => (dispatch) => { +export const checkLogin = () => dispatch => { dispatch(checkLoginRequest()); return coralApi('/auth') .then(({user}) => { if (!user) { - Storage.removeItem('token'); + if (!browser || browser.name !== 'safari') { + Storage.removeItem('token'); + } return dispatch(checkLoginFailure('not logged in')); } dispatch(checkLoginSuccess(user)); }) - .catch((error) => { + .catch(error => { console.error(error); dispatch(checkLoginFailure(`${error.translation_key}`)); }); diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 6b71fa9dd..071235ce3 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,14 +1,14 @@ -import {pym} from 'coral-framework'; -import * as Storage from '../helpers/storage'; -import * as actions from '../constants/auth'; -import coralApi, {base} from '../helpers/response'; import jwtDecode from 'jwt-decode'; +import {pym} from 'coral-framework'; +import browser from 'detect-browser'; +import * as actions from '../constants/auth'; +import * as Storage from '../helpers/storage'; +import coralApi, {base} from '../helpers/response'; const lang = new I18n(translations); import translations from './../translations'; import I18n from '../../coral-framework/modules/i18n/i18n'; -// Dialog Actions export const showSignInDialog = () => (dispatch) => { const signInPopUp = window.open( '/embed/stream/login', @@ -112,8 +112,10 @@ const signInFailure = (error) => ({ //============================================================================== export const handleAuthToken = (token) => (dispatch) => { - Storage.setItem('exp', jwtDecode(token).exp); - Storage.setItem('token', token); + if (!browser || browser.name !== 'safari') { + Storage.setItem('exp', jwtDecode(token).exp); + Storage.setItem('token', token); + } dispatch({type: 'HANDLE_AUTH_TOKEN'}); }; @@ -269,7 +271,9 @@ export const fetchForgotPassword = (email) => (dispatch) => { export const logout = () => (dispatch) => { return coralApi('/auth', {method: 'DELETE'}).then(() => { - Storage.removeItem('token'); + if (!browser || browser.name !== 'safari') { + Storage.removeItem('token'); + } dispatch({type: actions.LOGOUT}); }); }; @@ -292,7 +296,9 @@ export const checkLogin = () => (dispatch) => { coralApi('/auth') .then((result) => { if (!result.user) { - Storage.removeItem('token'); + if (!browser || browser.name !== 'safari') { + Storage.removeItem('token'); + } throw new Error('Not logged in'); } diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index 794a73e30..bad2e52f7 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -1,22 +1,29 @@ -import * as Storage from './storage'; +import browser from 'detect-browser'; const buildOptions = (inputOptions = {}) => { const defaultOptions = { method: 'GET', headers: { Accept: 'application/json', - Authorization: `Bearer ${Storage.getItem('token')}`, 'Content-Type': 'application/json' }, credentials: 'same-origin' }; - let options = Object.assign({}, defaultOptions, inputOptions); - options.headers = Object.assign( - {}, - defaultOptions.headers, - inputOptions.headers - ); + let options = { + defaultOptions, + ...inputOptions + }; + + if (!browser || browser.name !== 'safari') { + let authorization = localStorage.getItem('token'); + + if (authorization) { + options.headers = { + Authorization: `Bearer ${authorization}` + }; + } + } if (options.method.toLowerCase() !== 'get') { options.body = JSON.stringify(options.body); @@ -25,9 +32,9 @@ const buildOptions = (inputOptions = {}) => { return options; }; -const handleResp = (res) => { +const handleResp = res => { if (res.status > 399) { - return res.json().then((err) => { + return res.json().then(err => { let message = err.message || res.status; const error = new Error(); diff --git a/package.json b/package.json index 84d0fdf52..cbf514cf5 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "csurf": "^1.9.0", "dataloader": "^1.3.0", "debug": "^2.6.3", + "detect-browser": "^1.7.0", "dotenv": "^4.0.0", "ejs": "^2.5.6", "env-rewrite": "^1.0.2", diff --git a/yarn.lock b/yarn.lock index 728687248..3fd71e907 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2390,6 +2390,10 @@ destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" +detect-browser@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-1.7.0.tgz#11758cd6aa07d76c25784036d19154ae0392c3b3" + detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" From bb6be9a7345d7f1b96a13a3e62ad4d9d351b4d18 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 11:53:40 -0300 Subject: [PATCH 13/36] BE implementation --- client/coral-framework/actions/auth.js | 108 +++++++++++---------- client/coral-framework/helpers/response.js | 4 +- routes/api/auth/index.js | 29 +++++- services/passport.js | 7 ++ 4 files changed, 90 insertions(+), 58 deletions(-) diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 071235ce3..7798e165f 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -9,7 +9,7 @@ const lang = new I18n(translations); import translations from './../translations'; import I18n from '../../coral-framework/modules/i18n/i18n'; -export const showSignInDialog = () => (dispatch) => { +export const showSignInDialog = () => dispatch => { const signInPopUp = window.open( '/embed/stream/login', 'Login', @@ -32,7 +32,7 @@ export const showSignInDialog = () => (dispatch) => { dispatch({type: actions.SHOW_SIGNIN_DIALOG}); }; -export const hideSignInDialog = () => (dispatch) => { +export const hideSignInDialog = () => dispatch => { dispatch({type: actions.HIDE_SIGNIN_DIALOG}); window.close(); }; @@ -51,7 +51,7 @@ const createUsernameSuccess = () => ({ type: actions.CREATE_USERNAME_SUCCESS }); -const createUsernameFailure = (error) => ({ +const createUsernameFailure = error => ({ type: actions.CREATE_USERNAME_FAILURE, error }); @@ -61,7 +61,7 @@ export const updateUsername = ({username}) => ({ username }); -export const createUsername = (userId, formData) => (dispatch) => { +export const createUsername = (userId, formData) => dispatch => { dispatch(createUsernameRequest()); coralApi('/account/username', {method: 'PUT', body: formData}) .then(() => { @@ -69,26 +69,26 @@ export const createUsername = (userId, formData) => (dispatch) => { dispatch(hideCreateUsernameDialog()); dispatch(updateUsername(formData)); }) - .catch((error) => { + .catch(error => { dispatch(createUsernameFailure(lang.t(`error.${error.translation_key}`))); }); }; -export const changeView = (view) => (dispatch) => { +export const changeView = view => dispatch => { dispatch({ type: actions.CHANGE_VIEW, view }); switch (view) { - case 'SIGNUP': - window.resizeTo(500, 800); - break; - case 'FORGOT': - window.resizeTo(500, 400); - break; - default: - window.resizeTo(500, 550); + case 'SIGNUP': + window.resizeTo(500, 800); + break; + case 'FORGOT': + window.resizeTo(500, 400); + break; + default: + window.resizeTo(500, 550); } }; @@ -102,7 +102,7 @@ const signInRequest = () => ({ type: actions.FETCH_SIGNIN_REQUEST }); -const signInFailure = (error) => ({ +const signInFailure = error => ({ type: actions.FETCH_SIGNIN_FAILURE, error }); @@ -111,7 +111,7 @@ const signInFailure = (error) => ({ // AUTH TOKEN //============================================================================== -export const handleAuthToken = (token) => (dispatch) => { +export const handleAuthToken = token => dispatch => { if (!browser || browser.name !== 'safari') { Storage.setItem('exp', jwtDecode(token).exp); Storage.setItem('token', token); @@ -123,26 +123,29 @@ export const handleAuthToken = (token) => (dispatch) => { // SIGN IN //============================================================================== -export const fetchSignIn = (formData) => (dispatch) => { - dispatch(signInRequest()); - return coralApi('/auth/local', {method: 'POST', body: formData}) - .then(({token}) => { - dispatch(handleAuthToken(token)); - dispatch(hideSignInDialog()); - }) - .catch((error) => { - if (error.metadata) { +export const fetchSignIn = formData => { + return dispatch => { + dispatch(signInRequest()); - // the user might not have a valid email. prompt the user user re-request the confirmation email - dispatch( - signInFailure(lang.t('error.emailNotVerified', error.metadata)) - ); - } else { + return coralApi('/auth/local', {method: 'POST', body: formData}) + .then(({token}) => { + dispatch(handleAuthToken(token)); + dispatch(hideSignInDialog()); + }) + .catch(error => { + if (error.metadata) { - // invalid credentials - dispatch(signInFailure(lang.t('error.emailPasswordError'))); - } - }); + // the user might not have a valid email. prompt the user user re-request the confirmation email + dispatch( + signInFailure(lang.t('error.emailNotVerified', error.metadata)) + ); + } else { + + // invalid credentials + dispatch(signInFailure(lang.t('error.emailPasswordError'))); + } + }); + }; }; //============================================================================== @@ -153,17 +156,17 @@ const signInFacebookRequest = () => ({ type: actions.FETCH_SIGNIN_FACEBOOK_REQUEST }); -const signInFacebookSuccess = (user) => ({ +const signInFacebookSuccess = user => ({ type: actions.FETCH_SIGNIN_FACEBOOK_SUCCESS, user }); -const signInFacebookFailure = (error) => ({ +const signInFacebookFailure = error => ({ type: actions.FETCH_SIGNIN_FACEBOOK_FAILURE, error }); -export const fetchSignInFacebook = () => (dispatch) => { +export const fetchSignInFacebook = () => dispatch => { dispatch(signInFacebookRequest()); window.open( `${base}/auth/facebook`, @@ -180,7 +183,7 @@ const signUpFacebookRequest = () => ({ type: actions.FETCH_SIGNUP_FACEBOOK_REQUEST }); -export const fetchSignUpFacebook = () => (dispatch) => { +export const fetchSignUpFacebook = () => dispatch => { dispatch(signUpFacebookRequest()); window.open( `${base}/auth/facebook`, @@ -213,10 +216,10 @@ export const facebookCallback = (err, data) => (dispatch, getState) => { //============================================================================== const signUpRequest = () => ({type: actions.FETCH_SIGNUP_REQUEST}); -const signUpSuccess = (user) => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); -const signUpFailure = (error) => ({type: actions.FETCH_SIGNUP_FAILURE, error}); +const signUpSuccess = user => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); +const signUpFailure = error => ({type: actions.FETCH_SIGNUP_FAILURE, error}); -export const fetchSignUp = (formData, redirectUri) => (dispatch) => { +export const fetchSignUp = (formData, redirectUri) => dispatch => { dispatch(signUpRequest()); coralApi('/users', { @@ -227,7 +230,7 @@ export const fetchSignUp = (formData, redirectUri) => (dispatch) => { .then(({user}) => { dispatch(signUpSuccess(user)); }) - .catch((error) => { + .catch(error => { let errorMessage = lang.t(`error.${error.message}`); // if there is no translation defined, just show the error string @@ -254,7 +257,7 @@ const forgotPasswordFailure = () => ({ type: actions.FETCH_FORGOT_PASSWORD_FAILURE }); -export const fetchForgotPassword = (email) => (dispatch) => { +export const fetchForgotPassword = email => dispatch => { dispatch(forgotPasswordRequest(email)); const redirectUri = pym.parentUrl || location.href; coralApi('/account/password/reset', { @@ -262,14 +265,14 @@ export const fetchForgotPassword = (email) => (dispatch) => { body: {email, loc: redirectUri} }) .then(() => dispatch(forgotPasswordSuccess())) - .catch((error) => dispatch(forgotPasswordFailure(error))); + .catch(error => dispatch(forgotPasswordFailure(error))); }; //============================================================================== // LOGOUT //============================================================================== -export const logout = () => (dispatch) => { +export const logout = () => dispatch => { return coralApi('/auth', {method: 'DELETE'}).then(() => { if (!browser || browser.name !== 'safari') { Storage.removeItem('token'); @@ -283,7 +286,7 @@ export const logout = () => (dispatch) => { //============================================================================== const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST}); -const checkLoginFailure = (error) => ({type: actions.CHECK_LOGIN_FAILURE, error}); +const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error}); const checkLoginSuccess = (user, isAdmin) => ({ type: actions.CHECK_LOGIN_SUCCESS, @@ -291,10 +294,10 @@ const checkLoginSuccess = (user, isAdmin) => ({ isAdmin }); -export const checkLogin = () => (dispatch) => { +export const checkLogin = () => dispatch => { dispatch(checkLoginRequest()); coralApi('/auth') - .then((result) => { + .then(result => { if (!result.user) { if (!browser || browser.name !== 'safari') { Storage.removeItem('token'); @@ -304,14 +307,14 @@ export const checkLogin = () => (dispatch) => { dispatch(checkLoginSuccess(result.user)); }) - .catch((error) => { + .catch(error => { console.error(error); dispatch(checkLoginFailure(`${error.translation_key}`)); }); }; export const validForm = () => ({type: actions.VALID_FORM}); -export const invalidForm = (error) => ({type: actions.INVALID_FORM, error}); +export const invalidForm = error => ({type: actions.INVALID_FORM, error}); //============================================================================== // VERIFY EMAIL @@ -329,7 +332,7 @@ const verifyEmailFailure = () => ({ type: actions.VERIFY_EMAIL_FAILURE }); -export const requestConfirmEmail = (email, redirectUri) => (dispatch) => { +export const requestConfirmEmail = (email, redirectUri) => dispatch => { dispatch(verifyEmailRequest()); return coralApi('/users/resend-verify', { method: 'POST', @@ -339,8 +342,7 @@ export const requestConfirmEmail = (email, redirectUri) => (dispatch) => { .then(() => { dispatch(verifyEmailSuccess()); }) - .catch((err) => { - + .catch(err => { // email might have already been verifyed dispatch(verifyEmailFailure(err)); }); diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index bad2e52f7..b6e48abb3 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -5,13 +5,13 @@ const buildOptions = (inputOptions = {}) => { method: 'GET', headers: { Accept: 'application/json', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, credentials: 'same-origin' }; let options = { - defaultOptions, + ...defaultOptions, ...inputOptions }; diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index 6f610e2b0..90fe31b1e 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -3,6 +3,14 @@ const {passport, HandleGenerateCredentials, HandleLogout} = require('../../../se const router = express.Router(); +const lookup = (i) => { + switch (i) { + case 0: return 'header'; + case 1: return 'cookie'; + case 2: return 'query'; + } +}; + /** * This returns the user if they are logged in. */ @@ -15,16 +23,31 @@ router.get('/', (req, res, next) => { res.status(204).end(); }, (req, res) => { - // Send back the user object. - res.json({user: req.user}); + const authorizations = [ + req.headers.authorization, + req.cookies ? req.cookies.authorization : [], + req.query.authorization + ]; + + res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); + + let i = authorizations.findIndex((source) => source !== null && typeof source != 'undefined' && source.length > 0); + if (i >= 0) { + let authorization = authorizations[i]; + let source = lookup(i); + + // Send back the user object. + res.json({authorization, source, user: req.user}); + } }); /** * This blacklists the token used to authenticate. */ + router.delete('/', HandleLogout); -//============================================================================== +// ============================================================================= // PASSPORT ROUTES //============================================================================== diff --git a/services/passport.js b/services/passport.js index c64bb2334..5e993be51 100644 --- a/services/passport.js +++ b/services/passport.js @@ -47,6 +47,12 @@ const HandleGenerateCredentials = (req, res, next) => (err, user) => { // Generate the token to re-issue to the frontend. const token = GenerateToken(user); + // handling cookie + res.cookie('authorization', token, { + httpOnly: true, + expires: new Date(Date.now() + 900000) + }); + // Send back the details! res.json({user, token}); }; @@ -134,6 +140,7 @@ const HandleLogout = (req, res, next) => { return next(err); } + res.clearCookie('authorization'); res.status(204).end(); }); }; From e510553d9a7fb9accafb92f6c8884878bc2ccb9f Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 13:55:03 -0300 Subject: [PATCH 14/36] Sending cookies if safari --- client/coral-admin/src/actions/auth.js | 20 +++--- client/coral-framework/actions/auth.js | 83 +++++++++++----------- client/coral-framework/helpers/response.js | 4 +- routes/api/auth/index.js | 50 +++++++------ services/passport.js | 15 ++-- 5 files changed, 94 insertions(+), 78 deletions(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 00ab46910..16b6c774a 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,4 +1,4 @@ -import browser from 'detect-browser'; +import browser from 'bowser'; import * as actions from '../constants/auth'; import coralApi from 'coral-framework/helpers/response'; import * as Storage from 'coral-framework/helpers/storage'; @@ -8,7 +8,7 @@ import {handleAuthToken} from 'coral-framework/actions/auth'; // SIGN IN //============================================================================== -export const handleLogin = (email, password, recaptchaResponse) => dispatch => { +export const handleLogin = (email, password, recaptchaResponse) => (dispatch) => { dispatch({type: actions.LOGIN_REQUEST}); const params = { @@ -29,7 +29,7 @@ export const handleLogin = (email, password, recaptchaResponse) => dispatch => { .then(({user, token}) => { if (!user) { - if (!browser || browser.name !== 'safari') { + if (!browser || browser.name !== 'Safari') { Storage.removeItem('token'); } return dispatch(checkLoginFailure('not logged in')); @@ -38,7 +38,7 @@ export const handleLogin = (email, password, recaptchaResponse) => dispatch => { dispatch(handleAuthToken(token)); dispatch(checkLoginSuccess(user)); }) - .catch(error => { + .catch((error) => { if (error.translation_key === 'LOGIN_MAXIMUM_EXCEEDED') { dispatch({ type: actions.LOGIN_MAXIMUM_EXCEEDED, @@ -66,11 +66,11 @@ const forgotPassowordFailure = () => ({ type: actions.FETCH_FORGOT_PASSWORD_FAILURE }); -export const requestPasswordReset = email => dispatch => { +export const requestPasswordReset = (email) => (dispatch) => { dispatch(forgotPassowordRequest(email)); return coralApi('/account/password/reset', {method: 'POST', body: {email}}) .then(() => dispatch(forgotPassowordSuccess())) - .catch(error => dispatch(forgotPassowordFailure(error))); + .catch((error) => dispatch(forgotPassowordFailure(error))); }; //============================================================================== @@ -87,17 +87,17 @@ const checkLoginSuccess = (user, isAdmin) => ({ isAdmin }); -const checkLoginFailure = error => ({ +const checkLoginFailure = (error) => ({ type: actions.CHECK_LOGIN_FAILURE, error }); -export const checkLogin = () => dispatch => { +export const checkLogin = () => (dispatch) => { dispatch(checkLoginRequest()); return coralApi('/auth') .then(({user}) => { if (!user) { - if (!browser || browser.name !== 'safari') { + if (!browser || browser.name !== 'Safari') { Storage.removeItem('token'); } return dispatch(checkLoginFailure('not logged in')); @@ -105,7 +105,7 @@ export const checkLogin = () => dispatch => { dispatch(checkLoginSuccess(user)); }) - .catch(error => { + .catch((error) => { console.error(error); dispatch(checkLoginFailure(`${error.translation_key}`)); }); diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 7798e165f..2f0a2dc0f 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,6 +1,6 @@ import jwtDecode from 'jwt-decode'; import {pym} from 'coral-framework'; -import browser from 'detect-browser'; +import browser from 'bowser'; import * as actions from '../constants/auth'; import * as Storage from '../helpers/storage'; import coralApi, {base} from '../helpers/response'; @@ -9,7 +9,7 @@ const lang = new I18n(translations); import translations from './../translations'; import I18n from '../../coral-framework/modules/i18n/i18n'; -export const showSignInDialog = () => dispatch => { +export const showSignInDialog = () => (dispatch) => { const signInPopUp = window.open( '/embed/stream/login', 'Login', @@ -32,7 +32,7 @@ export const showSignInDialog = () => dispatch => { dispatch({type: actions.SHOW_SIGNIN_DIALOG}); }; -export const hideSignInDialog = () => dispatch => { +export const hideSignInDialog = () => (dispatch) => { dispatch({type: actions.HIDE_SIGNIN_DIALOG}); window.close(); }; @@ -51,7 +51,7 @@ const createUsernameSuccess = () => ({ type: actions.CREATE_USERNAME_SUCCESS }); -const createUsernameFailure = error => ({ +const createUsernameFailure = (error) => ({ type: actions.CREATE_USERNAME_FAILURE, error }); @@ -61,7 +61,7 @@ export const updateUsername = ({username}) => ({ username }); -export const createUsername = (userId, formData) => dispatch => { +export const createUsername = (userId, formData) => (dispatch) => { dispatch(createUsernameRequest()); coralApi('/account/username', {method: 'PUT', body: formData}) .then(() => { @@ -69,26 +69,26 @@ export const createUsername = (userId, formData) => dispatch => { dispatch(hideCreateUsernameDialog()); dispatch(updateUsername(formData)); }) - .catch(error => { + .catch((error) => { dispatch(createUsernameFailure(lang.t(`error.${error.translation_key}`))); }); }; -export const changeView = view => dispatch => { +export const changeView = (view) => (dispatch) => { dispatch({ type: actions.CHANGE_VIEW, view }); switch (view) { - case 'SIGNUP': - window.resizeTo(500, 800); - break; - case 'FORGOT': - window.resizeTo(500, 400); - break; - default: - window.resizeTo(500, 550); + case 'SIGNUP': + window.resizeTo(500, 800); + break; + case 'FORGOT': + window.resizeTo(500, 400); + break; + default: + window.resizeTo(500, 550); } }; @@ -102,7 +102,7 @@ const signInRequest = () => ({ type: actions.FETCH_SIGNIN_REQUEST }); -const signInFailure = error => ({ +const signInFailure = (error) => ({ type: actions.FETCH_SIGNIN_FAILURE, error }); @@ -111,8 +111,8 @@ const signInFailure = error => ({ // AUTH TOKEN //============================================================================== -export const handleAuthToken = token => dispatch => { - if (!browser || browser.name !== 'safari') { +export const handleAuthToken = (token) => (dispatch) => { + if (!browser || browser.name !== 'Safari') { Storage.setItem('exp', jwtDecode(token).exp); Storage.setItem('token', token); } @@ -123,8 +123,8 @@ export const handleAuthToken = token => dispatch => { // SIGN IN //============================================================================== -export const fetchSignIn = formData => { - return dispatch => { +export const fetchSignIn = (formData) => { + return (dispatch) => { dispatch(signInRequest()); return coralApi('/auth/local', {method: 'POST', body: formData}) @@ -132,7 +132,7 @@ export const fetchSignIn = formData => { dispatch(handleAuthToken(token)); dispatch(hideSignInDialog()); }) - .catch(error => { + .catch((error) => { if (error.metadata) { // the user might not have a valid email. prompt the user user re-request the confirmation email @@ -156,17 +156,17 @@ const signInFacebookRequest = () => ({ type: actions.FETCH_SIGNIN_FACEBOOK_REQUEST }); -const signInFacebookSuccess = user => ({ +const signInFacebookSuccess = (user) => ({ type: actions.FETCH_SIGNIN_FACEBOOK_SUCCESS, user }); -const signInFacebookFailure = error => ({ +const signInFacebookFailure = (error) => ({ type: actions.FETCH_SIGNIN_FACEBOOK_FAILURE, error }); -export const fetchSignInFacebook = () => dispatch => { +export const fetchSignInFacebook = () => (dispatch) => { dispatch(signInFacebookRequest()); window.open( `${base}/auth/facebook`, @@ -183,7 +183,7 @@ const signUpFacebookRequest = () => ({ type: actions.FETCH_SIGNUP_FACEBOOK_REQUEST }); -export const fetchSignUpFacebook = () => dispatch => { +export const fetchSignUpFacebook = () => (dispatch) => { dispatch(signUpFacebookRequest()); window.open( `${base}/auth/facebook`, @@ -216,10 +216,10 @@ export const facebookCallback = (err, data) => (dispatch, getState) => { //============================================================================== const signUpRequest = () => ({type: actions.FETCH_SIGNUP_REQUEST}); -const signUpSuccess = user => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); -const signUpFailure = error => ({type: actions.FETCH_SIGNUP_FAILURE, error}); +const signUpSuccess = (user) => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); +const signUpFailure = (error) => ({type: actions.FETCH_SIGNUP_FAILURE, error}); -export const fetchSignUp = (formData, redirectUri) => dispatch => { +export const fetchSignUp = (formData, redirectUri) => (dispatch) => { dispatch(signUpRequest()); coralApi('/users', { @@ -230,7 +230,7 @@ export const fetchSignUp = (formData, redirectUri) => dispatch => { .then(({user}) => { dispatch(signUpSuccess(user)); }) - .catch(error => { + .catch((error) => { let errorMessage = lang.t(`error.${error.message}`); // if there is no translation defined, just show the error string @@ -257,7 +257,7 @@ const forgotPasswordFailure = () => ({ type: actions.FETCH_FORGOT_PASSWORD_FAILURE }); -export const fetchForgotPassword = email => dispatch => { +export const fetchForgotPassword = (email) => (dispatch) => { dispatch(forgotPasswordRequest(email)); const redirectUri = pym.parentUrl || location.href; coralApi('/account/password/reset', { @@ -265,16 +265,16 @@ export const fetchForgotPassword = email => dispatch => { body: {email, loc: redirectUri} }) .then(() => dispatch(forgotPasswordSuccess())) - .catch(error => dispatch(forgotPasswordFailure(error))); + .catch((error) => dispatch(forgotPasswordFailure(error))); }; //============================================================================== // LOGOUT //============================================================================== -export const logout = () => dispatch => { +export const logout = () => (dispatch) => { return coralApi('/auth', {method: 'DELETE'}).then(() => { - if (!browser || browser.name !== 'safari') { + if (!browser || browser.name !== 'Safari') { Storage.removeItem('token'); } dispatch({type: actions.LOGOUT}); @@ -286,7 +286,7 @@ export const logout = () => dispatch => { //============================================================================== const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST}); -const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error}); +const checkLoginFailure = (error) => ({type: actions.CHECK_LOGIN_FAILURE, error}); const checkLoginSuccess = (user, isAdmin) => ({ type: actions.CHECK_LOGIN_SUCCESS, @@ -294,12 +294,12 @@ const checkLoginSuccess = (user, isAdmin) => ({ isAdmin }); -export const checkLogin = () => dispatch => { +export const checkLogin = () => (dispatch) => { dispatch(checkLoginRequest()); coralApi('/auth') - .then(result => { + .then((result) => { if (!result.user) { - if (!browser || browser.name !== 'safari') { + if (!browser || browser.name !== 'Safari') { Storage.removeItem('token'); } throw new Error('Not logged in'); @@ -307,14 +307,14 @@ export const checkLogin = () => dispatch => { dispatch(checkLoginSuccess(result.user)); }) - .catch(error => { + .catch((error) => { console.error(error); dispatch(checkLoginFailure(`${error.translation_key}`)); }); }; export const validForm = () => ({type: actions.VALID_FORM}); -export const invalidForm = error => ({type: actions.INVALID_FORM, error}); +export const invalidForm = (error) => ({type: actions.INVALID_FORM, error}); //============================================================================== // VERIFY EMAIL @@ -332,7 +332,7 @@ const verifyEmailFailure = () => ({ type: actions.VERIFY_EMAIL_FAILURE }); -export const requestConfirmEmail = (email, redirectUri) => dispatch => { +export const requestConfirmEmail = (email, redirectUri) => (dispatch) => { dispatch(verifyEmailRequest()); return coralApi('/users/resend-verify', { method: 'POST', @@ -342,7 +342,8 @@ export const requestConfirmEmail = (email, redirectUri) => dispatch => { .then(() => { dispatch(verifyEmailSuccess()); }) - .catch(err => { + .catch((err) => { + // email might have already been verifyed dispatch(verifyEmailFailure(err)); }); diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index b6e48abb3..ce9de6942 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -32,9 +32,9 @@ const buildOptions = (inputOptions = {}) => { return options; }; -const handleResp = res => { +const handleResp = (res) => { if (res.status > 399) { - return res.json().then(err => { + return res.json().then((err) => { let message = err.message || res.status; const error = new Error(); diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index 90fe31b1e..e0e39adf9 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -1,16 +1,9 @@ const express = require('express'); +const bowser = require('bowser'); const {passport, HandleGenerateCredentials, HandleLogout} = require('../../../services/passport'); const router = express.Router(); -const lookup = (i) => { - switch (i) { - case 0: return 'header'; - case 1: return 'cookie'; - case 2: return 'query'; - } -}; - /** * This returns the user if they are logged in. */ @@ -23,22 +16,39 @@ router.get('/', (req, res, next) => { res.status(204).end(); }, (req, res) => { - const authorizations = [ - req.headers.authorization, - req.cookies ? req.cookies.authorization : [], - req.query.authorization - ]; + // If the user is Safari, let's send a cookie + const browser = bowser._detect(req.headers['user-agent']); - res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); + if (browser.name === 'Safari') { - let i = authorizations.findIndex((source) => source !== null && typeof source != 'undefined' && source.length > 0); - if (i >= 0) { - let authorization = authorizations[i]; - let source = lookup(i); + const lookup = (i) => { + switch (i) { + case 0: return 'header'; + case 1: return 'cookie'; + case 2: return 'query'; + } + }; - // Send back the user object. - res.json({authorization, source, user: req.user}); + const authorizations = [ + req.headers.authorization, + req.cookies ? req.cookies.authorization : [], + req.query.authorization + ]; + + res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); + + let i = authorizations.findIndex((source) => source !== null && typeof source != 'undefined' && source.length > 0); + if (i >= 0) { + let authorization = authorizations[i]; + let source = lookup(i); + + // Send back the user object. + res.json({authorization, source, user: req.user}); + } } + + // Send back the user object. + res.json({user: req.user}); }); /** diff --git a/services/passport.js b/services/passport.js index 5e993be51..4b1c10158 100644 --- a/services/passport.js +++ b/services/passport.js @@ -9,6 +9,7 @@ const errors = require('../errors'); const uuid = require('uuid'); const debug = require('debug')('talk:passport'); const {createClient} = require('./redis'); +const bowser = require('bowser'); // Create a redis client to use for authentication. const client = createClient(); @@ -47,11 +48,15 @@ const HandleGenerateCredentials = (req, res, next) => (err, user) => { // Generate the token to re-issue to the frontend. const token = GenerateToken(user); - // handling cookie - res.cookie('authorization', token, { - httpOnly: true, - expires: new Date(Date.now() + 900000) - }); + // If the user is Safari, let's send a cookie + const browser = bowser._detect(req.headers['user-agent']); + + if (browser.name === 'Safari') { + res.cookie('authorization', token, { + httpOnly: true, + expires: new Date(Date.now() + 900000) + }); + } // Send back the details! res.json({user, token}); From 75080cfe3055d214ac29d14e5b50760ebb49082b Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 16:19:19 -0300 Subject: [PATCH 15/36] Password reset and valid locations --- client/coral-admin/src/actions/auth.js | 7 +++++-- services/users.js | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 29971e294..2eb85c86a 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,6 +1,7 @@ +import {pym} from 'coral-framework'; import * as actions from '../constants/auth'; -import * as Storage from 'coral-framework/helpers/storage'; import coralApi from 'coral-framework/helpers/response'; +import * as Storage from 'coral-framework/helpers/storage'; import {handleAuthToken} from 'coral-framework/actions/auth'; //============================================================================== @@ -52,7 +53,9 @@ const forgotPassowordFailure = () => ({ export const requestPasswordReset = (email) => (dispatch) => { dispatch(forgotPassowordRequest(email)); - return coralApi('/account/password/reset', {method: 'POST', body: {email}}) + const redirectUri = location.href; + + return coralApi('/account/password/reset', {method: 'POST', body: {email, loc: redirectUri}}) .then(() => dispatch(forgotPassowordSuccess())) .catch((error) => dispatch(forgotPassowordFailure(error))); }; diff --git a/services/users.js b/services/users.js index 496db4528..07a690411 100644 --- a/services/users.js +++ b/services/users.js @@ -566,10 +566,9 @@ module.exports = class UsersService { // endpoint. return; } - let redirectDomain; try { - redirectDomain = url.parse(loc).hostname; + redirectDomain = url.parse(loc).host; } catch (e) { return Promise.reject('redirect location is invalid'); } From 21644bda8a7cf18c84dcd3c54f8eee72efd7b3e6 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 16:24:39 -0300 Subject: [PATCH 16/36] Linting --- client/coral-admin/src/actions/auth.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 2eb85c86a..d5a1eeea1 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,4 +1,3 @@ -import {pym} from 'coral-framework'; import * as actions from '../constants/auth'; import coralApi from 'coral-framework/helpers/response'; import * as Storage from 'coral-framework/helpers/storage'; From a8c361e2f7bdc8fea5105b87e6b46eee09ea31b6 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 16:53:12 -0300 Subject: [PATCH 17/36] by hostname --- services/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/users.js b/services/users.js index 07a690411..4c76f179c 100644 --- a/services/users.js +++ b/services/users.js @@ -568,7 +568,7 @@ module.exports = class UsersService { } let redirectDomain; try { - redirectDomain = url.parse(loc).host; + redirectDomain = url.parse(loc).hostname; } catch (e) { return Promise.reject('redirect location is invalid'); } From 460f3f292b3e89967dd2568b96b4bcc5c4a1f271 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 17:41:35 -0300 Subject: [PATCH 18/36] =?UTF-8?q?=C3=81dding=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 4 ++++ package.json | 3 +++ yarn.lock | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/app.js b/app.js index 16840f965..d0f0f316b 100644 --- a/app.js +++ b/app.js @@ -11,6 +11,8 @@ const errors = require('./errors'); const {createGraphOptions} = require('./graph'); const apollo = require('graphql-server-express'); const accepts = require('accepts'); +const compression = require('compression'); +const cookieParser = require('cookie-parser'); const app = express(); @@ -31,6 +33,8 @@ app.set('trust proxy', 1); app.use(helmet({ frameguard: false })); +app.use(compression()); +app.use(cookieParser()); app.use(bodyParser.json()); //============================================================================== diff --git a/package.json b/package.json index cbf514cf5..b1eb180ed 100644 --- a/package.json +++ b/package.json @@ -54,10 +54,13 @@ "app-module-path": "^2.2.0", "bcrypt": "^1.0.2", "body-parser": "^1.17.1", + "bowser": "^1.7.0", "cli-table": "^0.3.1", "colors": "^1.1.2", "commander": "^2.9.0", + "compression": "^1.6.2", "connect-redis": "^3.1.0", + "cookie-parser": "^1.4.3", "cross-spawn": "^5.1.0", "csurf": "^1.9.0", "dataloader": "^1.3.0", diff --git a/yarn.lock b/yarn.lock index 3fd71e907..cc1ddd018 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1262,6 +1262,10 @@ boom@2.x.x: dependencies: hoek "2.x.x" +bowser@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.0.tgz#169de4018711f994242bff9a8009e77a1f35e003" + brace-expansion@^1.0.0: version "1.1.7" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" @@ -1395,6 +1399,10 @@ builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" +bytes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + bytes@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" @@ -1815,6 +1823,12 @@ component-emitter@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +compressible@~2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" + dependencies: + mime-db ">= 1.27.0 < 2" + compression-webpack-plugin@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-0.4.0.tgz#811de04215f811ea6a12d4d8aed8457d758f13ac" @@ -1824,6 +1838,17 @@ compression-webpack-plugin@^0.4.0: optionalDependencies: node-zopfli "^2.0.0" +compression@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1925,6 +1950,13 @@ convert-source-map@^1.1.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" +cookie-parser@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5" + dependencies: + cookie "0.3.1" + cookie-signature "1.0.6" + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -5147,14 +5179,14 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +"mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" + mime-db@~1.12.0: version "1.12.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.12.0.tgz#3d0c63180f458eb10d325aaa37d7c58ae312e9d7" -mime-db@~1.27.0: - version "1.27.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" - mime-types@^2.1.10, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: version "2.1.15" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" From 178cecad053f2c754470386008cc5ee4ec314933 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 25 May 2017 16:58:35 -0400 Subject: [PATCH 19/36] Update version 1.7.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84d0fdf52..f40ea4e1e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "talk", - "version": "1.6.0", + "version": "1.7.0", "description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net", "main": "app.js", "scripts": { From cbf7cc67f4100ba123eacf7035808da9315079bd Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 18:30:01 -0300 Subject: [PATCH 20/36] Extracting token from cookie if safari --- client/coral-framework/actions/auth.js | 10 ++++---- routes/api/auth/index.js | 2 +- services/passport.js | 32 +++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 2f0a2dc0f..f0827ca73 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -112,10 +112,8 @@ const signInFailure = (error) => ({ //============================================================================== export const handleAuthToken = (token) => (dispatch) => { - if (!browser || browser.name !== 'Safari') { - Storage.setItem('exp', jwtDecode(token).exp); - Storage.setItem('token', token); - } + Storage.setItem('exp', jwtDecode(token).exp); + Storage.setItem('token', token); dispatch({type: 'HANDLE_AUTH_TOKEN'}); }; @@ -129,7 +127,9 @@ export const fetchSignIn = (formData) => { return coralApi('/auth/local', {method: 'POST', body: formData}) .then(({token}) => { - dispatch(handleAuthToken(token)); + if (!browser || browser.name !== 'Safari') { + dispatch(handleAuthToken(token)); + } dispatch(hideSignInDialog()); }) .catch((error) => { diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index e0e39adf9..c5c2e3dfb 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -8,7 +8,7 @@ const router = express.Router(); * This returns the user if they are logged in. */ router.get('/', (req, res, next) => { - + console.log('is there req user>', req.user); if (req.user) { return next(); } diff --git a/services/passport.js b/services/passport.js index 4b1c10158..07a98f789 100644 --- a/services/passport.js +++ b/services/passport.js @@ -174,7 +174,37 @@ const ExtractJwt = require('passport-jwt').ExtractJwt; passport.use(new JwtStrategy({ // Prepare the extractor from the header. - jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'), + jwtFromRequest: (req, res) => { + + const browser = bowser._detect(req.headers['user-agent']); + + if (browser.name === 'Safari') { + const lookup = (i) => { + switch (i) { + case 0: return 'header'; + case 1: return 'cookie'; + case 2: return 'query'; + } + } + + // Adding custom extractor + const authorizations = [ + req.headers.authorization, + req.cookies.authorization, + req.query.authorization + ]; + + let i = authorizations.findIndex((source) => source !== null && typeof source != 'undefined' && source.length > 0); + + if (i >= 0) { + let authorization = authorizations[i]; + let source = lookup(i); + return authorization; + } + } else { + return ExtractJwt.fromAuthHeaderWithScheme('Bearer')(req) + } +}, // Use the secret passed in which is loaded from the environment. This can be // a certificate (loaded) or a HMAC key. From 8171cb53e1301027dfd5d959e4ad13dd486ad3a9 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 20:04:32 -0300 Subject: [PATCH 21/36] =?UTF-8?q?=C3=81dding=20another=20extractor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/coral-framework/helpers/response.js | 4 +- client/coral-framework/services/transport.js | 7 ++- routes/api/auth/index.js | 34 +-------------- services/passport.js | 46 +++++++------------- 4 files changed, 25 insertions(+), 66 deletions(-) diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index ce9de6942..b3e167d16 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -1,4 +1,4 @@ -import browser from 'detect-browser'; +import browser from 'bowser'; const buildOptions = (inputOptions = {}) => { const defaultOptions = { @@ -15,7 +15,7 @@ const buildOptions = (inputOptions = {}) => { ...inputOptions }; - if (!browser || browser.name !== 'safari') { + if (!browser || browser.name !== 'Safari') { let authorization = localStorage.getItem('token'); if (authorization) { diff --git a/client/coral-framework/services/transport.js b/client/coral-framework/services/transport.js index e421ca3da..8aa33e2f4 100644 --- a/client/coral-framework/services/transport.js +++ b/client/coral-framework/services/transport.js @@ -1,5 +1,6 @@ import {createNetworkInterface} from 'apollo-client'; import * as Storage from '../helpers/storage'; +import browser from 'bowser'; //============================================================================== // NETWORK INTERFACE @@ -21,7 +22,11 @@ networkInterface.use([{ if (!req.options.headers) { req.options.headers = {}; // Create the header object if needed. } - req.options.headers['authorization'] = `Bearer ${Storage.getItem('token')}`; + + if (!browser || browser.name !== 'Safari') { + req.options.headers['authorization'] = `Bearer ${Storage.getItem('token')}`; + } + next(); } }]); diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index c5c2e3dfb..05fb8b5e4 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -8,7 +8,8 @@ const router = express.Router(); * This returns the user if they are logged in. */ router.get('/', (req, res, next) => { - console.log('is there req user>', req.user); + console.log('REQ.USER', req.user); + if (req.user) { return next(); } @@ -16,37 +17,6 @@ router.get('/', (req, res, next) => { res.status(204).end(); }, (req, res) => { - // If the user is Safari, let's send a cookie - const browser = bowser._detect(req.headers['user-agent']); - - if (browser.name === 'Safari') { - - const lookup = (i) => { - switch (i) { - case 0: return 'header'; - case 1: return 'cookie'; - case 2: return 'query'; - } - }; - - const authorizations = [ - req.headers.authorization, - req.cookies ? req.cookies.authorization : [], - req.query.authorization - ]; - - res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); - - let i = authorizations.findIndex((source) => source !== null && typeof source != 'undefined' && source.length > 0); - if (i >= 0) { - let authorization = authorizations[i]; - let source = lookup(i); - - // Send back the user object. - res.json({authorization, source, user: req.user}); - } - } - // Send back the user object. res.json({user: req.user}); }); diff --git a/services/passport.js b/services/passport.js index 07a98f789..d67407b3c 100644 --- a/services/passport.js +++ b/services/passport.js @@ -170,41 +170,24 @@ const CheckBlacklisted = (jwt) => new Promise((resolve, reject) => { const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; +let cookieExtractor = function(req) { + let token = null; + + if (req && req.cookies) { + token = req.cookies['authorization']; + } + + return token; +}; + // Extract the JWT from the 'Authorization' header with the 'Bearer' scheme. passport.use(new JwtStrategy({ // Prepare the extractor from the header. - jwtFromRequest: (req, res) => { - - const browser = bowser._detect(req.headers['user-agent']); - - if (browser.name === 'Safari') { - const lookup = (i) => { - switch (i) { - case 0: return 'header'; - case 1: return 'cookie'; - case 2: return 'query'; - } - } - - // Adding custom extractor - const authorizations = [ - req.headers.authorization, - req.cookies.authorization, - req.query.authorization - ]; - - let i = authorizations.findIndex((source) => source !== null && typeof source != 'undefined' && source.length > 0); - - if (i >= 0) { - let authorization = authorizations[i]; - let source = lookup(i); - return authorization; - } - } else { - return ExtractJwt.fromAuthHeaderWithScheme('Bearer')(req) - } -}, + jwtFromRequest: ExtractJwt.fromExtractors([ + cookieExtractor, + ExtractJwt.fromAuthHeaderWithScheme('Bearer') + ]), // Use the secret passed in which is loaded from the environment. This can be // a certificate (loaded) or a HMAC key. @@ -227,6 +210,7 @@ passport.use(new JwtStrategy({ // Load the user from the environment, because we just got a user from the // header. try { + console.log(req.cookies, req.headers) // Check to see if the token has been revoked await CheckBlacklisted(jwt); From 8edc16ed8507a5b2625c2d685f8d8fa28cd2ed32 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Thu, 25 May 2017 20:06:49 -0300 Subject: [PATCH 22/36] Removing logs --- routes/api/auth/index.js | 1 - services/passport.js | 1 - 2 files changed, 2 deletions(-) diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index 05fb8b5e4..9035ce268 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -8,7 +8,6 @@ const router = express.Router(); * This returns the user if they are logged in. */ router.get('/', (req, res, next) => { - console.log('REQ.USER', req.user); if (req.user) { return next(); diff --git a/services/passport.js b/services/passport.js index d67407b3c..719086f89 100644 --- a/services/passport.js +++ b/services/passport.js @@ -210,7 +210,6 @@ passport.use(new JwtStrategy({ // Load the user from the environment, because we just got a user from the // header. try { - console.log(req.cookies, req.headers) // Check to see if the token has been revoked await CheckBlacklisted(jwt); From 276e58060aee26f6213b52c7c99abe34030ddb89 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 26 May 2017 17:11:29 +0700 Subject: [PATCH 23/36] Fix change username dialog --- .../coral-plugin-auth/client/components/ChangeUsername.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/coral-plugin-auth/client/components/ChangeUsername.js b/plugins/coral-plugin-auth/client/components/ChangeUsername.js index 9b0cbb1a6..5b5a54510 100644 --- a/plugins/coral-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/coral-plugin-auth/client/components/ChangeUsername.js @@ -23,7 +23,7 @@ class ChangeUsernameContainer extends React.Component { this.state = { formData: { - username: props.user.username + username: (props.auth.user && props.auth.user.username) || '' }, errors: {}, showErrors: false @@ -84,7 +84,7 @@ class ChangeUsernameContainer extends React.Component { const {validForm, invalidForm} = this.props; this.displayErrors(); if (this.isCompleted() && !Object.keys(errors).length) { - this.props.createUsername(this.props.user.id, this.state.formData); + this.props.createUsername(this.props.auth.user.id, this.state.formData); validForm(); } else { invalidForm(lang.t('createdisplay.checkTheForm')); @@ -113,7 +113,9 @@ class ChangeUsernameContainer extends React.Component { } } -const mapStateToProps = ({auth, user}) => ({auth, user}); +const mapStateToProps = ({auth}) => ({ + auth: auth.toJS() +}); const mapDispatchToProps = dispatch => bindActionCreators( From bab47c9d444c450a98ab8d5ab6a77ee941453721 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 26 May 2017 20:33:43 +0700 Subject: [PATCH 24/36] Separate store --- client/coral-embed-stream/src/index.js | 6 ++---- client/coral-framework/actions/auth.js | 11 ++++++----- .../client/components/ChangeUsername.js | 2 +- routes/api/auth/index.js | 1 - 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/client/coral-embed-stream/src/index.js b/client/coral-embed-stream/src/index.js index 0306079f3..66ed9ad56 100644 --- a/client/coral-embed-stream/src/index.js +++ b/client/coral-embed-stream/src/index.js @@ -8,16 +8,14 @@ import './graphql'; import {addExternalConfig} from 'coral-embed-stream/src/actions/config'; import reducers from './reducers'; -import localStore, {injectReducers} from 'coral-framework/services/store'; +import store, {injectReducers} from 'coral-framework/services/store'; import AppRouter from './AppRouter'; import {pym} from 'coral-framework'; injectReducers(reducers); -const store = (window.opener && window.opener.coralStore) ? window.opener.coralStore : localStore; - // Don't run this in the popup. -if (store === localStore) { +if (!window.opener) { store.dispatch(checkLogin()); pym.sendMessage('getConfig'); diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index f0827ca73..c4d6d782e 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -192,7 +192,7 @@ export const fetchSignUpFacebook = () => (dispatch) => { ); }; -export const facebookCallback = (err, data) => (dispatch, getState) => { +export const facebookCallback = (err, data) => (dispatch) => { if (err) { dispatch(signInFacebookFailure(err)); return; @@ -201,10 +201,6 @@ export const facebookCallback = (err, data) => (dispatch, getState) => { dispatch(handleAuthToken(data.token)); dispatch(signInFacebookSuccess(data.user)); dispatch(hideSignInDialog()); - const {user: {canEditName, status}} = getState().auth.toJS(); - if (canEditName && status !== 'BANNED') { - dispatch(showCreateUsernameDialog()); - } } catch (err) { dispatch(signInFacebookFailure(err)); return; @@ -306,6 +302,11 @@ export const checkLogin = () => (dispatch) => { } dispatch(checkLoginSuccess(result.user)); + + // Display create username dialog if necessary. + if (result.user.canEditName && result.user.status !== 'BANNED') { + dispatch(showCreateUsernameDialog()); + } }) .catch((error) => { console.error(error); diff --git a/plugins/coral-plugin-auth/client/components/ChangeUsername.js b/plugins/coral-plugin-auth/client/components/ChangeUsername.js index 5b5a54510..761fe786d 100644 --- a/plugins/coral-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/coral-plugin-auth/client/components/ChangeUsername.js @@ -100,7 +100,7 @@ class ChangeUsernameContainer extends React.Component { return (
Date: Fri, 26 May 2017 20:48:24 +0700 Subject: [PATCH 25/36] Detect mobile safari & desktop safari --- client/coral-admin/src/actions/auth.js | 6 +++--- client/coral-framework/actions/auth.js | 8 ++++---- client/coral-framework/helpers/response.js | 4 ++-- client/coral-framework/services/transport.js | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 16b6c774a..69e7d4303 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,4 +1,4 @@ -import browser from 'bowser'; +import bowser from 'bowser'; import * as actions from '../constants/auth'; import coralApi from 'coral-framework/helpers/response'; import * as Storage from 'coral-framework/helpers/storage'; @@ -29,7 +29,7 @@ export const handleLogin = (email, password, recaptchaResponse) => (dispatch) => .then(({user, token}) => { if (!user) { - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { Storage.removeItem('token'); } return dispatch(checkLoginFailure('not logged in')); @@ -97,7 +97,7 @@ export const checkLogin = () => (dispatch) => { return coralApi('/auth') .then(({user}) => { if (!user) { - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { Storage.removeItem('token'); } return dispatch(checkLoginFailure('not logged in')); diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index c4d6d782e..2deda5f1d 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,6 +1,6 @@ import jwtDecode from 'jwt-decode'; import {pym} from 'coral-framework'; -import browser from 'bowser'; +import bowser from 'bowser'; import * as actions from '../constants/auth'; import * as Storage from '../helpers/storage'; import coralApi, {base} from '../helpers/response'; @@ -127,7 +127,7 @@ export const fetchSignIn = (formData) => { return coralApi('/auth/local', {method: 'POST', body: formData}) .then(({token}) => { - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { dispatch(handleAuthToken(token)); } dispatch(hideSignInDialog()); @@ -270,7 +270,7 @@ export const fetchForgotPassword = (email) => (dispatch) => { export const logout = () => (dispatch) => { return coralApi('/auth', {method: 'DELETE'}).then(() => { - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { Storage.removeItem('token'); } dispatch({type: actions.LOGOUT}); @@ -295,7 +295,7 @@ export const checkLogin = () => (dispatch) => { coralApi('/auth') .then((result) => { if (!result.user) { - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { Storage.removeItem('token'); } throw new Error('Not logged in'); diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index b3e167d16..ac6e53cf9 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -1,4 +1,4 @@ -import browser from 'bowser'; +import bowser from 'bowser'; const buildOptions = (inputOptions = {}) => { const defaultOptions = { @@ -15,7 +15,7 @@ const buildOptions = (inputOptions = {}) => { ...inputOptions }; - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { let authorization = localStorage.getItem('token'); if (authorization) { diff --git a/client/coral-framework/services/transport.js b/client/coral-framework/services/transport.js index 8aa33e2f4..0c430a021 100644 --- a/client/coral-framework/services/transport.js +++ b/client/coral-framework/services/transport.js @@ -1,6 +1,6 @@ import {createNetworkInterface} from 'apollo-client'; import * as Storage from '../helpers/storage'; -import browser from 'bowser'; +import bowser from 'bowser'; //============================================================================== // NETWORK INTERFACE @@ -23,7 +23,7 @@ networkInterface.use([{ req.options.headers = {}; // Create the header object if needed. } - if (!browser || browser.name !== 'Safari') { + if (!bowser.safari && !bowser.ios) { req.options.headers['authorization'] = `Bearer ${Storage.getItem('token')}`; } From 6a9f216c0f98dd404e744d8c75e6ed6f5390acd8 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 26 May 2017 20:58:48 +0700 Subject: [PATCH 26/36] Detect mobile & desktop safari server side --- services/passport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/passport.js b/services/passport.js index 719086f89..f3eb0da83 100644 --- a/services/passport.js +++ b/services/passport.js @@ -51,7 +51,7 @@ const HandleGenerateCredentials = (req, res, next) => (err, user) => { // If the user is Safari, let's send a cookie const browser = bowser._detect(req.headers['user-agent']); - if (browser.name === 'Safari') { + if (browser.ios || browser.safari) { res.cookie('authorization', token, { httpOnly: true, expires: new Date(Date.now() + 900000) From d4569b5f518d5e029cd1f0ffdc4f3d40bed58303 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 26 May 2017 21:37:11 +0700 Subject: [PATCH 27/36] Set cookie for facebook login on safari --- services/passport.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/services/passport.js b/services/passport.js index f3eb0da83..4f5a8fb8d 100644 --- a/services/passport.js +++ b/services/passport.js @@ -33,6 +33,17 @@ const GenerateToken = (user) => JWT.sign({}, JWT_SECRET, { audience: JWT_AUDIENCE }); +// SetTokenForSafari sends the token in a cookie for Safari clients. +const SetTokenForSafari = (req, res, token) => { + const browser = bowser._detect(req.headers['user-agent']); + if (browser.ios || browser.safari) { + res.cookie('authorization', token, { + httpOnly: true, + expires: new Date(Date.now() + 900000) + }); + } +}; + // HandleGenerateCredentials validates that an authentication scheme did indeed // return a user, if it did, then sign and return the user and token to be used // by the frontend to display and update the UI. @@ -48,15 +59,7 @@ const HandleGenerateCredentials = (req, res, next) => (err, user) => { // Generate the token to re-issue to the frontend. const token = GenerateToken(user); - // If the user is Safari, let's send a cookie - const browser = bowser._detect(req.headers['user-agent']); - - if (browser.ios || browser.safari) { - res.cookie('authorization', token, { - httpOnly: true, - expires: new Date(Date.now() + 900000) - }); - } + SetTokenForSafari(req, res, token); // Send back the details! res.json({user, token}); @@ -77,6 +80,8 @@ const HandleAuthPopupCallback = (req, res, next) => (err, user) => { // Generate the token to re-issue to the frontend. const token = GenerateToken(user); + SetTokenForSafari(req, res, token); + // We logged in the user! Let's send back the user data. res.render('auth-callback', {auth: JSON.stringify({err: null, data: {user, token}})}); }; From 7b6b46f3e5551433683ec972832d8f438dafb07b Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 26 May 2017 21:38:29 +0700 Subject: [PATCH 28/36] Sync username with store --- .../client/components/ChangeUsername.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/coral-plugin-auth/client/components/ChangeUsername.js b/plugins/coral-plugin-auth/client/components/ChangeUsername.js index 761fe786d..cbb7adba5 100644 --- a/plugins/coral-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/coral-plugin-auth/client/components/ChangeUsername.js @@ -30,6 +30,16 @@ class ChangeUsernameContainer extends React.Component { }; } + componentWillReceiveProps(next) { + if (!this.props.auth.showCreateUsernameDialog && next.auth.showCreateUsernameDialog) { + this.setState({ + formData: { + username: (this.props.auth.user && this.props.auth.user.username) || '', + }, + }); + } + } + handleChange = e => { const {name, value} = e.target; this.setState( From 82c5d140bef2b01c335be99f74a2327e7ef23c56 Mon Sep 17 00:00:00 2001 From: Andrew Losowsky Date: Fri, 26 May 2017 12:30:26 -0400 Subject: [PATCH 29/36] added iphone 7 support in the list --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 718847d9e..ffb54a4fd 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ alternative methods of loading configuration during development. - iPad - iPad Pro +- iPhone 7 Plus +- iPhone 7 - iPhone 6 Plus - iPhone 6 - iPhone 5 From 99a9154d4053a607909b613a040e8a714e901bf9 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Sat, 27 May 2017 00:26:04 +0700 Subject: [PATCH 30/36] Remove unused dependency --- package.json | 1 - yarn.lock | 4 ---- 2 files changed, 5 deletions(-) diff --git a/package.json b/package.json index b1eb180ed..11634fa8d 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,6 @@ "csurf": "^1.9.0", "dataloader": "^1.3.0", "debug": "^2.6.3", - "detect-browser": "^1.7.0", "dotenv": "^4.0.0", "ejs": "^2.5.6", "env-rewrite": "^1.0.2", diff --git a/yarn.lock b/yarn.lock index cc1ddd018..3d01f098e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2422,10 +2422,6 @@ destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" -detect-browser@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-1.7.0.tgz#11758cd6aa07d76c25784036d19154ae0392c3b3" - detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" From a7cdcb0bf7f5d6d8918da9c71317886b23e7f3f9 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Sat, 27 May 2017 00:54:36 +0700 Subject: [PATCH 31/36] Fix request options and use better filename --- client/coral-admin/src/actions/assets.js | 2 +- client/coral-admin/src/actions/auth.js | 2 +- client/coral-admin/src/actions/community.js | 2 +- client/coral-admin/src/actions/install.js | 2 +- client/coral-admin/src/actions/settings.js | 2 +- client/coral-admin/src/actions/users.js | 2 +- client/coral-framework/actions/asset.js | 2 +- client/coral-framework/actions/auth.js | 2 +- client/coral-framework/actions/user.js | 2 +- .../helpers/{response.js => request.js} | 13 +++++-------- 10 files changed, 14 insertions(+), 17 deletions(-) rename client/coral-framework/helpers/{response.js => request.js} (82%) diff --git a/client/coral-admin/src/actions/assets.js b/client/coral-admin/src/actions/assets.js index f5c2f848a..8a18a8e3f 100644 --- a/client/coral-admin/src/actions/assets.js +++ b/client/coral-admin/src/actions/assets.js @@ -8,7 +8,7 @@ import { UPDATE_ASSETS } from '../constants/assets'; -import coralApi from '../../../coral-framework/helpers/response'; +import coralApi from '../../../coral-framework/helpers/request'; /** * Action disptacher related to assets diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 69e7d4303..57871b79d 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,6 +1,6 @@ import bowser from 'bowser'; import * as actions from '../constants/auth'; -import coralApi from 'coral-framework/helpers/response'; +import coralApi from 'coral-framework/helpers/request'; import * as Storage from 'coral-framework/helpers/storage'; import {handleAuthToken} from 'coral-framework/actions/auth'; diff --git a/client/coral-admin/src/actions/community.js b/client/coral-admin/src/actions/community.js index 9a8743762..36b9ffb0a 100644 --- a/client/coral-admin/src/actions/community.js +++ b/client/coral-admin/src/actions/community.js @@ -14,7 +14,7 @@ import { HIDE_SUSPENDUSER_DIALOG } from '../constants/community'; -import coralApi from '../../../coral-framework/helpers/response'; +import coralApi from '../../../coral-framework/helpers/request'; export const fetchAccounts = (query = {}) => (dispatch) => { diff --git a/client/coral-admin/src/actions/install.js b/client/coral-admin/src/actions/install.js index 21ff58de1..15413e220 100644 --- a/client/coral-admin/src/actions/install.js +++ b/client/coral-admin/src/actions/install.js @@ -1,4 +1,4 @@ -import coralApi from 'coral-framework/helpers/response'; +import coralApi from 'coral-framework/helpers/request'; import * as actions from '../constants/install'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; diff --git a/client/coral-admin/src/actions/settings.js b/client/coral-admin/src/actions/settings.js index b0530e77e..65c200420 100644 --- a/client/coral-admin/src/actions/settings.js +++ b/client/coral-admin/src/actions/settings.js @@ -1,4 +1,4 @@ -import coralApi from '../../../coral-framework/helpers/response'; +import coralApi from '../../../coral-framework/helpers/request'; export const SETTINGS_LOADING = 'SETTINGS_LOADING'; export const SETTINGS_RECEIVED = 'SETTINGS_RECEIVED'; diff --git a/client/coral-admin/src/actions/users.js b/client/coral-admin/src/actions/users.js index 2642db90d..e888d5b74 100644 --- a/client/coral-admin/src/actions/users.js +++ b/client/coral-admin/src/actions/users.js @@ -1,4 +1,4 @@ -import coralApi from '../../../coral-framework/helpers/response'; +import coralApi from '../../../coral-framework/helpers/request'; import * as userTypes from '../constants/users'; /** diff --git a/client/coral-framework/actions/asset.js b/client/coral-framework/actions/asset.js index 129cd1c3c..9c0081470 100644 --- a/client/coral-framework/actions/asset.js +++ b/client/coral-framework/actions/asset.js @@ -1,5 +1,5 @@ import * as actions from '../constants/asset'; -import coralApi from '../helpers/response'; +import coralApi from '../helpers/request'; import {addNotification} from '../actions/notification'; import I18n from 'coral-framework/modules/i18n/i18n'; diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 2deda5f1d..f714f1fac 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -3,7 +3,7 @@ import {pym} from 'coral-framework'; import bowser from 'bowser'; import * as actions from '../constants/auth'; import * as Storage from '../helpers/storage'; -import coralApi, {base} from '../helpers/response'; +import coralApi, {base} from '../helpers/request'; const lang = new I18n(translations); import translations from './../translations'; diff --git a/client/coral-framework/actions/user.js b/client/coral-framework/actions/user.js index 910fe0865..95d4116a6 100644 --- a/client/coral-framework/actions/user.js +++ b/client/coral-framework/actions/user.js @@ -1,5 +1,5 @@ import {addNotification} from '../actions/notification'; -import coralApi from '../helpers/response'; +import coralApi from '../helpers/request'; import * as actions from '../constants/auth'; import I18n from 'coral-framework/modules/i18n/i18n'; diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/request.js similarity index 82% rename from client/coral-framework/helpers/response.js rename to client/coral-framework/helpers/request.js index ac6e53cf9..0e15003e1 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/request.js @@ -1,4 +1,6 @@ import bowser from 'bowser'; +import * as Storage from './storage'; +import merge from 'lodash/merge'; const buildOptions = (inputOptions = {}) => { const defaultOptions = { @@ -10,18 +12,13 @@ const buildOptions = (inputOptions = {}) => { credentials: 'same-origin' }; - let options = { - ...defaultOptions, - ...inputOptions - }; + let options = merge({}, defaultOptions, inputOptions); if (!bowser.safari && !bowser.ios) { - let authorization = localStorage.getItem('token'); + let authorization = Storage.getItem('token'); if (authorization) { - options.headers = { - Authorization: `Bearer ${authorization}` - }; + options.headers.Authorization = `Bearer ${authorization}`; } } From 52b3dcab43d0f8c48ac5e542996c5c8ab6069f5a Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Sat, 27 May 2017 01:05:12 +0700 Subject: [PATCH 32/36] Fix changing username not updating --- plugins/coral-plugin-auth/client/components/UserBox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/coral-plugin-auth/client/components/UserBox.js b/plugins/coral-plugin-auth/client/components/UserBox.js index a4a0e1c99..d8adf2380 100644 --- a/plugins/coral-plugin-auth/client/components/UserBox.js +++ b/plugins/coral-plugin-auth/client/components/UserBox.js @@ -25,7 +25,7 @@ const UserBox = ({loggedIn, user, logout, onShowProfile}) => ( const mapStateToProps = ({auth, user}) => ({ loggedIn: auth.toJS().loggedIn, - user: user.toJS() + user: auth.toJS().user }); const mapDispatchToProps = dispatch => From 54e7956af589341364d4c6bb09f731e4fd3ffaf3 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Fri, 26 May 2017 15:08:47 -0400 Subject: [PATCH 33/36] Update default plugins that ship with Coral core --- plugins.default.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins.default.json b/plugins.default.json index b3443af48..3f64a383b 100644 --- a/plugins.default.json +++ b/plugins.default.json @@ -1,9 +1,13 @@ { "server": [ "coral-plugin-respect", - "coral-plugin-facebook-auth" + "coral-plugin-like", + "coral-plugin-facebook-auth", + "coral-plugin-auth" ], "client": [ - "coral-plugin-respect" + "coral-plugin-respect", + "coral-plugin-like", + "coral-plugin-auth" ] } From 8713a2ae875493a45f1dfe1068d88baf3eadcfa4 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Sat, 27 May 2017 02:08:54 +0700 Subject: [PATCH 34/36] Enable Linting --- .eslintignore | 5 ++++ .../client/components/ChangeUsername.js | 14 +++++----- .../client/components/FakeComment.js | 3 ++- .../client/components/ForgotContent.js | 4 +-- .../client/components/SignInButton.js | 2 +- .../client/components/SignInContainer.js | 27 ++++++++++--------- .../client/components/SignUpContent.js | 2 +- .../client/components/UserBox.js | 6 ++--- plugins/coral-plugin-auth/client/index.js | 3 ++- plugins/coral-plugin-auth/index.js | 3 ++- .../client/components/LikeButton.js | 17 ++++++------ .../client/containers/LikeButton.js | 27 ++++++++++--------- .../coral-plugin-love/client/LoveButton.js | 2 +- plugins/coral-plugin-love/index.js | 8 +++--- .../coral-plugin-mod/client/components/Box.js | 5 ++-- .../client/components/Container.js | 6 ++--- plugins/coral-plugin-mod/index.js | 4 +-- .../client/components/OffTopicCheckbox.js | 7 +++-- .../client/components/OffTopicTag.js | 4 +-- 19 files changed, 78 insertions(+), 71 deletions(-) diff --git a/.eslintignore b/.eslintignore index fc0d50a25..96e49da53 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,5 +3,10 @@ client/lib **/*.html plugins/* !plugins/coral-plugin-facebook-auth +!plugins/coral-plugin-auth !plugins/coral-plugin-respect +!plugins/coral-plugin-offtopic +!plugins/coral-plugin-like +!plugins/coral-plugin-mod +!plugins/coral-plugin-love node_modules diff --git a/plugins/coral-plugin-auth/client/components/ChangeUsername.js b/plugins/coral-plugin-auth/client/components/ChangeUsername.js index cbb7adba5..ee02b2e17 100644 --- a/plugins/coral-plugin-auth/client/components/ChangeUsername.js +++ b/plugins/coral-plugin-auth/client/components/ChangeUsername.js @@ -40,10 +40,10 @@ class ChangeUsernameContainer extends React.Component { } } - handleChange = e => { + handleChange = (e) => { const {name, value} = e.target; this.setState( - state => ({ + (state) => ({ ...state, formData: { ...state.formData, @@ -57,7 +57,7 @@ class ChangeUsernameContainer extends React.Component { }; addError = (name, error) => { - return this.setState(state => ({ + return this.setState((state) => ({ errors: { ...state.errors, [name]: error @@ -75,20 +75,20 @@ class ChangeUsernameContainer extends React.Component { } else { const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line // Removes Error - this.setState(state => ({...state, errors})); + this.setState((state) => ({...state, errors})); } }; isCompleted = () => { const {formData} = this.state; - return !Object.keys(formData).filter(prop => !formData[prop].length).length; + return !Object.keys(formData).filter((prop) => !formData[prop].length).length; }; displayErrors = (show = true) => { this.setState({showErrors: show}); }; - handleSubmitUsername = e => { + handleSubmitUsername = (e) => { e.preventDefault(); const {errors} = this.state; const {validForm, invalidForm} = this.props; @@ -127,7 +127,7 @@ const mapStateToProps = ({auth}) => ({ auth: auth.toJS() }); -const mapDispatchToProps = dispatch => +const mapDispatchToProps = (dispatch) => bindActionCreators( { createUsername, diff --git a/plugins/coral-plugin-auth/client/components/FakeComment.js b/plugins/coral-plugin-auth/client/components/FakeComment.js index 01cc6863e..349e7d0a4 100644 --- a/plugins/coral-plugin-auth/client/components/FakeComment.js +++ b/plugins/coral-plugin-auth/client/components/FakeComment.js @@ -69,4 +69,5 @@ export const FakeComment = ({username, created_at, body}) => (
-); \ No newline at end of file +); + diff --git a/plugins/coral-plugin-auth/client/components/ForgotContent.js b/plugins/coral-plugin-auth/client/components/ForgotContent.js index 2099330bc..8bd6b27a6 100644 --- a/plugins/coral-plugin-auth/client/components/ForgotContent.js +++ b/plugins/coral-plugin-auth/client/components/ForgotContent.js @@ -7,7 +7,7 @@ import I18n from 'coral-framework/modules/i18n/i18n'; const lang = new I18n(translations); class ForgotContent extends React.Component { - handleSubmit = e => { + handleSubmit = (e) => { e.preventDefault(); this.props.fetchForgotPassword(this.emailInput.value); }; @@ -25,7 +25,7 @@ class ForgotContent extends React.Component {
(this.emailInput = input)} + ref={(input) => (this.emailInput = input)} type="text" style={{fontSize: 16}} id="email" diff --git a/plugins/coral-plugin-auth/client/components/SignInButton.js b/plugins/coral-plugin-auth/client/components/SignInButton.js index b54cbfedd..881233c83 100644 --- a/plugins/coral-plugin-auth/client/components/SignInButton.js +++ b/plugins/coral-plugin-auth/client/components/SignInButton.js @@ -18,7 +18,7 @@ const mapStateToProps = ({auth}) => ({ loggedIn: auth.toJS().loggedIn }); -const mapDispatchToProps = dispatch => +const mapDispatchToProps = (dispatch) => bindActionCreators({showSignInDialog}, dispatch); export default connect(mapStateToProps, mapDispatchToProps)(SignInButton); diff --git a/plugins/coral-plugin-auth/client/components/SignInContainer.js b/plugins/coral-plugin-auth/client/components/SignInContainer.js index cbff000ee..523f343ed 100644 --- a/plugins/coral-plugin-auth/client/components/SignInContainer.js +++ b/plugins/coral-plugin-auth/client/components/SignInContainer.js @@ -61,7 +61,8 @@ class SignInContainer extends React.Component { window.removeEventListener('storage', this.handleAuth); } - handleAuth = e => { + handleAuth = (e) => { + // Listening to FB changes // FB localStorage key is 'auth' const authCallback = this.props.facebookCallback; @@ -72,10 +73,10 @@ class SignInContainer extends React.Component { } }; - handleChange = e => { + handleChange = (e) => { const {name, value} = e.target; this.setState( - state => ({ + (state) => ({ ...state, formData: { ...state.formData, @@ -88,12 +89,12 @@ class SignInContainer extends React.Component { ); }; - handleChangeEmail = e => { + handleChangeEmail = (e) => { const {value} = e.target; this.setState({emailToBeResent: value}); }; - handleResendVerification = e => { + handleResendVerification = (e) => { e.preventDefault(); this.props .requestConfirmEmail( @@ -102,6 +103,7 @@ class SignInContainer extends React.Component { ) .then(() => { setTimeout(() => { + // allow success UI to be shown for a second, and then close the modal this.props.hideSignInDialog(); }, 2500); @@ -109,7 +111,7 @@ class SignInContainer extends React.Component { }; addError = (name, error) => { - return this.setState(state => ({ + return this.setState((state) => ({ errors: { ...state.errors, [name]: error @@ -133,20 +135,20 @@ class SignInContainer extends React.Component { } else { const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line // Removes Error - this.setState(state => ({...state, errors})); + this.setState((state) => ({...state, errors})); } }; isCompleted = () => { const {formData} = this.state; - return !Object.keys(formData).filter(prop => !formData[prop].length).length; + return !Object.keys(formData).filter((prop) => !formData[prop].length).length; }; displayErrors = (show = true) => { this.setState({showErrors: show}); }; - handleSignUp = e => { + handleSignUp = (e) => { e.preventDefault(); const {errors} = this.state; const {fetchSignUp, validForm, invalidForm} = this.props; @@ -159,7 +161,7 @@ class SignInContainer extends React.Component { } }; - handleSignIn = e => { + handleSignIn = (e) => { e.preventDefault(); this.props.fetchSignIn(this.state.formData); }; @@ -183,17 +185,16 @@ class SignInContainer extends React.Component { } } -const mapStateToProps = state => ({ +const mapStateToProps = (state) => ({ auth: state.auth.toJS() }); -const mapDispatchToProps = dispatch => +const mapDispatchToProps = (dispatch) => bindActionCreators( { checkLogin, facebookCallback, fetchSignUp, - fetchSignUp, fetchSignIn, fetchSignInFacebook, fetchSignUpFacebook, diff --git a/plugins/coral-plugin-auth/client/components/SignUpContent.js b/plugins/coral-plugin-auth/client/components/SignUpContent.js index 5f2dd36ea..fd885d1fe 100644 --- a/plugins/coral-plugin-auth/client/components/SignUpContent.js +++ b/plugins/coral-plugin-auth/client/components/SignUpContent.js @@ -1,5 +1,5 @@ import styles from './styles.css'; -import React, {PropTypes} from 'react'; +import React from 'react'; import translations from '../translations'; import I18n from 'coral-framework/modules/i18n/i18n'; import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; diff --git a/plugins/coral-plugin-auth/client/components/UserBox.js b/plugins/coral-plugin-auth/client/components/UserBox.js index d8adf2380..cfd0fc9d2 100644 --- a/plugins/coral-plugin-auth/client/components/UserBox.js +++ b/plugins/coral-plugin-auth/client/components/UserBox.js @@ -4,7 +4,7 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import translations from '../translations'; import I18n from 'coral-framework/modules/i18n/i18n'; -import {showSignInDialog, logout} from 'coral-framework/actions/auth'; +import {logout} from 'coral-framework/actions/auth'; const lang = new I18n(translations); const UserBox = ({loggedIn, user, logout, onShowProfile}) => ( @@ -23,12 +23,12 @@ const UserBox = ({loggedIn, user, logout, onShowProfile}) => (
); -const mapStateToProps = ({auth, user}) => ({ +const mapStateToProps = ({auth}) => ({ loggedIn: auth.toJS().loggedIn, user: auth.toJS().user }); -const mapDispatchToProps = dispatch => +const mapDispatchToProps = (dispatch) => bindActionCreators({logout}, dispatch); export default connect(mapStateToProps, mapDispatchToProps)(UserBox); diff --git a/plugins/coral-plugin-auth/client/index.js b/plugins/coral-plugin-auth/client/index.js index 41fa3adbe..c41c097bd 100644 --- a/plugins/coral-plugin-auth/client/index.js +++ b/plugins/coral-plugin-auth/client/index.js @@ -8,4 +8,5 @@ export default { stream: [UserBox, SignInButton, ChangeUserNameContainer], login: [SignInContainer] } -}; \ No newline at end of file +}; + diff --git a/plugins/coral-plugin-auth/index.js b/plugins/coral-plugin-auth/index.js index a09954537..85dfb349b 100644 --- a/plugins/coral-plugin-auth/index.js +++ b/plugins/coral-plugin-auth/index.js @@ -1 +1,2 @@ -module.exports = {}; \ No newline at end of file +module.exports = {}; + diff --git a/plugins/coral-plugin-like/client/components/LikeButton.js b/plugins/coral-plugin-like/client/components/LikeButton.js index b91ffd42a..0a88d35a4 100644 --- a/plugins/coral-plugin-like/client/components/LikeButton.js +++ b/plugins/coral-plugin-like/client/components/LikeButton.js @@ -1,19 +1,18 @@ -import React, { Component } from 'react'; +import React, {Component} from 'react'; import styles from './style.css'; -import Icon from './Icon'; -import { I18n } from 'coral-framework'; +import {I18n} from 'coral-framework'; import cn from 'classnames'; import translations from '../translations.json'; -import { getMyActionSummary, getTotalActionCount } from 'coral-framework/utils'; +import {getMyActionSummary, getTotalActionCount} from 'coral-framework/utils'; const lang = new I18n(translations); const name = 'coral-plugin-like'; class LikeButton extends Component { handleClick = () => { - const { postLike, showSignInDialog, deleteAction } = this.props; - const { root: { me }, comment } = this.props; + const {postLike, showSignInDialog, deleteAction} = this.props; + const {root: {me}, comment} = this.props; const myLikeActionSummary = getMyActionSummary( 'LikeActionSummary', @@ -42,7 +41,7 @@ class LikeButton extends Component { }; render() { - const { comment } = this.props; + const {comment} = this.props; if (!comment) { return null; @@ -56,7 +55,7 @@ class LikeButton extends Component {