create password reset token from FE, start to add flash text
This commit is contained in:
parent
ea6d30c430
commit
5aa5032961
7 changed files with 93 additions and 21 deletions
|
@ -94,6 +94,7 @@ export const DETECT_INFINITE_LOOPS = 'DETECT_INFINITE_LOOPS';
|
|||
export const RESET_INFINITE_LOOPS = 'RESET_INFINITE_LOOPS';
|
||||
|
||||
export const RESET_PASSWORD_INITIATE = 'RESET_PASSWORD_INITIATE';
|
||||
export const RESET_PASSWORD_RESET = 'RESET_PASSWORD_RESET';
|
||||
|
||||
// eventually, handle errors more specifically and better
|
||||
export const ERROR = 'ERROR';
|
||||
|
|
|
@ -13,12 +13,12 @@ function ResetPasswordForm(props) {
|
|||
{...email}
|
||||
/>
|
||||
</p>
|
||||
<input type="submit" disabled={submitting || invalid || pristine} value="Send email to reset password" aria-label="Send email to reset password" />
|
||||
<input type="submit" disabled={submitting || invalid || pristine} value="Send password reset email" aria-label="Send email to reset password" />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
ResetPassword.propTypes = {
|
||||
ResetPasswordForm.propTypes = {
|
||||
fields: PropTypes.shape({
|
||||
email: PropTypes.object.isRequired
|
||||
}).isRequired,
|
||||
|
@ -27,6 +27,6 @@ ResetPassword.propTypes = {
|
|||
submitting: PropTypes.bool,
|
||||
invalid: PropTypes.bool,
|
||||
pristine: PropTypes.bool
|
||||
}
|
||||
};
|
||||
|
||||
export default ResetPasswordForm;
|
||||
|
|
|
@ -1,29 +1,51 @@
|
|||
import React from 'react';
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import * as UserActions from '../../User/actions';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { reduxForm } from 'redux-form';
|
||||
import ResetPasswordForm from './ResetPasswordForm';
|
||||
import classNames from 'classnames';
|
||||
|
||||
class ResetPasswordView extends React.Component {
|
||||
componentWillMount() {
|
||||
this.props.resetPasswordReset();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.refs.resetPassword.focus();
|
||||
}
|
||||
|
||||
render() {
|
||||
const resetPasswordClass = classNames({
|
||||
'reset-password': true,
|
||||
'reset-password--submitted': this.props.user.passwordResetInitialized
|
||||
});
|
||||
return (
|
||||
<div className="reset-password" ref="resetPassword" tabIndex="0">
|
||||
<div className={resetPasswordClass} ref="resetPassword" tabIndex="0">
|
||||
<h1>Reset Your Password</h1>
|
||||
<ResetPasswordForm {...this.props} />
|
||||
<p className="reset-password__submitted">
|
||||
Your password reset email should arrive shortly. If you don't see it, check
|
||||
in your spam folder as sometimes it can end up there.
|
||||
</p>
|
||||
<p className="form__navigation-options">
|
||||
<Link className="form__login-button" to="/login">Login</Link>
|
||||
or
|
||||
or
|
||||
<Link className="form__signup-button" to="/signup">Sign up</Link>
|
||||
</p>
|
||||
<Link className="form__cancel-button" to="/">Cancel</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ResetPasswordView.propTypes = {
|
||||
resetPasswordReset: PropTypes.func.isRequired,
|
||||
user: PropTypes.shape({
|
||||
passwordResetInitialized: PropTypes.bool
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
user: state.user
|
||||
|
@ -37,13 +59,13 @@ function mapDispatchToProps(dispatch) {
|
|||
function validate(formProps) {
|
||||
const errors = {};
|
||||
if (!formProps.email) {
|
||||
errors.email = 'Please enter an email'
|
||||
errors.email = 'Please enter an email';
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
export default reduxForm({
|
||||
form: 'reset-password',
|
||||
fields: 'email',
|
||||
fields: ['email'],
|
||||
validate
|
||||
}, mapStateToProps, mapDispatchToProps)(ResetPasswordView);
|
||||
|
|
|
@ -105,15 +105,23 @@ export function logoutUser() {
|
|||
};
|
||||
}
|
||||
|
||||
export function initiatePasswordReset(formValues) {
|
||||
export function initiateResetPassword(formValues) {
|
||||
return (dispatch) => {
|
||||
axios.post(`${ROOT_URL}/reset-password`, formValues, { withCredentials: true})
|
||||
.then(response => {
|
||||
axios.post(`${ROOT_URL}/reset-password`, formValues, { withCredentials: true })
|
||||
.then(() => {
|
||||
dispatch({
|
||||
type: ActionTypes.RESET_PASSWORD_INITIATE
|
||||
});
|
||||
})
|
||||
.catch(response => dispatch({ActionTypes.ERROR}));
|
||||
}
|
||||
.catch(response => dispatch({
|
||||
type: ActionTypes.ERROR,
|
||||
message: response.data
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
export function resetPasswordReset() {
|
||||
return {
|
||||
type: ActionTypes.RESET_PASSWORD_RESET
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ const user = (state = { authenticated: false }, action) => {
|
|||
return {
|
||||
authenticated: false
|
||||
};
|
||||
case ActionTypes.RESET_PASSWORD_INITIATE:
|
||||
return Object.assign(state, {}, { resetPasswordInitiate: true });
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -7,3 +7,20 @@
|
|||
padding: #{20 / $base-font-size}rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.reset-password-form__email-input {
|
||||
width: #{300 / $base-font-size}rem;
|
||||
}
|
||||
|
||||
.reset-password-form__field {
|
||||
margin: #{20 / $base-font-size}rem 0;
|
||||
}
|
||||
|
||||
.reset-password__submitted {
|
||||
width: #{300 / $base-font-size}rem;
|
||||
display: none;
|
||||
.reset-password--submitted {
|
||||
display: block;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import User from '../models/user';
|
||||
import crypto from 'crypto';
|
||||
import async from 'async';
|
||||
|
||||
export function createUser(req, res, next) {
|
||||
const user = new User({
|
||||
|
@ -74,11 +76,31 @@ export function updatePreferences(req, res) {
|
|||
}
|
||||
|
||||
export function resetPasswordInitiate(req, res) {
|
||||
async.waterfall([
|
||||
(done) => {
|
||||
crypto.randomBytes(20, function(err, buf) {
|
||||
var token = buf.toString('hex');
|
||||
done(err, token);
|
||||
});
|
||||
},
|
||||
(token, done) => {
|
||||
User.findOne({ email: req.body.email }, (err, user) => {
|
||||
if (!user) {
|
||||
return res.json({message: 'If the email is registered with the editor, an email has been sent.'});
|
||||
return res.json({success: true, message: 'If the email is registered with the editor, an email has been sent.'});
|
||||
}
|
||||
user.resetPasswordToken = token;
|
||||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||
|
||||
user.save(function(err) {
|
||||
done(err, token, user);
|
||||
});
|
||||
});
|
||||
}
|
||||
], (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return res.json({success: false});
|
||||
}
|
||||
return res.json({success: true, message: 'If the email is registered with the editor, an email has been sent.'});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue