Merge pull request #8414 from FreeCodeCamp/staging

Release Staging
This commit is contained in:
Berkeley Martinez
2016-05-02 23:19:14 -07:00
9 changed files with 98 additions and 110 deletions

View File

@ -506,7 +506,7 @@ a[href="/email-signup"], a[href="/email-signin"] {
} }
} }
form.email-update .btn{ form.update-email .btn{
margin:0; margin:0;
width:40%; width:40%;
display:inline-block; display:inline-block;

View File

@ -12,21 +12,11 @@ const { defaultProfileImage } = require('../utils/constantStrings.json');
const githubRegex = (/github/i); const githubRegex = (/github/i);
const debug = debugFactory('fcc:models:userIdent'); const debug = debugFactory('fcc:models:userIdent');
function createAccessToken(user, ttl, cb) {
if (arguments.length === 2 && typeof ttl === 'function') {
cb = ttl;
ttl = 0;
}
user.accessTokens.create({
created: new Date(),
ttl: Math.min(ttl || user.constructor.settings.ttl,
user.constructor.settings.maxTTL)
}, cb);
}
export default function(UserIdent) { export default function(UserIdent) {
// original source // original source
// github.com/strongloop/loopback-component-passport // github.com/strongloop/loopback-component-passport
const createAccountMessage =
'Accounts can only be created using GitHub or though email';
UserIdent.login = function( UserIdent.login = function(
provider, provider,
authScheme, authScheme,
@ -40,96 +30,93 @@ export default function(UserIdent) {
cb = options; cb = options;
options = {}; options = {};
} }
var autoLogin = options.autoLogin || !options.autoLogin; const userIdentityModel = UserIdent;
var userIdentityModel = UserIdent;
profile.id = profile.id || profile.openid; profile.id = profile.id || profile.openid;
userIdentityModel.findOne({ const filter = {
where: { where: {
provider: getSocialProvider(provider), provider: getSocialProvider(provider),
externalId: profile.id externalId: profile.id
} }
}, function(err, identity) { };
if (err) { return userIdentityModel.findOne(filter)
return cb(err); .then(identity => {
} // identity already exists
if (identity) { // find user and log them in
identity.credentials = credentials; if (identity) {
return identity.updateAttributes({ identity.credentials = credentials;
profile: profile, const options = {
credentials: credentials, profile: profile,
modified: new Date() credentials: credentials,
}, function(err) { modified: new Date()
if (err) { };
return cb(err); return identity.updateAttributes(options)
} // grab user associated with identity
// Find the user for the given identity .then(() => identity.user())
return identity.user(function(err, user) { .then(user => {
// Create access token if the autoLogin flag is set to true // Create access token for user
if (!err && user && autoLogin) { const options = {
return (options.createAccessToken || createAccessToken)( created: new Date(),
user, ttl: user.constructor.settings.ttl
function(err, token) { };
cb(err, user, identity, token); return user.accessTokens.create(options)
} .then(token => ({ user, token }));
); })
} .then(({ token, user })=> {
return cb(err, user, identity); cb(null, user, identity, token);
}); })
}); .catch(err => cb(err));
}
// Find the user model
var userModel = userIdentityModel.relations.user &&
userIdentityModel.relations.user.modelTo ||
loopback.getModelByType(loopback.User);
var userObj = options.profileToUser(provider, profile, options);
if (!userObj.email && !options.emailOptional) {
process.nextTick(function() {
return cb('email is missing from the user profile');
});
}
var query;
if (userObj.email) {
query = { or: [
{ username: userObj.username },
{ email: userObj.email }
]};
} else {
query = { username: userObj.username };
}
return userModel.findOrCreate({ where: query }, userObj, (err, user) => {
if (err) {
return cb(err);
} }
var date = new Date(); // Find the user model
return userIdentityModel.create({ const userModel = userIdentityModel.relations.user &&
provider: getSocialProvider(provider), userIdentityModel.relations.user.modelTo ||
externalId: profile.id, loopback.getModelByType(loopback.User);
authScheme: authScheme,
profile: profile, const userObj = options.profileToUser(provider, profile, options);
credentials: credentials, if (getSocialProvider(provider) !== 'github') {
userId: user.id, const err = new Error(createAccountMessage);
created: date, err.userMessage = createAccountMessage;
modified: date err.messageType = 'info';
}, function(err, identity) { err.redirectTo = '/signin';
if (!err && user && autoLogin) { return process.nextTick(() => cb(err));
return (options.createAccessToken || createAccessToken)( }
user,
function(err, token) { let query;
cb(err, user, identity, token); if (userObj.email) {
} query = { or: [
); { username: userObj.username },
} { email: userObj.email }
return cb(err, user, identity); ]};
}); } else {
query = { username: userObj.username };
}
return userModel.findOrCreate({ where: query }, userObj)
.then(([ user ]) => {
const promises = [
userIdentityModel.create({
provider: getSocialProvider(provider),
externalId: profile.id,
authScheme: authScheme,
profile: profile,
credentials: credentials,
userId: user.id,
created: new Date(),
modified: new Date()
}),
user.accessTokens.create({
created: new Date(),
ttl: user.constructor.settings.ttl
})
];
return Promise.all(promises)
.then(([ identity, token ]) => ({ user, identity, token }));
})
.then(({ user, token, identity }) => cb(null, user, identity, token))
.catch(err => cb(err));
}); });
});
}; };
UserIdent.observe('before save', function(ctx, next) { UserIdent.observe('before save', function(ctx, next) {
var userIdent = ctx.currentInstance || ctx.instance; const userIdent = ctx.currentInstance || ctx.instance;
if (!userIdent) { if (!userIdent) {
debug('no user identity instance found'); debug('no user identity instance found');
return next(); return next();

View File

@ -41,6 +41,8 @@ module.exports = function(User) {
User.definition.properties.rand.default = function() { User.definition.properties.rand.default = function() {
return Math.random(); return Math.random();
}; };
// increase user accessToken ttl to 900 days
User.settings.ttl = 900 * 24 * 60 * 60 * 1000;
// username should not be in blacklist // username should not be in blacklist
User.validatesExclusionOf('username', { User.validatesExclusionOf('username', {

View File

@ -241,7 +241,7 @@ module.exports = function(app) {
if (!req.user) { if (!req.user) {
return res.redirect('/'); return res.redirect('/');
} }
return res.render('account/email-update', { return res.render('account/update-email', {
title: 'Update your Email' title: 'Update your Email'
}); });
} }

View File

@ -13,18 +13,18 @@ import {
const passportOptions = { const passportOptions = {
emailOptional: true, emailOptional: true,
profileToUser(provider, profile) { profileToUser(provider, profile) {
var emails = profile.emails; const emails = profile.emails;
// NOTE(berks): get email or set to null. // NOTE(berks): get email or set to null.
// MongoDB indexs email but can be sparse(blank) // MongoDB indexs email but can be sparse(blank)
var email = emails && emails[0] && emails[0].value ? const email = emails && emails[0] && emails[0].value ?
emails[0].value : emails[0].value :
null; null;
// create random username // create random username
// username will be assigned when camper signups for Github // username will be assigned when camper signups for Github
var username = 'fcc' + uuid.v4().slice(0, 8); const username = 'fcc' + uuid.v4().slice(0, 8);
var password = generateKey('password'); const password = generateKey('password');
var userObj = { let userObj = {
username: username, username: username,
password: password password: password
}; };
@ -41,7 +41,7 @@ const passportOptions = {
} }
if (/github/.test(provider)) { if (/github/.test(provider)) {
setProfileFromGithub(userObj, profile, profile._json); userObj = setProfileFromGithub(userObj, profile, profile._json);
} }
return userObj; return userObj;
} }

View File

@ -25,11 +25,11 @@ export default function prodErrorHandler() {
var message = 'Oops! Something went wrong. Please try again later'; var message = 'Oops! Something went wrong. Please try again later';
if (type === 'html') { if (type === 'html') {
if (typeof req.flash === 'function') { if (typeof req.flash === 'function') {
req.flash('errors', { req.flash(err.messageType || 'errors', {
msg: message msg: err.userMessage || message
}); });
} }
return res.redirect('/map'); return res.redirect(err.redirectTo || '/map');
// json // json
} else if (type === 'json') { } else if (type === 'json') {
res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Type', 'application/json');

View File

@ -1,5 +1,3 @@
import assign from 'object.assign';
const providerHash = { const providerHash = {
facebook: ({ id }) => id, facebook: ({ id }) => id,
twitter: ({ username }) => username, twitter: ({ username }) => username,
@ -32,15 +30,16 @@ export function setProfileFromGithub(
name name
} }
) { ) {
return assign( return Object.assign(
user, user,
{ isGithubCool: true, isMigrationGrandfathered: false },
{ {
name, name,
email: user.email || githubEmail,
username: username.toLowerCase(), username: username.toLowerCase(),
location, location,
joinedGithubOn, joinedGithubOn,
website, website,
isGithubCool: true,
picture, picture,
githubId, githubId,
githubURL, githubURL,

View File

@ -54,7 +54,7 @@ block content
p.large-p.text-center p.large-p.text-center
em #{user.email} em #{user.email}
.col-xs-12 .col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/email-update') a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/update-email')
i.fa.fa-envelope i.fa.fa-envelope
| Update my Email | Update my Email
.row .row
@ -100,7 +100,7 @@ block content
p.large-p.text-center p.large-p.text-center
| You don't have an email id associated to this account. | You don't have an email id associated to this account.
.col-xs-12 .col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/email-update') a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/update-email')
i.fa.fa-envelope i.fa.fa-envelope
| Update my Email | Update my Email

View File

@ -8,7 +8,7 @@ block content
span.ion-close-circled#flash-close span.ion-close-circled#flash-close
#flash-content #flash-content
h2.text-center Update your email address here: h2.text-center Update your email address here:
form.form-horizontal.email-update(method='POST', action='/api/users/#{user.id}/update-email', name="updateEmailForm") form.form-horizontal.update-email(method='POST', action='/api/users/#{user.id}/update-email', name="updateEmailForm")
.row .row
.col-sm-6.col-sm-offset-3 .col-sm-6.col-sm-offset-3
input(type='hidden', name='_csrf', value=_csrf) input(type='hidden', name='_csrf', value=_csrf)