Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some improvements with didactic value #22

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8dd90f8
differentiated the state name from the prop mapped name to understand…
pimoGit Feb 19, 2018
19a2fa5
fix errs in the comments
pimoGit Feb 19, 2018
b295378
added some clarification comments
pimoGit Feb 25, 2018
528aafe
change some comments for better
pimoGit Feb 25, 2018
47d0b53
added some useful comments
pimoGit Feb 27, 2018
705b25d
comments added for custom HOC and delted gmap ref da index
pimoGit Feb 28, 2018
35800e7
more comments
pimoGit Mar 1, 2018
02f8c68
added key to list item and useful comments, get rid og gmap ref, chan…
pimoGit Mar 5, 2018
829c127
enanched some comments
pimoGit Mar 6, 2018
5d60960
corrected some commnts
pimoGit Mar 10, 2018
b39af64
added some useful commets
pimoGit Mar 14, 2018
5c22444
added useful comments
pimoGit Mar 15, 2018
4414bf3
more comments
pimoGit Mar 16, 2018
a135b5c
some useful comments added
pimoGit Mar 19, 2018
1064d93
again comments
pimoGit Mar 19, 2018
d832025
more comments
pimoGit Mar 20, 2018
afc22f7
get rid of gmap and added useful comment
pimoGit Mar 22, 2018
e8a4207
useful comments again
pimoGit Mar 26, 2018
7114032
my compressed vers of validate, draft of comp optimization, comments
pimoGit Mar 28, 2018
70b3cc5
cleaned up the working signup and added an alt V draft file
pimoGit Apr 2, 2018
3b77b6e
refactoring draft potential actions optimization + comments
pimoGit Apr 4, 2018
acc5d4c
alt V to include HOC-auth directly in the feature comp, and commented…
pimoGit Apr 6, 2018
8b9573d
resolved srevr err alert duplication V2 - simpler way
pimoGit Apr 11, 2018
c4536c7
clear commented action optimization vto create a new branch for it
pimoGit Apr 12, 2018
dc97f58
uncomment the refactoring action
pimoGit Apr 12, 2018
6b9c329
action optimization, eliminated repeated code and centralized it in a…
pimoGit Apr 12, 2018
077731d
resolved merge conflit for: action optimization, eliminated repeated …
pimoGit Apr 12, 2018
28c5f91
join the 2 files in this version
pimoGit Apr 13, 2018
b0509d8
deleted useles file after branching
pimoGit Apr 13, 2018
d99b5d3
deleted useless file on the new branch
pimoGit Apr 13, 2018
ec1e19b
first attemtp to work of this version
pimoGit Apr 13, 2018
590cd81
some fixing and one step forward to make work this version
pimoGit Apr 19, 2018
f8cadea
trying to debug this version
pimoGit Apr 23, 2018
52713de
made this version of optimized signup comp work
pimoGit Apr 23, 2018
7d1e60a
output labels and err msg in a better way
pimoGit Apr 25, 2018
565a41b
Merge branch 'signup-comp-v2'
pimoGit May 4, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion auth/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<head>
<link rel="stylesheet" href="/style/style.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
</head>
<body>
<div class="container"></div>
Expand Down
30 changes: 15 additions & 15 deletions auth/client/src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,7 @@ export function signinUser({ email, password }) {
return function(dispatch) {
// Submit email/password to the server
axios.post(`${ROOT_URL}/signin`, { email, password })
.then(response => {
// If request is good...
// - Update state to indicate user is authenticated
dispatch({ type: AUTH_USER });
// - Save the JWT token
localStorage.setItem('token', response.data.token);
// - redirect to the route '/feature'
browserHistory.push('/feature');
})
.then(response => authUser(dispatch, response))
.catch(() => {
// If request is bad...
// - Show an error to the user
Expand All @@ -33,16 +25,24 @@ export function signinUser({ email, password }) {
export function signupUser({ email, password }) {
return function(dispatch) {
axios.post(`${ROOT_URL}/signup`, { email, password })
.then(response => {
dispatch({ type: AUTH_USER });
localStorage.setItem('token', response.data.token);
browserHistory.push('/feature');
})
.then(response => authUser(dispatch, response))
.catch(response => dispatch(authError(response.data.error)));
}
}

export function authError(error) {

//refactoring actions optimization, external from (signinUser e signupUser)
export function authUser(dispatch, response) {
// If request is good...
// - Update state to indicate user is authenticated
dispatch({ type: AUTH_USER });
// - Save the JWT token
localStorage.setItem('token', response.data.token); // localStorage is a Web API (DOM) we just set a name and pass the token
// - redirect to the route '/feature'
browserHistory.push('/feature');
}

export function authError(error) { //this action is external from (signinUser e signupUser) coz it's easier to share with these 2 (so no repeat)
return {
type: AUTH_ERROR,
payload: error
Expand Down
2 changes: 1 addition & 1 deletion auth/client/src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default class App extends Component {
return (
<div>
<Header />
{this.props.children}
{this.props.children} {/* has child routes to show*/}
</div>
);
}
Expand Down
27 changes: 17 additions & 10 deletions auth/client/src/components/auth/signin.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import * as actions from '../../actions';
import { reduxForm } from 'redux-form';// import the HOC from redux-form
import * as actions from '../../actions';//import actions creators

class Signin extends Component {
handleFormSubmit({ email, password }) {
// Need to do something to log user in
this.props.signinUser({ email, password });
componentWillMount() {// clear the server err for every back and forth to the page for renderAlert()
this.props.authError('');
}

renderAlert() {
renderAlert() { // show up the err msg if it exists [funct called in render..]
if (this.props.errorMessage) {
return (
<div className="alert alert-danger">
Expand All @@ -17,12 +17,19 @@ class Signin extends Component {
);
}
}

handleFormSubmit({ email, password }) {//callback #1
// Need to do something to log user in
this.props.signinUser({ email, password });//call the action creator
}



render() {
const { handleSubmit, fields: { email, password }} = this.props;
const { handleSubmit, fields: { email, password }} = this.props;//hooks up handleSubmit (method from redux-form to the fields)

return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}> {/*hooks up handleSubmit to the callback #1*/}
<fieldset className="form-group">
<label>Email:</label>
<input {...email} className="form-control" />
Expand All @@ -45,4 +52,4 @@ function mapStateToProps(state) {
export default reduxForm({
form: 'signin',
fields: ['email', 'password']
}, mapStateToProps, actions)(Signin);
}, mapStateToProps, actions)(Signin);//hooks up the actions creators
68 changes: 57 additions & 11 deletions auth/client/src/components/auth/signup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import * as actions from '../../actions';

//helper comp function, split strings when needed (to have the right string output from the field name in the loop)
function splitString(initialtext) {
let regex1 = RegExp(/(?=[A-Z])/); //has cap letter in
let are2words = regex1.test(initialtext); // check if true
let result= are2words ? initialtext.split(/(?=[A-Z])/).join(" ") : initialtext;
//console.log(initialtext, are2words);
return result
}

class Signup extends Component {
handleFormSubmit(formProps) {
// Call action creator to sign up the user!
this.props.signupUser(formProps);
componentWillMount() {// clear the server err for every back and forth to the page for renderAlert()
this.props.authError('');
}

renderAlert() {
Expand All @@ -17,38 +26,64 @@ class Signup extends Component {
);
}
}

handleFormSubmit(formProps) {
// Call action creator to sign up the user!
this.props.signupUser(formProps);
}



// comp optimization
renderFieldsets(fieldlist){

let fieldsetArr = Object.values(fieldlist).map(fieldobj => (
<fieldset className="form-group" key={fieldobj.name}>
<label className='captext'>{splitString(fieldobj.name)}</label>
<input className="form-control" {...fieldobj} type={fieldobj.name === 'password' || fieldobj.name === 'passwordConfirm' ? 'password' : ''} />
{fieldobj.touched && fieldobj.error && <div className="error">{fieldobj.error}</div>}
</fieldset>
));
return fieldsetArr;
}


render() {
const { handleSubmit, fields: { email, password, passwordConfirm }} = this.props;

return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
{/* keeping this for didactic purpose
<fieldset className="form-group">
<label>Email:</label>
<input className="form-control" {...email} />
{email.touched && email.error && <div className="error">{email.error}</div>}
{email.touched && email.error && <div className="error">{email.error}</div>} //if 2&&== true - return the last vale of the && seq [js trick]
</fieldset>
<fieldset className="form-group">
<label>Password:</label>
<input className="form-control" {...password} type="password" />
{password.touched && password.error && <div className="error">{password.error}</div>}
{password.touched && password.error && <div className="error">{password.error}</div>} //manage 2 type of err with 1 block
</fieldset>
<fieldset className="form-group">
<label>Confirm Password:</label>
<input className="form-control" {...passwordConfirm} type="password" />
{passwordConfirm.touched && passwordConfirm.error && <div className="error">{passwordConfirm.error}</div>}
</fieldset>
{passwordConfirm.touched && passwordConfirm.error && <div className="error">{passwordConfirm.error}</div>}
</fieldset>*/}
{this.renderFieldsets(this.props.fields)}
{this.renderAlert()}
<button action="submit" className="btn btn-primary">Sign up!</button>
</form>
);
}
}

function validate(formProps) {
function validate(formProps) {// the arg is provided by HOC redux-form [and is a obj of the fields-value]
const errors = {};

if (!formProps.email) {

//console.log(formProps);

/* keeping this for didactic purpose
if (!formProps.email) {
errors.email = 'Please enter an email';
}

Expand All @@ -58,7 +93,18 @@ function validate(formProps) {

if (!formProps.passwordConfirm) {
errors.passwordConfirm = 'Please enter a password confirmation';
}
}*/

//my compressed approach of the above
Object.keys(formProps).map(field =>
{
if (!formProps[field]) {
//errors[field] = 'Please enter ' + (field === 'email' ? 'an ' : 'a ') + field;
errors[field] = `Please enter ${(field === 'email' ? 'an ' : 'a ') + splitString(field)}`;
}
}
)


if (formProps.password !== formProps.passwordConfirm) {
errors.password = 'Passwords must match';
Expand Down
4 changes: 3 additions & 1 deletion auth/client/src/components/feature.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
//import RequireAuth from './auth/require_auth'; ALT V just in case we want to use the HOC here

class Feature extends Component {
componentWillMount() {
Expand All @@ -18,4 +19,5 @@ function mapStateToProps(state) {
return { message: state.auth.message };
}

export default connect(mapStateToProps, actions)(Feature);
export default connect(mapStateToProps, actions)(Feature);
// ALT V just in case we wanna use HOC here not in the route, wrap like this RequireAuth(Feature)
2 changes: 1 addition & 1 deletion auth/client/src/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Header extends Component {
</li>
} else {
// show a link to sign in or sign up
return [
return [ // returns an array of li (so don't have err without div, rendering multiple items at the same level)
<li className="nav-item" key={1}>
<Link className="nav-link" to="/signin">Sign In</Link>
</li>,
Expand Down
4 changes: 2 additions & 2 deletions auth/client/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import reducers from './reducers';
import { AUTH_USER } from './actions/types';

const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(reducers);
const store = createStoreWithMiddleware(reducers); // create store outside to get it before check the token

const token = localStorage.getItem('token');
// If we have a token, consider the user to be signed in
if (token) {
// we need to update application state
store.dispatch({ type: AUTH_USER });
store.dispatch({ type: AUTH_USER }); // we can dispatch the action to the reducers [so if user is already auth we know it]
}

ReactDOM.render(
Expand Down
2 changes: 1 addition & 1 deletion auth/client/src/reducers/auth_reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
export default function(state = {}, action) {
switch(action.type) {
case AUTH_USER:
return { ...state, error: '', authenticated: true };
return { ...state, error: '', authenticated: true }; // reset error in case user is auth
case UNAUTH_USER:
return { ...state, authenticated: false };
case AUTH_ERROR:
Expand Down
4 changes: 2 additions & 2 deletions auth/client/src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import { reducer as form } from 'redux-form';// imp the reducer from redux-form and create an alias [... as form] to use a clearer name
import authReducer from './auth_reducer';

const rootReducer = combineReducers({
form,
form,// include the reducer from redux-form [form: form ES6 abbreviation]
auth: authReducer
});

Expand Down
1 change: 1 addition & 0 deletions auth/client/style/style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.error {
color: red;
}
.captext { text-transform: capitalize;}
6 changes: 3 additions & 3 deletions auth/server/controllers/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ const config = require('../config');

function tokenForUser(user) {
const timestamp = new Date().getTime();
return jwt.encode({ sub: user.id, iat: timestamp }, config.secret);
return jwt.encode({ sub: user.id, iat: timestamp }, config.secret); // sub: and iat: are existing properties of jwt to be setted
}

exports.signin = function(req, res, next) {
// User has already had their email and password auth'd
// We just need to give them a token
res.send({ token: tokenForUser(req.user) });
res.send({ token: tokenForUser(req.user) }); // req.user is returned from our Locastrategy in passport.js
}

exports.signup = function(req, res, next) {
Expand Down Expand Up @@ -39,7 +39,7 @@ exports.signup = function(req, res, next) {
user.save(function(err) {
if (err) { return next(err); }

// Repond to request indicating the user was created
// Repond to request indicating the user was created and returning the user token
res.json({ token: tokenForUser(user) });
});
});
Expand Down
2 changes: 1 addition & 1 deletion auth/server/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ userSchema.pre('save', function(next) {
});
});

userSchema.methods.comparePassword = function(candidatePassword, callback) {
userSchema.methods.comparePassword = function(candidatePassword, callback) { // attach a new funct to our schema
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) { return callback(err); }

Expand Down
4 changes: 2 additions & 2 deletions auth/server/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ const Authentication = require('./controllers/authentication');
const passportService = require('./services/passport');
const passport = require('passport');

const requireAuth = passport.authenticate('jwt', { session: false });
const requireAuth = passport.authenticate('jwt', { session: false });// session: false means we don't want cookies set (we use jwt)
const requireSignin = passport.authenticate('local', { session: false });

module.exports = function(app) {
app.get('/', requireAuth, function(req, res) {
app.get('/', requireAuth, function(req, res) { // we say to use the requireAuth (we create above) to handle this route req before sendig a res
res.send({ message: 'Super secret code is ABC123' });
});
app.post('/signin', requireSignin, Authentication.signin);
Expand Down
22 changes: 11 additions & 11 deletions auth/server/services/passport.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ const ExtractJwt = require('passport-jwt').ExtractJwt;
const LocalStrategy = require('passport-local');

// Create local strategy
const localOptions = { usernameField: 'email' };
const localOptions = { usernameField: 'email' }; // just to set that if it searchs for user has to loook at email
const localLogin = new LocalStrategy(localOptions, function(email, password, done) {
// Verify this email and password, call done with the user
// if it is the correct email and password
// otherwise, call done with false
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (err) { return done(err); }// err in the operation
if (!user) { return done(null, false); } // no err but email (so user) not found

// compare passwords - is `password` equal to user.password?
user.comparePassword(password, function(err, isMatch) {
user.comparePassword(password, function(err, isMatch) { //comparePassword is a method we created in user
if (err) { return done(err); }
if (!isMatch) { return done(null, false); }

Expand All @@ -27,22 +27,22 @@ const localLogin = new LocalStrategy(localOptions, function(email, password, don

// Setup options for JWT Strategy
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('authorization'),
secretOrKey: config.secret
jwtFromRequest: ExtractJwt.fromHeader('authorization'),//where to find the jtw (in this case header-authorization from the request)
secretOrKey: config.secret //what to use to decript the token (so we can have the user id back)
};

// Create JWT strategy
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
// See if the user ID in the payload exists in our database
// If it does, call 'done' with that other
// If it does, call 'done' with that user
// otherwise, call done without a user object
User.findById(payload.sub, function(err, user) {
if (err) { return done(err, false); }
User.findById(payload.sub, function(err, user) {// payload is the obj created with jwt.encode attached to the token in the db
if (err) { return done(err, false); } // if there is an err and we cannot find user (coz of the err)

if (user) {
done(null, user);
done(null, user);// there is no err an we find a user
} else {
done(null, false);
done(null, false);// there is no err but we don't find the user
}
});
});
Expand Down
Loading