From e2273f581038aca6a1a28c42da8b1619e9a51e7f Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 28 Feb 2017 14:32:01 -0700 Subject: [PATCH 01/21] change PermissionRequired to LoginView and create a login form. delete old login page --- client/coral-admin/src/actions/auth.js | 13 ++ .../coral-admin/src/components/LoginView.js | 49 +++++++ .../coral-admin/src/components/NotFound.css | 10 +- .../src/components/PermissionRequired.js | 13 -- .../coral-admin/src/components/ui/Drawer.js | 10 +- .../coral-admin/src/components/ui/Header.js | 11 +- .../coral-admin/src/components/ui/Layout.js | 17 ++- client/coral-admin/src/constants/auth.js | 4 + .../containers/Install/InstallContainer.js | 2 +- .../src/containers/LayoutContainer.js | 20 +-- routes/admin/index.js | 4 - views/admin/login.ejs | 132 ------------------ 12 files changed, 109 insertions(+), 176 deletions(-) create mode 100644 client/coral-admin/src/components/LoginView.js delete mode 100644 client/coral-admin/src/components/PermissionRequired.js delete mode 100644 views/admin/login.ejs diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index c2f3a8056..0eb17f74c 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,6 +1,19 @@ import * as actions from '../constants/auth'; import coralApi from '../../../coral-framework/helpers/response'; +// Log In. +export const handleLogin = (email, password) => dispatch => { + dispatch({type: actions.LOGIN_REQUEST}); + return coralApi('/auth/local', {method: 'POST', body: {email, password}}) + .then(result => { + const isAdmin = !!result.user.roles.filter(i => i === 'ADMIN').length; + dispatch(checkLoginSuccess(result.user, isAdmin)); + }) + .catch(error => { + console.error(error); + }); +}; + // Check Login const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST}); diff --git a/client/coral-admin/src/components/LoginView.js b/client/coral-admin/src/components/LoginView.js new file mode 100644 index 000000000..e9b740683 --- /dev/null +++ b/client/coral-admin/src/components/LoginView.js @@ -0,0 +1,49 @@ +import React, {PropTypes} from 'react'; +import Layout from 'coral-admin/src/components/ui/Layout'; +import styles from './NotFound.css'; +import {Button, TextField} from 'coral-ui'; + +class LoginView extends React.Component { + + constructor (props) { + super(props); + this.state = {email: '', password: ''}; + } + + handleSignIn = e => { + e.preventDefault(); + this.props.handleLogin(this.state.email, this.state.password); + } + + render () { + return ( + +
+

Permission Required

+

Sign in to interact with your community.

+
+ this.setState({email: e.target.value})} /> + this.setState({password: e.target.value})} + type='password' /> + + +
+
+ ); + } +} + +LoginView.propTypes = { + handleLogin: PropTypes.func.isRequired +}; + +export default LoginView; diff --git a/client/coral-admin/src/components/NotFound.css b/client/coral-admin/src/components/NotFound.css index fc9aedc6b..e0e04e0fd 100644 --- a/client/coral-admin/src/components/NotFound.css +++ b/client/coral-admin/src/components/NotFound.css @@ -1,12 +1,8 @@ .layout { - max-width: 800px; - margin: 0 auto; + max-width: 400px; + margin: 0 auto; } .layout h1 { - font-size: 40px; -} - -.layout img { - width: 100%; + font-size: 40px; } diff --git a/client/coral-admin/src/components/PermissionRequired.js b/client/coral-admin/src/components/PermissionRequired.js deleted file mode 100644 index c61ab1cef..000000000 --- a/client/coral-admin/src/components/PermissionRequired.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import {Layout} from 'react-mdl'; -import styles from './NotFound.css'; - -export const PermissionRequired = () => ( - -
-

Permission Required

-

We’re sorry, but you don’t have access to that page.

- Communicorn -
-
-); diff --git a/client/coral-admin/src/components/ui/Drawer.js b/client/coral-admin/src/components/ui/Drawer.js index 8fdf4f19d..9af651f3b 100644 --- a/client/coral-admin/src/components/ui/Drawer.js +++ b/client/coral-admin/src/components/ui/Drawer.js @@ -1,11 +1,11 @@ -import React from 'react'; +import React, {PropTypes} from 'react'; import {Navigation, Drawer} from 'react-mdl'; import {IndexLink, Link} from 'react-router'; import styles from './Drawer.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../../translations.json'; -export default ({handleLogout, restricted = false}) => ( +const CoralDrawer = ({handleLogout, restricted = false}) => ( { !restricted ?
@@ -45,5 +45,11 @@ export default ({handleLogout, restricted = false}) => ( ); +CoralDrawer.propTypes = { + handleLogout: PropTypes.func.isRequired, + restricted: PropTypes.bool // hide app elements from a logged out user +}; + const lang = new I18n(translations); +export default CoralDrawer; diff --git a/client/coral-admin/src/components/ui/Header.js b/client/coral-admin/src/components/ui/Header.js index 556b33b6c..4a2314926 100644 --- a/client/coral-admin/src/components/ui/Header.js +++ b/client/coral-admin/src/components/ui/Header.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {PropTypes} from 'react'; import {Navigation, Header, IconButton, MenuItem, Menu} from 'react-mdl'; import {Link, IndexLink} from 'react-router'; import styles from './Header.css'; @@ -6,7 +6,7 @@ import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../../translations.json'; import {Logo} from './Logo'; -export default ({handleLogout, restricted = false}) => ( +const CoralHeader = ({handleLogout, restricted = false}) => (
{ @@ -64,4 +64,11 @@ export default ({handleLogout, restricted = false}) => (
); +CoralHeader.propTypes = { + handleLogout: PropTypes.func.isRequired, + restricted: PropTypes.bool // hide elemnts from a user that's logged out +}; + const lang = new I18n(translations); + +export default CoralHeader; diff --git a/client/coral-admin/src/components/ui/Layout.js b/client/coral-admin/src/components/ui/Layout.js index f28e8dd80..c8b5bf57a 100644 --- a/client/coral-admin/src/components/ui/Layout.js +++ b/client/coral-admin/src/components/ui/Layout.js @@ -1,15 +1,22 @@ -import React from 'react'; +import React, {PropTypes} from 'react'; import {Layout as LayoutMDL} from 'react-mdl'; import Header from './Header'; import Drawer from './Drawer'; import styles from './Layout.css'; -export const Layout = ({children, ...props}) => ( +const Layout = ({children, handleLogout = () => {}, restricted = false, ...props}) => ( -
- -
+
+ +
{children}
); + +Layout.propTypes = { + handleLogout: PropTypes.func, + restricted: PropTypes.bool // hide elements from a user that's logged out +}; + +export default Layout; diff --git a/client/coral-admin/src/constants/auth.js b/client/coral-admin/src/constants/auth.js index f77deb670..88a9c4a3f 100644 --- a/client/coral-admin/src/constants/auth.js +++ b/client/coral-admin/src/constants/auth.js @@ -7,3 +7,7 @@ export const CHECK_CSRF_TOKEN = 'CHECK_CSRF_TOKEN'; export const LOGOUT_REQUEST = 'LOGOUT_REQUEST'; export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'; export const LOGOUT_FAILURE = 'LOGOUT_FAILURE'; + +export const LOGIN_REQUEST = 'LOGIN_REQUEST'; +export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; +export const LOGIN_FAILURE = 'LOGIN_FAILURE'; diff --git a/client/coral-admin/src/containers/Install/InstallContainer.js b/client/coral-admin/src/containers/Install/InstallContainer.js index 7a8634180..123a1493b 100644 --- a/client/coral-admin/src/containers/Install/InstallContainer.js +++ b/client/coral-admin/src/containers/Install/InstallContainer.js @@ -2,7 +2,7 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; import styles from './style.css'; import {Wizard, WizardNav} from 'coral-ui'; -import {Layout} from '../../components/ui/Layout'; +import Layout from 'coral-admin/src/components/ui/Layout'; import { nextStep, diff --git a/client/coral-admin/src/containers/LayoutContainer.js b/client/coral-admin/src/containers/LayoutContainer.js index 5ce208503..ce3c7d1bf 100644 --- a/client/coral-admin/src/containers/LayoutContainer.js +++ b/client/coral-admin/src/containers/LayoutContainer.js @@ -1,24 +1,23 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; -import {Layout} from '../components/ui/Layout'; -import {checkLogin, logout} from '../actions/auth'; +import Layout from '../components/ui/Layout'; +import {checkLogin, handleLogin, logout} from '../actions/auth'; import {FullLoading} from '../components/FullLoading'; -import {PermissionRequired} from '../components/PermissionRequired'; +import LoginView from '../components/LoginView'; class LayoutContainer extends Component { componentWillMount () { const {checkLogin} = this.props; - checkLogin().then(() => { - if (!this.props.auth.isAdmin) { - location.href = '/admin/login'; - } - }); + checkLogin(); } render () { const {isAdmin, loggedIn, loadingUser} = this.props.auth; + const {handleLogout} = this.props; if (loadingUser) { return ; } - if (!isAdmin) { return ; } - if (isAdmin && loggedIn) { return ; } + if (!isAdmin) { + return ; + } + if (isAdmin && loggedIn) { return ; } return ; } } @@ -29,6 +28,7 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ checkLogin: () => dispatch(checkLogin()), + handleLogin: (username, password) => dispatch(handleLogin(username, password)), handleLogout: () => dispatch(logout()) }); diff --git a/routes/admin/index.js b/routes/admin/index.js index a3699143e..e2473bca9 100644 --- a/routes/admin/index.js +++ b/routes/admin/index.js @@ -15,10 +15,6 @@ router.get('/password-reset', (req, res) => { res.render('password-reset', {redirectUri: process.env.TALK_ROOT_URL}); }); -router.get('/login', (req, res, next) => { - res.render('admin/login'); -}); - router.get('*', (req, res) => { res.render('admin', {basePath: '/client/coral-admin'}); }); diff --git a/views/admin/login.ejs b/views/admin/login.ejs deleted file mode 100644 index e88dd86fd..000000000 --- a/views/admin/login.ejs +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - Admin Login - - - - - - -
-
- Admin Login - - - - -
-
-
- - - - From bb1aea63baf7fa9fc58b4d20b0be43ddedc56b84 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 28 Feb 2017 14:33:57 -0700 Subject: [PATCH 02/21] add a couple of routes --- client/coral-admin/src/AppRouter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index d96bacfe0..a1ba32ea7 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -14,6 +14,8 @@ import Dashboard from 'containers/Dashboard/Dashboard'; const routes = (
+ + From b369fb910106f5314128df43f567387f8f1f50ae Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 28 Feb 2017 14:38:19 -0700 Subject: [PATCH 03/21] re-rename --- .../src/components/{LoginView.js => AdminLogin.js} | 6 +++--- client/coral-admin/src/containers/LayoutContainer.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename client/coral-admin/src/components/{LoginView.js => AdminLogin.js} (92%) diff --git a/client/coral-admin/src/components/LoginView.js b/client/coral-admin/src/components/AdminLogin.js similarity index 92% rename from client/coral-admin/src/components/LoginView.js rename to client/coral-admin/src/components/AdminLogin.js index e9b740683..b96a84031 100644 --- a/client/coral-admin/src/components/LoginView.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -3,7 +3,7 @@ import Layout from 'coral-admin/src/components/ui/Layout'; import styles from './NotFound.css'; import {Button, TextField} from 'coral-ui'; -class LoginView extends React.Component { +class AdminLogin extends React.Component { constructor (props) { super(props); @@ -42,8 +42,8 @@ class LoginView extends React.Component { } } -LoginView.propTypes = { +AdminLogin.propTypes = { handleLogin: PropTypes.func.isRequired }; -export default LoginView; +export default AdminLogin; diff --git a/client/coral-admin/src/containers/LayoutContainer.js b/client/coral-admin/src/containers/LayoutContainer.js index ce3c7d1bf..94ce98c55 100644 --- a/client/coral-admin/src/containers/LayoutContainer.js +++ b/client/coral-admin/src/containers/LayoutContainer.js @@ -3,7 +3,7 @@ import {connect} from 'react-redux'; import Layout from '../components/ui/Layout'; import {checkLogin, handleLogin, logout} from '../actions/auth'; import {FullLoading} from '../components/FullLoading'; -import LoginView from '../components/LoginView'; +import AdminLogin from '../components/AdminLogin'; class LayoutContainer extends Component { componentWillMount () { @@ -15,7 +15,7 @@ class LayoutContainer extends Component { const {handleLogout} = this.props; if (loadingUser) { return ; } if (!isAdmin) { - return ; + return ; } if (isAdmin && loggedIn) { return ; } return ; From 8f23ca678d93144cc86c3c7a46f8d1e66bb64c7a Mon Sep 17 00:00:00 2001 From: riley Date: Tue, 28 Feb 2017 16:30:05 -0700 Subject: [PATCH 04/21] add Alert component to coral-ui --- client/coral-admin/src/actions/auth.js | 4 ++-- client/coral-admin/src/components/AdminLogin.js | 10 ++++++++-- .../src/containers/LayoutContainer.js | 6 ++++-- client/coral-admin/src/reducers/auth.js | 7 ++++++- client/coral-admin/src/translations.json | 8 +++++++- .../components/CreateUsernameDialog.js | 3 +-- .../coral-sign-in/components/SignInContent.js | 3 +-- .../coral-sign-in/components/SignUpContent.js | 3 +-- client/coral-sign-in/components/styles.css | 17 ----------------- client/coral-ui/components/Alert.css | 16 ++++++++++++++++ .../components/Alert.js | 2 +- client/coral-ui/index.js | 1 + 12 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 client/coral-ui/components/Alert.css rename client/{coral-sign-in => coral-ui}/components/Alert.js (87%) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 0eb17f74c..66c063d00 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,5 +1,5 @@ import * as actions from '../constants/auth'; -import coralApi from '../../../coral-framework/helpers/response'; +import coralApi from 'coral-framework/helpers/response'; // Log In. export const handleLogin = (email, password) => dispatch => { @@ -10,7 +10,7 @@ export const handleLogin = (email, password) => dispatch => { dispatch(checkLoginSuccess(result.user, isAdmin)); }) .catch(error => { - console.error(error); + dispatch({type: actions.LOGIN_FAILURE, message: error.translation_key}); }); }; diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index b96a84031..1475ccce7 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -1,7 +1,10 @@ import React, {PropTypes} from 'react'; import Layout from 'coral-admin/src/components/ui/Layout'; import styles from './NotFound.css'; -import {Button, TextField} from 'coral-ui'; +import {Button, TextField, Alert} from 'coral-ui'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from '../translations'; +const lang = new I18n(translations); class AdminLogin extends React.Component { @@ -16,12 +19,14 @@ class AdminLogin extends React.Component { } render () { + const {errorMessage} = this.props; return (

Permission Required

Sign in to interact with your community.

+ {errorMessage && {lang.t(`errors.${errorMessage}`)}} ; } if (!isAdmin) { - return ; + return ; } if (isAdmin && loggedIn) { return ; } return ; diff --git a/client/coral-admin/src/reducers/auth.js b/client/coral-admin/src/reducers/auth.js index 095ef7aac..d2f178773 100644 --- a/client/coral-admin/src/reducers/auth.js +++ b/client/coral-admin/src/reducers/auth.js @@ -4,7 +4,8 @@ import * as actions from '../constants/auth'; const initialState = Map({ loggedIn: false, user: null, - isAdmin: false + isAdmin: false, + loginError: null }); export default function auth (state = initialState, action) { @@ -25,6 +26,10 @@ export default function auth (state = initialState, action) { .set('user', action.user); case actions.LOGOUT_SUCCESS: return initialState; + case actions.LOGIN_REQUEST: + return state.set('loginError', null); + case actions.LOGIN_FAILURE: + return state.set('loginError', action.message); default : return state; } diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index 7219a22ca..0fbd09011 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -1,5 +1,8 @@ { "en": { + "errors": { + "NOT_AUTHORIZED": "Your username or password is not recognized by our system." + }, "community": { "username_and_email": "Username and Email", "account_creation_date": "Account Creation Date", @@ -132,6 +135,9 @@ } }, "es": { + "errors": { + "NOT_AUTHORIZED": "Acción no autorizada." + }, "community": { "username_and_email": "Usuario y E-mail", "account_creation_date": "Fecha de creación de la cuenta", @@ -213,7 +219,7 @@ }, "bandialog": { "ban_user": "Quieres suspender el Usuario?", - "are_you_sure": "Estas segura que quieres suspender a {props.author.username}?", + "are_you_sure": "Estas segura que quieres suspender a {0}?", "note": "Nota: Suspender este usuario también va a colocar este comentario en la cola de Rechazados.", "cancel": "Cancelar", "yes_ban_user": "Si, Suspendan el usuario" diff --git a/client/coral-sign-in/components/CreateUsernameDialog.js b/client/coral-sign-in/components/CreateUsernameDialog.js index d0e348046..4a7a99b81 100644 --- a/client/coral-sign-in/components/CreateUsernameDialog.js +++ b/client/coral-sign-in/components/CreateUsernameDialog.js @@ -1,8 +1,7 @@ import React from 'react'; import TextField from 'coral-ui/components/TextField'; -import Alert from './Alert'; import Button from 'coral-ui/components/Button'; -import {Dialog} from 'coral-ui'; +import {Dialog, Alert} from 'coral-ui'; import FakeComment from './FakeComment'; import styles from './styles.css'; diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js index 1f339979b..a0ed5b5b4 100644 --- a/client/coral-sign-in/components/SignInContent.js +++ b/client/coral-sign-in/components/SignInContent.js @@ -1,6 +1,5 @@ import React, {PropTypes} from 'react'; -import Alert from './Alert'; -import {Button, TextField, Spinner, Success} from 'coral-ui'; +import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index 6a781675b..c1e1d36cc 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -1,6 +1,5 @@ import React, {PropTypes} from 'react'; -import Alert from './Alert'; -import {Button, TextField, Spinner, Success} from 'coral-ui'; +import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; diff --git a/client/coral-sign-in/components/styles.css b/client/coral-sign-in/components/styles.css index 31d4a4fed..d3cd47b87 100644 --- a/client/coral-sign-in/components/styles.css +++ b/client/coral-sign-in/components/styles.css @@ -65,23 +65,6 @@ input.error{ padding: 3px 0 16px; } -.alert { - padding: 10px; - margin-bottom: 20px; - border-radius: 2px; -} - -.alert--success { - border: solid 1px #1ec00e; - background: #cbf1b8; - color: #006900; -} - -.alert--error { - background: #FFEBEE; - color: #B71C1C; -} - .userBox { padding: 10px 0 20px; letter-spacing: 0.1px; diff --git a/client/coral-ui/components/Alert.css b/client/coral-ui/components/Alert.css new file mode 100644 index 000000000..47b4787a1 --- /dev/null +++ b/client/coral-ui/components/Alert.css @@ -0,0 +1,16 @@ +.alert { + padding: 10px; + margin-bottom: 20px; + border-radius: 2px; +} + +.alert--success { + border: solid 1px #1ec00e; + background: #cbf1b8; + color: #006900; +} + +.alert--error { + background: #FFEBEE; + color: #B71C1C; +} diff --git a/client/coral-sign-in/components/Alert.js b/client/coral-ui/components/Alert.js similarity index 87% rename from client/coral-sign-in/components/Alert.js rename to client/coral-ui/components/Alert.js index 019c3456a..02f0524ff 100644 --- a/client/coral-sign-in/components/Alert.js +++ b/client/coral-ui/components/Alert.js @@ -1,5 +1,5 @@ import React from 'react'; -import styles from './styles.css'; +import styles from './Alert.css'; const Alert = ({cStyle = 'error', children, className, ...props}) => (
Date: Tue, 28 Feb 2017 17:10:51 -0700 Subject: [PATCH 05/21] add reset password link --- client/coral-admin/src/actions/auth.js | 11 ++++ .../coral-admin/src/components/AdminLogin.js | 63 ++++++++++++++----- .../coral-admin/src/components/NotFound.css | 7 +++ client/coral-admin/src/constants/auth.js | 4 ++ .../src/containers/LayoutContainer.js | 13 +++- client/coral-admin/src/reducers/auth.js | 7 ++- 6 files changed, 85 insertions(+), 20 deletions(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 66c063d00..4fd4f3c63 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -14,6 +14,17 @@ export const handleLogin = (email, password) => dispatch => { }); }; +const forgotPassowordRequest = () => ({type: actions.FETCH_FORGOT_PASSWORD_REQUEST}); +const forgotPassowordSuccess = () => ({type: actions.FETCH_FORGOT_PASSWORD_SUCCESS}); +const forgotPassowordFailure = () => ({type: actions.FETCH_FORGOT_PASSWORD_FAILURE}); + +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))); +}; + // Check Login const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST}); diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index 1475ccce7..cd9bac1d4 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -10,7 +10,7 @@ class AdminLogin extends React.Component { constructor (props) { super(props); - this.state = {email: '', password: ''}; + this.state = {email: '', password: '', requestPassword: false}; } handleSignIn = e => { @@ -18,29 +18,57 @@ class AdminLogin extends React.Component { this.props.handleLogin(this.state.email, this.state.password); } + handleRequestPassword = e => { + e.preventDefault(); + this.props.requestPasswordReset(this.state.email); + } + render () { const {errorMessage} = this.props; + const signInForm = ( + + {errorMessage && {lang.t(`errors.${errorMessage}`)}} + this.setState({email: e.target.value})} /> + this.setState({password: e.target.value})} + type='password' /> + +

+ Forgot your password? { + e.preventDefault(); + this.setState({requestPassword: true}); + }}>Request a new one. +

+ + ); + const requestPasswordForm = ( + this.props.passwordRequestSuccess + ?

{this.props.passwordRequestSuccess}

+ :
+ this.setState({email: e.target.value})} /> + + + ); return (

Permission Required

Sign in to interact with your community.

-
- {errorMessage && {lang.t(`errors.${errorMessage}`)}} - this.setState({email: e.target.value})} /> - this.setState({password: e.target.value})} - type='password' /> - - + { this.state.requestPassword ? requestPasswordForm : signInForm }
); @@ -49,6 +77,7 @@ class AdminLogin extends React.Component { AdminLogin.propTypes = { handleLogin: PropTypes.func.isRequired, + passwordRequestSuccess: PropTypes.string, loginError: PropTypes.string }; diff --git a/client/coral-admin/src/components/NotFound.css b/client/coral-admin/src/components/NotFound.css index e0e04e0fd..c45fbcc02 100644 --- a/client/coral-admin/src/components/NotFound.css +++ b/client/coral-admin/src/components/NotFound.css @@ -6,3 +6,10 @@ .layout h1 { font-size: 40px; } + +.passwordRequestSuccess { + padding: 8px 14px; + background: lightgreen; + border: 1px solid darkgreen; + border-radius: 4px; +} diff --git a/client/coral-admin/src/constants/auth.js b/client/coral-admin/src/constants/auth.js index 88a9c4a3f..3c47bfc45 100644 --- a/client/coral-admin/src/constants/auth.js +++ b/client/coral-admin/src/constants/auth.js @@ -11,3 +11,7 @@ export const LOGOUT_FAILURE = 'LOGOUT_FAILURE'; export const LOGIN_REQUEST = 'LOGIN_REQUEST'; export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; export const LOGIN_FAILURE = 'LOGIN_FAILURE'; + +export const FETCH_FORGOT_PASSWORD_REQUEST = 'FETCH_FORGOT_PASSWORD_REQUEST'; +export const FETCH_FORGOT_PASSWORD_SUCCESS = 'FETCH_FORGOT_PASSWORD_SUCCESS'; +export const FETCH_FORGOT_PASSWORD_FAILURE = 'FETCH_FORGOT_PASSWORD_FAILURE'; diff --git a/client/coral-admin/src/containers/LayoutContainer.js b/client/coral-admin/src/containers/LayoutContainer.js index ca9ff2e7b..d122cd23a 100644 --- a/client/coral-admin/src/containers/LayoutContainer.js +++ b/client/coral-admin/src/containers/LayoutContainer.js @@ -1,7 +1,7 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; import Layout from '../components/ui/Layout'; -import {checkLogin, handleLogin, logout} from '../actions/auth'; +import {checkLogin, handleLogin, logout, requestPasswordReset} from '../actions/auth'; import {FullLoading} from '../components/FullLoading'; import AdminLogin from '../components/AdminLogin'; @@ -11,12 +11,20 @@ class LayoutContainer extends Component { checkLogin(); } render () { - const {isAdmin, loggedIn, loadingUser, loginError} = this.props.auth; + const { + isAdmin, + loggedIn, + loadingUser, + loginError, + passwordRequestSuccess + } = this.props.auth; const {handleLogout} = this.props; if (loadingUser) { return ; } if (!isAdmin) { return ; } if (isAdmin && loggedIn) { return ; } @@ -31,6 +39,7 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ checkLogin: () => dispatch(checkLogin()), handleLogin: (username, password) => dispatch(handleLogin(username, password)), + requestPasswordReset: email => dispatch(requestPasswordReset(email)), handleLogout: () => dispatch(logout()) }); diff --git a/client/coral-admin/src/reducers/auth.js b/client/coral-admin/src/reducers/auth.js index d2f178773..b52efdb85 100644 --- a/client/coral-admin/src/reducers/auth.js +++ b/client/coral-admin/src/reducers/auth.js @@ -5,7 +5,8 @@ const initialState = Map({ loggedIn: false, user: null, isAdmin: false, - loginError: null + loginError: null, + passwordRequestSuccess: null }); export default function auth (state = initialState, action) { @@ -30,6 +31,10 @@ export default function auth (state = initialState, action) { return state.set('loginError', null); case actions.LOGIN_FAILURE: return state.set('loginError', action.message); + case actions.FETCH_FORGOT_PASSWORD_REQUEST: + return state.set('passwordRequestSuccess', null); + case actions.FETCH_FORGOT_PASSWORD_SUCCESS: + return state.set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email.'); default : return state; } From 04ab00d053e441d5c5010b3cdf2d58f72ddf629d Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 10:40:40 -0700 Subject: [PATCH 06/21] ignore this --- client/coral-admin/src/AppRouter.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index aacc3d6c7..38d06dcb1 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -14,8 +14,6 @@ import Dashboard from 'containers/Dashboard/Dashboard'; const routes = (
- - From 045fa3e2a945988910aa1e066d410c44695ccc2a Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 10:42:01 -0700 Subject: [PATCH 07/21] also ignore this --- client/coral-admin/src/components/AdminLogin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index cd9bac1d4..3d374bcda 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -66,7 +66,7 @@ class AdminLogin extends React.Component { return (
-

Permission Required

+

Team Sign In

Sign in to interact with your community.

{ this.state.requestPassword ? requestPasswordForm : signInForm }
From 4e5bcbc27f61185bbc32e7301af21bb8974683f1 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 11:42:03 -0700 Subject: [PATCH 08/21] even more design updates --- .../coral-admin/src/components/AdminLogin.js | 30 ++++++++++------- .../coral-admin/src/components/NotFound.css | 32 ++++++++++++++++--- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index 3d374bcda..7c7d4b00f 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -1,7 +1,7 @@ import React, {PropTypes} from 'react'; import Layout from 'coral-admin/src/components/ui/Layout'; import styles from './NotFound.css'; -import {Button, TextField, Alert} from 'coral-ui'; +import {Button, TextField, Alert, Success} from 'coral-ui'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; const lang = new I18n(translations); @@ -29,20 +29,22 @@ class AdminLogin extends React.Component {
{errorMessage && {lang.t(`errors.${errorMessage}`)}} this.setState({email: e.target.value})} /> this.setState({password: e.target.value})} type='password' /> +
-

- Forgot your password? { + full + onClick={this.handleSignIn}>Sign In +

+ Forgot your password? { e.preventDefault(); this.setState({requestPassword: true}); }}>Request a new one. @@ -51,23 +53,29 @@ class AdminLogin extends React.Component { ); const requestPasswordForm = ( this.props.passwordRequestSuccess - ?

{this.props.passwordRequestSuccess}

+ ?

{ + location.href = location.href; + }}> + {this.props.passwordRequestSuccess} Sign in + +

: this.setState({email: e.target.value})} /> ); return ( -
-

Team Sign In

-

Sign in to interact with your community.

+
+

Team sign in

+

Sign in to interact with your community.

{ this.state.requestPassword ? requestPasswordForm : signInForm }
diff --git a/client/coral-admin/src/components/NotFound.css b/client/coral-admin/src/components/NotFound.css index c45fbcc02..9977f858a 100644 --- a/client/coral-admin/src/components/NotFound.css +++ b/client/coral-admin/src/components/NotFound.css @@ -1,15 +1,37 @@ .layout { + max-width: 800px; + margin: 0 auto; +} + +.loginLayout { max-width: 400px; margin: 0 auto; } +.loginHeader, .loginCTA, .forgotPasswordCTA, .passwordRequestSuccess { + text-align: center; + font-size: 16px; +} + +.forgotPasswordLink, .signInLink { + color: blue; + font-weight: normal; + text-decoration: none; +} + +.forgotPasswordLink:hover, .signInLink:hover { + text-decoration: underline; +} + .layout h1 { font-size: 40px; } -.passwordRequestSuccess { - padding: 8px 14px; - background: lightgreen; - border: 1px solid darkgreen; - border-radius: 4px; +.loginHeader { + font-size: 30px; +} + +.passwordRequestSuccess { + cursor: pointer; + padding: 8px 14px; } From 2f05cec380a01986b8d5cdb12f0b78c2109bc6c2 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 11:50:32 -0700 Subject: [PATCH 09/21] Removed yarn install (already has yarn!) --- Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index dc7e64e31..fc0b3aca2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,5 @@ FROM node:7.6 -# Install yarn -RUN npm install -g yarn - # Create app directory RUN mkdir -p /usr/src/app WORKDIR /usr/src/app From 0085d2bb0473e4c2fd708e832cccc48ae11c65f6 Mon Sep 17 00:00:00 2001 From: David Jay Date: Wed, 1 Mar 2017 14:21:03 -0500 Subject: [PATCH 10/21] Preventing premod comments from being posted optimistically. --- client/coral-framework/graphql/mutations/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-framework/graphql/mutations/index.js b/client/coral-framework/graphql/mutations/index.js index 67af2df4a..4c2920e54 100644 --- a/client/coral-framework/graphql/mutations/index.js +++ b/client/coral-framework/graphql/mutations/index.js @@ -40,7 +40,7 @@ export const postComment = graphql(POST_COMMENT, { updateQueries: { AssetQuery: (oldData, {mutationResult:{data:{createComment:{comment}}}}) => { - if (oldData.asset.moderation === 'PRE') { + if (oldData.asset.settings.moderation === 'PRE') { return oldData; } From 9cb835b08bc493ed072c00398f26cdb15ac13d74 Mon Sep 17 00:00:00 2001 From: David Jay Date: Wed, 1 Mar 2017 14:49:42 -0500 Subject: [PATCH 11/21] Setting action user_id to null on suspect words. --- graph/mutators/action.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index a572a641c..3bc20cba4 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -16,7 +16,7 @@ const createAction = ({user = {}}, {item_id, item_type, action_type, group_id, m return ActionsService.insertUserAction({ item_id, item_type, - user_id: user.id, + user_id: group_id === 'Matched suspect word filter' ? null : user.id, group_id, action_type, metadata From 49477ead6a3ae3b80bf4689a1dbc69c24ba7b6f9 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 13:47:08 -0700 Subject: [PATCH 12/21] Fixed temp issue --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index fc0b3aca2..7cd06e673 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ FROM node:7.6 +# Add node-gyp for bcrypt build support +RUN yarn global add node-gyp + # Create app directory RUN mkdir -p /usr/src/app WORKDIR /usr/src/app From fb96d432ee4f1fcf237f56a9efda881db8b34bf0 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 13:51:32 -0700 Subject: [PATCH 13/21] Moved action creation upstream --- graph/mutators/action.js | 2 +- graph/mutators/comment.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index 3bc20cba4..a572a641c 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -16,7 +16,7 @@ const createAction = ({user = {}}, {item_id, item_type, action_type, group_id, m return ActionsService.insertUserAction({ item_id, item_type, - user_id: group_id === 'Matched suspect word filter' ? null : user.id, + user_id: user.id, group_id, action_type, metadata diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index 5112ba829..d608eee57 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -1,6 +1,7 @@ const errors = require('../../errors'); const AssetsService = require('../../services/assets'); +const ActionsService = require('../../services/actions'); const CommentsService = require('../../services/comments'); const Wordlist = require('../../services/wordlist'); @@ -146,10 +147,11 @@ const createPublicComment = (context, commentInput) => { // TODO: this is kind of fragile, we should refactor this to resolve // all these const's that we're using like 'COMMENTS', 'FLAG' to be // defined in a checkable schema. - return context.mutators.Action.create({ + return ActionsService.insertUserAction({ item_id: comment.id, item_type: 'COMMENTS', action_type: 'FLAG', + user_id: null, group_id: 'Matched suspect word filter', metadata: {} }) From 62793f59472cb8a64fafa9c6b4492038c64649dc Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 14:40:10 -0700 Subject: [PATCH 14/21] keepin' it DRY --- .../src/containers/Configure/Configure.css | 2 +- .../src/containers/Configure/Configure.js | 85 ++++++++++--------- .../src/containers/Configure/Domainlist.js | 24 +++--- .../src/containers/Configure/EmbedLink.js | 21 ++--- .../Configure/ModerationSettings.js | 56 ++++++++++++ .../{CommentSettings.js => StreamSettings.js} | 47 +--------- .../src/containers/Configure/TechSettings.js | 48 +++++++++++ client/coral-admin/src/reducers/settings.js | 4 +- 8 files changed, 177 insertions(+), 110 deletions(-) create mode 100644 client/coral-admin/src/containers/Configure/ModerationSettings.js rename client/coral-admin/src/containers/Configure/{CommentSettings.js => StreamSettings.js} (80%) create mode 100644 client/coral-admin/src/containers/Configure/TechSettings.js diff --git a/client/coral-admin/src/containers/Configure/Configure.css b/client/coral-admin/src/containers/Configure/Configure.css index 1f23af30b..5f4a07c81 100644 --- a/client/coral-admin/src/containers/Configure/Configure.css +++ b/client/coral-admin/src/containers/Configure/Configure.css @@ -150,7 +150,7 @@ margin-top: 38px; } -.commentSettingsSection { +.settingsSection { padding-bottom: 200px; .action { display: inline-block; diff --git a/client/coral-admin/src/containers/Configure/Configure.js b/client/coral-admin/src/containers/Configure/Configure.js index 1ec78dcd2..2fbe9daf2 100644 --- a/client/coral-admin/src/containers/Configure/Configure.js +++ b/client/coral-admin/src/containers/Configure/Configure.js @@ -8,22 +8,20 @@ import { updateDomainlist } from '../../actions/settings'; -import {Button, List, Item} from 'coral-ui'; +import {Button, List, Item, Card, Spinner} from 'coral-ui'; import styles from './Configure.css'; import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../../translations.json'; -import EmbedLink from './EmbedLink'; -import CommentSettings from './CommentSettings'; -import Wordlist from './Wordlist'; -import Domainlist from './Domainlist'; -import has from 'lodash/has'; +import translations from 'coral-admin/src/translations.json'; +import StreamSettings from './StreamSettings'; +import ModerationSettings from './ModerationSettings'; +import TechSettings from './TechSettings'; class Configure extends Component { constructor (props) { super(props); this.state = { - activeSection: 'comments', + activeSection: 'stream', changed: false, errors: {} }; @@ -70,40 +68,51 @@ class Configure extends Component { getSection (section) { const pageTitle = this.getPageTitle(section); + let sectionComponent; switch(section){ - case 'comments': - return ; - case 'embed': - return has(this, 'props.settings.domains.whitelist') - ?
- - -
- : ; - case 'wordlist': - return has(this, 'props.settings.wordlist') - ? - :

loading wordlists

; + break; + case 'moderation': + sectionComponent = ; + break; + case 'tech': + sectionComponent = ; } + + if (this.props.settings.fetchingSettings) { + return Loading settings...; + } + + return ( +
+

{pageTitle}

+ {sectionComponent} +
+ ); } getPageTitle (section) { switch(section) { - case 'comments': - return lang.t('configure.comment-settings'); - case 'embed': - return lang.t('configure.embed-comment-stream'); + case 'stream': + return lang.t('configure.stream-settings'); + case 'moderation': + return lang.t('configure.moderation-settings'); + case 'tech': + return lang.t('configure.tech-settings'); default: return ''; } @@ -120,14 +129,14 @@ class Configure extends Component {
- - {lang.t('configure.comment-settings')} + + {lang.t('configure.stream-settings')} - - {lang.t('configure.embed-comment-stream')} + + {lang.t('configure.moderation-settings')} - - {lang.t('configure.wordlist')} + + {lang.t('configure.tech-settings')}
diff --git a/client/coral-admin/src/containers/Configure/Domainlist.js b/client/coral-admin/src/containers/Configure/Domainlist.js index 6918c0471..bda3ca139 100644 --- a/client/coral-admin/src/containers/Configure/Domainlist.js +++ b/client/coral-admin/src/containers/Configure/Domainlist.js @@ -9,19 +9,17 @@ const lang = new I18n(translations); const Domainlist = ({domains, onChangeDomainlist}) => { return ( -
-

{lang.t('configure.domain-list-title')}

- -

{lang.t('configure.domain-list-text')}

- data.split(',').map(d => d.trim())} - onChange={tags => onChangeDomainlist('whitelist', tags)} - /> -
-
+ +

{lang.t('configure.domain-list-title')}

+

{lang.t('configure.domain-list-text')}

+ data.split(',').map(d => d.trim())} + onChange={tags => onChangeDomainlist('whitelist', tags)} + /> +
); }; diff --git a/client/coral-admin/src/containers/Configure/EmbedLink.js b/client/coral-admin/src/containers/Configure/EmbedLink.js index 413f421d7..cdbb66c3a 100644 --- a/client/coral-admin/src/containers/Configure/EmbedLink.js +++ b/client/coral-admin/src/containers/Configure/EmbedLink.js @@ -44,19 +44,14 @@ class EmbedLink extends Component { "> `.trim(); return ( -
-

{this.props.title}

-
- -

{lang.t('configure.copy-and-paste')}

-