email validations work, now on to username validations

This commit is contained in:
Michael Q Larson
2014-12-23 18:20:53 -08:00
parent 20475ffcc4
commit fcd457b958
8 changed files with 170 additions and 85 deletions

15
app.js
View File

@ -76,7 +76,13 @@ app.use(connectAssets({
app.use(logger('dev')); app.use(logger('dev'));
app.use(bodyParser.json()); app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator()); app.use(expressValidator({
customValidators: {
matchRegex: function(param, regex) {
return regex.test(param);
}
}
}));
app.use(methodOverride()); app.use(methodOverride());
app.use(cookieParser()); app.use(cookieParser());
app.use(session({ app.use(session({
@ -264,13 +270,12 @@ app.get('/auth/twitter', passport.authenticate('twitter'));
app.get( app.get(
'/auth/twitter/callback', '/auth/twitter/callback',
passport.authenticate('twitter', { passport.authenticate('twitter', {
successRedirect: '/', successRedirect: '/auth/twitter/middle',
failureRedirect: '/auth/twitter/middle' failureRedirect: '/login'
}) })
); );
app.get('/auth/twitter/middle', function(req, res, next) { app.get('/auth/twitter/middle', passportConf.hasEmail);
});
app.get( app.get(
'/auth/linkedin', '/auth/linkedin',

View File

@ -14,7 +14,8 @@ var _ = require('lodash'),
// Login Required middleware. // Login Required middleware.
module.exports = { module.exports = {
isAuthenticated: isAuthenticated, isAuthenticated: isAuthenticated,
isAuthorized: isAuthorized isAuthorized: isAuthorized,
hasEmail: hasEmail
}; };
passport.serializeUser(function(user, done) { passport.serializeUser(function(user, done) {
@ -107,12 +108,6 @@ passport.use(
} else { } else {
User.findOne({ twitter: profile.id }, function(err, existingUser) { User.findOne({ twitter: profile.id }, function(err, existingUser) {
if (err) { return done(err); } if (err) { return done(err); }
//if (existingUser) return done(null, existingUser);
// Twitter will not provide an email address. Period.
// But a persons twitter username is guaranteed to be unique
// so we can "fake" a twitter email address as follows:
//user.email = profile.username + "@twitter.com";
var user = existingUser || new User(); var user = existingUser || new User();
user.twitter = profile.id; user.twitter = profile.id;
user.email = user.email || ''; user.email = user.email || '';
@ -132,15 +127,6 @@ passport.use(
if (err) { return done(err); } if (err) { return done(err); }
done(null, user); done(null, user);
}); });
//TODO: Twitter redirect to capture user email.
//if (!user.email) {
// req.redirect('/account');
// req.flash('errors', {
// msg:
// 'OK, you are signed in. ' +
// 'Please add your email address to your profile.'
// });
//}
}); });
} }
}) })
@ -513,6 +499,21 @@ function isAuthenticated(req, res, next) {
res.redirect('/login'); res.redirect('/login');
} }
function hasEmail(req, res) {
if (req.user) {
console.log('started');
if (req.user.email) {
res.redirect('/');
} else {
console.log('hit');
req.flash('info', {
msg: 'Please add your email address before starting our challenges.'
});
res.redirect('/account');
}
}
}
// Authorization Required middleware. // Authorization Required middleware.
function isAuthorized(req, res, next) { function isAuthorized(req, res, next) {
var provider = req.path.split('/').slice(-1)[0]; var provider = req.path.split('/').slice(-1)[0];

View File

@ -170,10 +170,6 @@ exports.updateProgress = function(req, res) {
}); });
}; };
/** /**
* POST /account/profile * POST /account/profile
* Update profile information. * Update profile information.
@ -182,16 +178,56 @@ exports.updateProgress = function(req, res) {
exports.postUpdateProfile = function(req, res, next) { exports.postUpdateProfile = function(req, res, next) {
User.findById(req.user.id, function(err, user) { User.findById(req.user.id, function(err, user) {
if (err) return next(err); if (err) return next(err);
user.email = req.body.email || '';
user.profile.name = req.body.name || '';
user.profile.username = req.body.username || '';
user.profile.location = req.body.location || '';
user.profile.website = req.body.website || '';
user.save(function(err) { req.assert('email', 'Email is required').notEmpty();
if (err) return next(err); req.assert('email', 'Please enter a valid email address.').isEmail();
req.flash('success', { msg: 'Profile information updated.' }); req.assert('username', 'Your username must be between 3 and 20 characters').len(3, 20);
res.redirect('/account'); req.assert('username', 'Your username can only use letters, numbers or underscores').matchRegex(/[A-Za-z0-9_]+/);
var errors = req.validationErrors();
if (errors) {
req.flash('errors', errors);
return res.redirect('/account');
}
User.findOne({ email: req.body.email }, function(err, existingEmail) {
if (err) {
return next(err);
}
var user = req.user;
if (existingEmail && existingEmail.email != user.email) {
console.log(user.email);
console.log(existingEmail.email)
req.flash('errors', {
msg: "An account with that email address already exists."
});
return res.redirect('/account');
}
User.findOne({ username: req.body.username }, function(err, existingUsername) {
if (err) {
return next(err);
}
var user = req.user;
if (existingUsername && existingUsername.profile.username != user.profile.username) {
console.log(existingUsername.profile.username)
console.log(user.profile.username)
req.flash('errors', {
msg: 'An account with that username already exists.'
});
return res.redirect('/account');
}
var user = req.user;
user.email = req.body.email || '';
user.profile.name = req.body.name || '';
user.profile.username = req.body.username || '';
user.profile.location = req.body.location || '';
user.profile.website = req.body.website || '';
user.save(function (err) {
if (err) return next(err);
req.flash('success', {msg: 'Profile information updated.'});
res.redirect('/account');
});
});
}); });
}); });
}; };

View File

@ -3,15 +3,13 @@ var crypto = require('crypto');
var mongoose = require('mongoose'); var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({ var userSchema = new mongoose.Schema({
/*email: { email: {
type: String, type: String,
unique: true, unique: true,
lowercase: true, lowercase: true,
match: /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/ trim: true
},*/ },
email: String,
password: String, password: String,
facebook: String, facebook: String,
twitter: String, twitter: String,
google: String, google: String,
@ -283,13 +281,14 @@ var userSchema = new mongoose.Schema({
picture: { picture: {
type: String, type: String,
default: '' default: ''
} },
/*username: { username: {
type: String, type: String,
default: '', default: '',
unique: true, unique: true,
match: /^[a-zA-Z0-9_]+$/ lowercase: true,
}*/ trim: true
}
}, },
resetPasswordToken: String, resetPasswordToken: String,

