email validations work, now on to username validations
This commit is contained in:
15
app.js
15
app.js
@ -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',
|
||||||
|
@ -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 person’s 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];
|
||||||
|
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
|
|
||||||
|
Reference in New Issue
Block a user