From 00f3940d8f82db5dceafd812d62cb4dc82751db7 Mon Sep 17 00:00:00 2001 From: Kentaro Wakayama Date: Wed, 9 Apr 2014 10:10:22 +0200 Subject: [PATCH 1/2] Add joining of multiple accounts --- app/controllers/users.js | 94 +++++++++++++++++++++++++++++++++++ app/models/user.js | 7 ++- config/strategies/facebook.js | 45 ++++++----------- config/strategies/google.js | 42 +++++----------- config/strategies/linkedin.js | 41 +++++---------- config/strategies/twitter.js | 39 ++++----------- 6 files changed, 150 insertions(+), 118 deletions(-) diff --git a/app/controllers/users.js b/app/controllers/users.js index e2ff8f4b99..407b6faa4e 100755 --- a/app/controllers/users.js +++ b/app/controllers/users.js @@ -247,4 +247,98 @@ exports.hasAuthorization = function(req, res, next) { } next(); +}; + +/** + * Helper function to save or update a user. + * When the user is logged in, it joins the user data to the existing one. + * Otherwise it creates a new user. + * + * @author Kentaro Wakayama + * + * @date 2014-04-09 + * + * @param {Object} req This is the request object which contains the user when he is signed in. + * @param {String} token This is the accesstoken. + * @param {String} tokenSecret This is the refreshtoken. + * @param {Object} profile This is the user profile of the current provider. + * @param {Function} done Callback to supply Passport with the user that authenticated. + * + * @param {Object} providerData This Object contains all data which is specific for the provider + * @param {String} providerData.provider This is the passport provider name. + * @param {String} providerData.idKey This is the Key / Attribute name for saving / retrieving the provider id. + * @param {String} providerData.name This is the user's name. + * @param {String} [providerData.email] This is the user's email. + * @param {String} providerData.username This is the user's username. + * + * @return {[type]} [description] + */ +exports.saveOrUpdate = function(req, token, tokenSecret, profile, done, providerData) { + var provider = providerData.provider; + var idKey = providerData.idKey; + var searchProviderKey = provider + '.' + idKey; + var searchObject = {}; + searchObject[searchProviderKey] = profile.id; + + if (!req.user) { + // no user active, this is a fresh login + User.findOne(searchObject, function(err, user) { + if (err) { + return done(err); + } + if (!user) { + + var possibleUsername = ''; + if (providerData.email) { + possibleUsername = providerData.email.split('@')[0]; + } else { + possibleUsername = profile.username; + } + + User.findUniqueUsername(possibleUsername, null, function(availableUsername) { + user = new User({ + firstName: providerData.firstName, + lastName: providerData.lastName, + username: availableUsername, + displayName: providerData.displayName, + email: providerData.email, + provider: provider, + }); + + user[provider] = profile._json; + user[provider].token = token; + user[provider].tokenSecret = tokenSecret; + user.save(function(err) { + if (err) console.log(err); + return done(err, user); + }); + }); + } else { + user[provider].token = token; + user[provider].tokenSecret = tokenSecret; + user.save(function(err) { + if (err) console.log(err); + return done(err, user); + }); + } + }); + } else { + // a user is already logged in, join the provider data to the existing user. + User.findById( req.user._id, function(err, user) { + if (err) { + return done(err); + } + if (user) { + user[provider] = profile._json; + user[provider].token = token; + user[provider].tokenSecret = tokenSecret; + user.save(function(err) { + if (err) console.log(err); + return done(err, user); + }); + } else { + return done(err, user); + } + }); + } }; \ No newline at end of file diff --git a/app/models/user.js b/app/models/user.js index 30d12bb12d..2eebcbdb53 100755 --- a/app/models/user.js +++ b/app/models/user.js @@ -73,7 +73,12 @@ var UserSchema = new Schema({ created: { type: Date, default: Date.now - } + }, + facebook: {}, + twitter: {}, + github: {}, + google: {}, + linkedin: {} }); /** diff --git a/config/strategies/facebook.js b/config/strategies/facebook.js index 4802a46f1f..80f684b7f5 100644 --- a/config/strategies/facebook.js +++ b/config/strategies/facebook.js @@ -3,7 +3,8 @@ var passport = require('passport'), FacebookStrategy = require('passport-facebook').Strategy, User = require('mongoose').model('User'), - config = require('../config'); + config = require('../config'), + users = require('../../app/controllers/users'); module.exports = function() { // Use facebook strategy @@ -14,36 +15,18 @@ module.exports = function() { passReqToCallback: true }, function(req, accessToken, refreshToken, profile, done) { - if (req.user) { - return done(new Error('User is already signed in'), req.user); - } else { - User.findOne({ - 'provider': 'facebook', - 'providerData.id': profile.id - }, function(err, user) { - if (err) { - return done(err); - } - if (!user) { - User.findUniqueUsername(profile.username, null, function(availableUsername) { - user = new User({ - firstName: profile.name.givenName, - lastName: profile.name.familyName, - displayName: profile.displayName, - email: profile.emails[0].value, - username: availableUsername, - provider: 'facebook', - providerData: profile._json - }); - user.save(function(err) { - return done(err, user); - }); - }); - } else { - return done(err, user); - } - }); - } + + var providerData = { + firstName: profile.name.givenName, + lastName: profile.name.familyName, + displayName: profile.displayName, + provider: 'facebook', + idKey: 'id', + email: profile.emails[0].value, + username: profile.username, + }; + users.saveOrUpdate(req, accessToken, refreshToken, profile, done, providerData); + } )); }; \ No newline at end of file diff --git a/config/strategies/google.js b/config/strategies/google.js index d86e025559..fcbac8b220 100644 --- a/config/strategies/google.js +++ b/config/strategies/google.js @@ -3,7 +3,8 @@ var passport = require('passport'), GoogleStrategy = require('passport-google-oauth').OAuth2Strategy, User = require('mongoose').model('User'), - config = require('../config'); + config = require('../config'), + users = require('../../app/controllers/users'); module.exports = function() { // Use google strategy @@ -14,35 +15,18 @@ module.exports = function() { passReqToCallback: true }, function(req, accessToken, refreshToken, profile, done) { - if (req.user) { - return done(new Error('User is already signed in'), req.user); - } else { - User.findOne({ - 'provider': 'google', - 'providerData.id': profile.id - }, function(err, user) { - if (!user) { - var possibleUsername = profile.emails[0].value.split('@')[0]; - User.findUniqueUsername(possibleUsername, null, function(availableUsername) { - user = new User({ - firstName: profile.name.givenName, - lastName: profile.name.familyName, - displayName: profile.displayName, - email: profile.emails[0].value, - username: availableUsername, - provider: 'google', - providerData: profile._json - }); - user.save(function(err) { - return done(err, user); - }); - }); - } else { - return done(err, user); - } - }); - } + var providerData = { + firstName: profile.name.givenName, + lastName: profile.name.familyName, + displayName: profile.displayName, + provider: 'google', + idKey: 'id', + email: profile.emails[0].value, + username: profile.username + }; + users.saveOrUpdate(req, accessToken, refreshToken, profile, done, providerData); + } )); }; \ No newline at end of file diff --git a/config/strategies/linkedin.js b/config/strategies/linkedin.js index cbb460a62b..80994fbfb4 100644 --- a/config/strategies/linkedin.js +++ b/config/strategies/linkedin.js @@ -3,7 +3,8 @@ var passport = require('passport'), LinkedInStrategy = require('passport-linkedin').Strategy, User = require('mongoose').model('User'), - config = require('../config'); + config = require('../config'), + users = require('../../app/controllers/users'); module.exports = function() { // Use linkedin strategy @@ -15,35 +16,17 @@ module.exports = function() { profileFields: ['id', 'first-name', 'last-name', 'email-address'] }, function(req, accessToken, refreshToken, profile, done) { - if (req.user) { - return done(new Error('User is already signed in'), req.user); - } else { - User.findOne({ - 'provider': 'linkedin', - 'providerData.id': profile.id - }, function(err, user) { - if (!user) { - var possibleUsername = profile.emails[0].value.split('@')[0]; - User.findUniqueUsername(possibleUsername, null, function(availableUsername) { - user = new User({ - firstName: profile.name.givenName, - lastName: profile.name.familyName, - displayName: profile.displayName, - email: profile.emails[0].value, - username: availableUsername, - provider: 'linkedin', - providerData: profile._json - }); - user.save(function(err) { - return done(err, user); - }); - }); - } else { - return done(err, user); - } - }); - } + var providerData = { + firstName: profile.name.givenName, + lastName: profile.name.familyName, + displayName: profile.displayName, + provider: 'linkedin', + idKey: 'id', + username: profile.displayName, + }; + users.saveOrUpdate(req, accessToken, refreshToken, profile, done, providerData); + } )); }; \ No newline at end of file diff --git a/config/strategies/twitter.js b/config/strategies/twitter.js index 62301d4458..44e7b4d4bb 100644 --- a/config/strategies/twitter.js +++ b/config/strategies/twitter.js @@ -3,7 +3,8 @@ var passport = require('passport'), TwitterStrategy = require('passport-twitter').Strategy, User = require('mongoose').model('User'), - config = require('../config'); + config = require('../config'), + users = require('../../app/controllers/users'); module.exports = function() { // Use twitter strategy @@ -14,33 +15,15 @@ module.exports = function() { passReqToCallback: true }, function(req, token, tokenSecret, profile, done) { - if (req.user) { - return done(new Error('User is already signed in'), req.user); - } else { - User.findOne({ - 'provider': 'twitter', - 'providerData.id_str': profile.id - }, function(err, user) { - if (err) { - return done(err); - } - if (!user) { - User.findUniqueUsername(profile.username, null, function(availableUsername) { - user = new User({ - displayName: profile.displayName, - username: availableUsername, - provider: 'twitter', - providerData: profile._json - }); - user.save(function(err) { - return done(err, user); - }); - }); - } else { - return done(err, user); - } - }); - } + + var providerData = { + displayName: profile.displayName, + provider: 'twitter', + idKey: 'id_str', + username: profile.username, + }; + + users.saveOrUpdate(req, token, tokenSecret, profile, done, providerData); } )); }; \ No newline at end of file From 56b0c3112015ed7695e95460e5aa1df0f022a032 Mon Sep 17 00:00:00 2001 From: Kentaro Wakayama Date: Wed, 9 Apr 2014 10:11:24 +0200 Subject: [PATCH 2/2] Add account buttons to join more accounts --- public/modules/users/views/settings/profile.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/public/modules/users/views/settings/profile.html b/public/modules/users/views/settings/profile.html index 5006dc9f9e..aae41fff9f 100644 --- a/public/modules/users/views/settings/profile.html +++ b/public/modules/users/views/settings/profile.html @@ -31,4 +31,19 @@

Edit your profile

+

Add an other Account

+ \ No newline at end of file