View File

@ -27,7 +27,7 @@
"express": "^4.10.4", "express": "^4.10.4",
"express-flash": "^0.0.2", "express-flash": "^0.0.2",
"express-session": "^1.9.2", "express-session": "^1.9.2",
"express-validator": "^2.7.0", "express-validator": "^2.8.0",
"fbgraph": "^0.3.0", "fbgraph": "^0.3.0",
"github-api": "^0.7.0", "github-api": "^0.7.0",
"helmet": "^0.5.3", "helmet": "^0.5.3",

View File

@ -259,6 +259,11 @@ ul {
margin: auto; margin: auto;
} }
.btn-link-social {
max-width: 400px;
margin-bottom: 10px;
}
.navbar { .navbar {
background-color: #4a2b0f; background-color: #4a2b0f;
} }
@ -357,3 +362,8 @@ thead {
.nowrap { .nowrap {
white-space: nowrap; white-space: nowrap;
} }
.big-break {
margin-top: 30px;
margin-bottom: 30px;
}

View File

@ -8,9 +8,9 @@ block content
a.btn.btn-lg.btn-block.btn-facebook.btn-social(href='/auth/facebook') a.btn.btn-lg.btn-block.btn-facebook.btn-social(href='/auth/facebook')
i.fa.fa-facebook i.fa.fa-facebook
| Sign in with Facebook | Sign in with Facebook
//a.btn.btn-lg.btn-block.btn-github.btn-social(href='/auth/github') a.btn.btn-lg.btn-block.btn-github.btn-social(href='/auth/github')
// i.fa.fa-github i.fa.fa-github
// | Sign in with GitHub | Sign in with GitHub
a.btn.btn-lg.btn-block.btn-linkedin.btn-social(href='/auth/linkedin') a.btn.btn-lg.btn-block.btn-linkedin.btn-social(href='/auth/linkedin')
i.fa.fa-linkedin i.fa.fa-linkedin
| Sign in with LinkedIn | Sign in with LinkedIn

View File

@ -11,8 +11,8 @@ block content
label.col-sm-2.control-label(for='name') Name label.col-sm-2.control-label(for='name') Name
.col-sm-4 .col-sm-4
input.form-control(type='text', name='name', id='name', value='#{user.profile.name}') input.form-control(type='text', name='name', id='name', value='#{user.profile.name}')
//.form-group .form-group
label.col-sm-2.control-label(for='username') Username label.col-sm-2.control-label(for='username') Username (no spaces)
.col-sm-4 .col-sm-4
input.form-control(type='text', name='username', id='username', value='#{user.profile.username}') input.form-control(type='text', name='username', id='username', value='#{user.profile.username}')
.form-group .form-group
@ -32,47 +32,81 @@ block content
button.btn.btn.btn-primary(type='submit') button.btn.btn.btn-primary(type='submit')
span.ion-edit span.ion-edit
| Update my profile | Update my profile
- if (!user.google || !user.facebook || !user.github || !user.linkedin || !user.twitter)
h1 Completed Challenges .panel
.col-xs-12 .container
table.table.table-striped h1 Link other services to your account:
thead - if (!user.google)
tr .col-xs-12
th Challenge a.btn.btn-lg.btn-block.btn-google-plus.btn-link-social(href='/auth/google')
th Date Finished i.fa.fa-google-plus
for challenge in cc | Link Google with your account
if ch[challenge.challengeNumber] > 0 - if (!user.facebook)
tr .col-xs-12
td= cc[challenge.challengeNumber].name a.btn.btn-lg.btn-block.btn-facebook.btn-link-social(href='/auth/facebook')
td= moment(ch[challenge.challengeNumber], 'X').format("MMM DD, YYYY") i.fa.fa-facebook
| Link Facebook with your account
- if (!user.github)
.col-xs-12
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/auth/github')
i.fa.fa-github
| Link GitHub with your account
- if (!user.linkedin)
.col-xs-12
a.btn.btn-lg.btn-block.btn-linkedin.btn-link-social(href='/auth/linkedin')
i.fa.fa-linkedin
| Link LinkedIn with your account
- if (!user.twitter)
.col-xs-12
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/auth/twitter')
i.fa.fa-twitter
| Link Twitter with your account
br
- if (ch[0] > 0)
.panel
.container
h1 Completed Challenges
.col-xs-12
table.table.table-striped
thead
tr
th Challenge
th Date Finished
for challenge in cc
if ch[challenge.challengeNumber] > 0
tr
td= cc[challenge.challengeNumber].name
td= moment(ch[challenge.challengeNumber], 'X').format("MMM DD, YYYY")
br
.panel
.container
h3 Danger Zone h3 Danger Zone
button.btn.btn-danger.confirm-deletion button.btn.btn-danger.confirm-deletion
span.ion-trash-b span.ion-trash-b
| I want to delete my account | I want to delete my account
br
script. script.
$('.confirm-deletion').on("click", function() { $('.confirm-deletion').on("click", function() {
$('#modal-dialog').modal('show'); $('#modal-dialog').modal('show');
}); });
#modal-dialog.modal.animated.wobble br
.modal-dialog #modal-dialog.modal.animated.wobble
.modal-content .modal-dialog
.modal-header .modal-content
a.close(href='#', data-dismiss='modal', aria-hidden='true') × .modal-header
h3 Are you really leaving us? a.close(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body h3 Are you really leaving us?
p Pro Tip: If you tweet feedback to  .modal-body
a(href="https://twitter.com/intent/tweet?text=Hey%20@freecodecamp") @FreeCodeCamp p Pro Tip: If you tweet feedback to 
| , we'll act quickly on it! a(href="https://twitter.com/intent/tweet?text=Hey%20@freecodecamp") @FreeCodeCamp
.modal-footer | , we'll act quickly on it!
a.btn.btn-success.btn-block(href='#', data-dismiss='modal', aria-hidden='true') .modal-footer
span.ion-happy a.btn.btn-success.btn-block(href='#', data-dismiss='modal', aria-hidden='true')
| Nevermind, I'll stick around span.ion-happy
br | Nevermind, I'll stick around
form(action='/account/delete', method='POST') br
input(type='hidden', name='_csrf', value=_csrf) form(action='/account/delete', method='POST')
button.btn.btn-danger.btn-block(type='submit') input(type='hidden', name='_csrf', value=_csrf)
span.ion-trash-b button.btn.btn-danger.btn-block(type='submit')
| Yes, Delete my account span.ion-trash-b
br | Yes, Delete my account
br