diff --git a/app/controllers/users/users.authentication.server.controller.js b/app/controllers/users/users.authentication.server.controller.js index a912157a..9558ed97 100644 --- a/app/controllers/users/users.authentication.server.controller.js +++ b/app/controllers/users/users.authentication.server.controller.js @@ -95,4 +95,112 @@ exports.oauthCallback = function(strategy) { }); })(req, res, next); }; +}; + +/** + * Helper function to save or update a OAuth user profile + */ +exports.saveOAuthUserProfile = function(req, providerUserProfile, done) { + if (!req.user) { + // Define a search query fields + var searchMainProviderIdentifierField = 'providerData.' + providerUserProfile.providerIdentifierField; + var searchAdditionalProviderIdentifierField = 'additionalProvidersData.' + providerUserProfile.provider + '.' + providerUserProfile.providerIdentifierField; + + // Define main provider search query + var mainProviderSearchQuery = {}; + mainProviderSearchQuery.provider = providerUserProfile.provider; + mainProviderSearchQuery[searchMainProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; + + // Define additional provider search query + var additionalProviderSearchQuery = {}; + additionalProviderSearchQuery[searchAdditionalProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; + + // Define a search query to find existing user with current provider profile + var searchQuery = { + $or: [mainProviderSearchQuery, additionalProviderSearchQuery] + }; + + User.findOne(searchQuery, function(err, user) { + if (err) { + return done(err); + } else { + if (!user) { + var possibleUsername = providerUserProfile.username || ((providerUserProfile.email) ? providerUserProfile.email.split('@')[0] : ''); + + User.findUniqueUsername(possibleUsername, null, function(availableUsername) { + user = new User({ + firstName: providerUserProfile.firstName, + lastName: providerUserProfile.lastName, + username: availableUsername, + displayName: providerUserProfile.displayName, + email: providerUserProfile.email, + provider: providerUserProfile.provider, + providerData: providerUserProfile.providerData + }); + + // And save the user + user.save(function(err) { + return done(err, user); + }); + }); + } else { + return done(err, user); + } + } + }); + } else { + // User is already logged in, join the provider data to the existing user + var user = req.user; + + // Check if user exists, is not signed in using this provider, and doesn't have that provider data already configured + if (user.provider !== providerUserProfile.provider && (!user.additionalProvidersData || !user.additionalProvidersData[providerUserProfile.provider])) { + // Add the provider data to the additional provider data field + if (!user.additionalProvidersData) user.additionalProvidersData = {}; + user.additionalProvidersData[providerUserProfile.provider] = providerUserProfile.providerData; + + // Then tell mongoose that we've updated the additionalProvidersData field + user.markModified('additionalProvidersData'); + + // And save the user + user.save(function(err) { + return done(err, user, '/#!/settings/accounts'); + }); + } else { + return done(new Error('User is already connected using this provider'), user); + } + } +}; + +/** + * Remove OAuth provider + */ +exports.removeOAuthProvider = function(req, res, next) { + var user = req.user; + var provider = req.param('provider'); + + if (user && provider) { + // Delete the additional provider + if (user.additionalProvidersData[provider]) { + delete user.additionalProvidersData[provider]; + + // Then tell mongoose that we've updated the additionalProvidersData field + user.markModified('additionalProvidersData'); + } + + user.save(function(err) { + if (err) { + return res.status(400).send({ + message: errorHandler.getErrorMessage(err) + }); + } else { + req.login(user, function(err) { + if (err) { + res.status(400).send(err); + } else { + res.jsonp(user); + } + }); + } + }); + } }; \ No newline at end of file diff --git a/app/controllers/users/users.profile.server.controller.js b/app/controllers/users/users.profile.server.controller.js index 3fcf730f..ee902cc1 100644 --- a/app/controllers/users/users.profile.server.controller.js +++ b/app/controllers/users/users.profile.server.controller.js @@ -53,112 +53,4 @@ exports.update = function(req, res) { */ exports.me = function(req, res) { res.jsonp(req.user || null); -}; - -/** - * Helper function to save or update a OAuth user profile - */ -exports.saveOAuthUserProfile = function(req, providerUserProfile, done) { - if (!req.user) { - // Define a search query fields - var searchMainProviderIdentifierField = 'providerData.' + providerUserProfile.providerIdentifierField; - var searchAdditionalProviderIdentifierField = 'additionalProvidersData.' + providerUserProfile.provider + '.' + providerUserProfile.providerIdentifierField; - - // Define main provider search query - var mainProviderSearchQuery = {}; - mainProviderSearchQuery.provider = providerUserProfile.provider; - mainProviderSearchQuery[searchMainProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; - - // Define additional provider search query - var additionalProviderSearchQuery = {}; - additionalProviderSearchQuery[searchAdditionalProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; - - // Define a search query to find existing user with current provider profile - var searchQuery = { - $or: [mainProviderSearchQuery, additionalProviderSearchQuery] - }; - - User.findOne(searchQuery, function(err, user) { - if (err) { - return done(err); - } else { - if (!user) { - var possibleUsername = providerUserProfile.username || ((providerUserProfile.email) ? providerUserProfile.email.split('@')[0] : ''); - - User.findUniqueUsername(possibleUsername, null, function(availableUsername) { - user = new User({ - firstName: providerUserProfile.firstName, - lastName: providerUserProfile.lastName, - username: availableUsername, - displayName: providerUserProfile.displayName, - email: providerUserProfile.email, - provider: providerUserProfile.provider, - providerData: providerUserProfile.providerData - }); - - // And save the user - user.save(function(err) { - return done(err, user); - }); - }); - } else { - return done(err, user); - } - } - }); - } else { - // User is already logged in, join the provider data to the existing user - var user = req.user; - - // Check if user exists, is not signed in using this provider, and doesn't have that provider data already configured - if (user.provider !== providerUserProfile.provider && (!user.additionalProvidersData || !user.additionalProvidersData[providerUserProfile.provider])) { - // Add the provider data to the additional provider data field - if (!user.additionalProvidersData) user.additionalProvidersData = {}; - user.additionalProvidersData[providerUserProfile.provider] = providerUserProfile.providerData; - - // Then tell mongoose that we've updated the additionalProvidersData field - user.markModified('additionalProvidersData'); - - // And save the user - user.save(function(err) { - return done(err, user, '/#!/settings/accounts'); - }); - } else { - return done(new Error('User is already connected using this provider'), user); - } - } -}; - -/** - * Remove OAuth provider - */ -exports.removeOAuthProvider = function(req, res, next) { - var user = req.user; - var provider = req.param('provider'); - - if (user && provider) { - // Delete the additional provider - if (user.additionalProvidersData[provider]) { - delete user.additionalProvidersData[provider]; - - // Then tell mongoose that we've updated the additionalProvidersData field - user.markModified('additionalProvidersData'); - } - - user.save(function(err) { - if (err) { - return res.status(400).send({ - message: errorHandler.getErrorMessage(err) - }); - } else { - req.login(user, function(err) { - if (err) { - res.status(400).send(err); - } else { - res.jsonp(user); - } - }); - } - }); - } }; \ No newline at end of file diff --git a/app/routes/users.server.routes.js b/app/routes/users.server.routes.js index 4ddb7394..929a88a2 100644 --- a/app/routes/users.server.routes.js +++ b/app/routes/users.server.routes.js @@ -47,6 +47,10 @@ module.exports = function(app) { // Setting the linkedin oauth routes app.route('/auth/linkedin').get(passport.authenticate('linkedin')); app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin')); + + // Setting the github oauth routes + app.route('/auth/github').get(passport.authenticate('github')); + app.route('/auth/github/callback').get(users.oauthCallback('github')); // Finish by binding the user middleware app.param('userId', users.userByID); diff --git a/config/env/development.js b/config/env/development.js index 51401116..3a3d0173 100644 --- a/config/env/development.js +++ b/config/env/development.js @@ -25,6 +25,11 @@ module.exports = { clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET', callbackURL: 'http://localhost:3000/auth/linkedin/callback' }, + github: { + clientID: process.env.GITHUB_ID || 'APP_ID', + clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET', + callbackURL: 'http://localhost:3000/auth/github/callback' + }, mailer: { from: process.env.MAILER_FROM || 'MAILER_FROM', options: { diff --git a/config/env/production.js b/config/env/production.js index 6a2bf895..5461d5f9 100644 --- a/config/env/production.js +++ b/config/env/production.js @@ -40,6 +40,11 @@ module.exports = { clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET', callbackURL: 'http://localhost:3000/auth/linkedin/callback' }, + github: { + clientID: process.env.GITHUB_ID || 'APP_ID', + clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET', + callbackURL: 'http://localhost:3000/auth/github/callback' + }, mailer: { from: process.env.MAILER_FROM || 'MAILER_FROM', options: { diff --git a/config/env/test.js b/config/env/test.js index 060d6751..927a1d56 100644 --- a/config/env/test.js +++ b/config/env/test.js @@ -26,6 +26,11 @@ module.exports = { clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET', callbackURL: 'http://localhost:3000/auth/linkedin/callback' }, + github: { + clientID: process.env.GITHUB_ID || 'APP_ID', + clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET', + callbackURL: 'http://localhost:3000/auth/github/callback' + }, mailer: { from: process.env.MAILER_FROM || 'MAILER_FROM', options: { diff --git a/config/strategies/github.js b/config/strategies/github.js new file mode 100644 index 00000000..eb1cfe76 --- /dev/null +++ b/config/strategies/github.js @@ -0,0 +1,40 @@ +'use strict'; + +/** + * Module dependencies. + */ +var passport = require('passport'), + url = require('url'), + GithubStrategy = require('passport-github').Strategy, + config = require('../config'), + users = require('../../app/controllers/users'); + +module.exports = function() { + // Use github strategy + passport.use(new GithubStrategy({ + clientID: config.github.clientID, + clientSecret: config.github.clientSecret, + callbackURL: config.github.callbackURL, + passReqToCallback: true + }, + function(req, accessToken, refreshToken, profile, done) { + // Set the provider data and include tokens + var providerData = profile._json; + providerData.accessToken = accessToken; + providerData.refreshToken = refreshToken; + + // Create the user OAuth profile + var providerUserProfile = { + displayName: profile.displayName, + email: profile.emails[0].value, + username: profile.username, + provider: 'github', + providerIdentifierField: 'id', + providerData: providerData + }; + + // Save the user OAuth profile + users.saveOAuthUserProfile(req, providerUserProfile, done); + } + )); +}; \ No newline at end of file diff --git a/package.json b/package.json index d90f4e9e..dbf3c636 100755 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "passport-twitter": "~1.0.2", "passport-linkedin": "~0.1.3", "passport-google-oauth": "~0.1.5", + "passport-github": "~0.1.5", "lodash": "~2.4.1", "forever": "~0.11.0", "bower": "~1.3.8", diff --git a/public/modules/core/services/menus.client.service.js b/public/modules/core/services/menus.client.service.js index 27402617..d2366d1d 100644 --- a/public/modules/core/services/menus.client.service.js +++ b/public/modules/core/services/menus.client.service.js @@ -5,7 +5,7 @@ angular.module('core').service('Menus', [ function() { // Define a set of default roles - this.defaultRoles = ['user']; + this.defaultRoles = ['*']; // Define the menus object this.menus = {}; @@ -13,10 +13,14 @@ angular.module('core').service('Menus', [ // A private function for rendering decision var shouldRender = function(user) { if (user) { - for (var userRoleIndex in user.roles) { - for (var roleIndex in this.roles) { - if (this.roles[roleIndex] === user.roles[userRoleIndex]) { - return true; + if (!!~this.roles.indexOf('*')) { + return true; + } else { + for (var userRoleIndex in user.roles) { + for (var roleIndex in this.roles) { + if (this.roles[roleIndex] === user.roles[userRoleIndex]) { + return true; + } } } } @@ -87,7 +91,7 @@ angular.module('core').service('Menus', [ menuItemClass: menuItemType, uiRoute: menuItemUIRoute || ('/' + menuItemURL), isPublic: ((isPublic === null || typeof isPublic === 'undefined') ? this.menus[menuId].isPublic : isPublic), - roles: roles || this.defaultRoles, + roles: ((roles === null || typeof roles === 'undefined') ? this.menus[menuId].roles : roles), position: position || 0, items: [], shouldRender: shouldRender @@ -111,7 +115,7 @@ angular.module('core').service('Menus', [ link: menuItemURL, uiRoute: menuItemUIRoute || ('/' + menuItemURL), isPublic: ((isPublic === null || typeof isPublic === 'undefined') ? this.menus[menuId].items[itemIndex].isPublic : isPublic), - roles: roles || this.defaultRoles, + roles: ((roles === null || typeof roles === 'undefined') ? this.menus[menuId].items[itemIndex].roles : roles), position: position || 0, shouldRender: shouldRender }); diff --git a/public/modules/users/img/buttons/github.png b/public/modules/users/img/buttons/github.png new file mode 100644 index 00000000..6ff6672f Binary files /dev/null and b/public/modules/users/img/buttons/github.png differ diff --git a/public/modules/users/views/authentication/signin.client.view.html b/public/modules/users/views/authentication/signin.client.view.html index 4b7db025..1a1768ef 100644 --- a/public/modules/users/views/authentication/signin.client.view.html +++ b/public/modules/users/views/authentication/signin.client.view.html @@ -13,6 +13,9 @@ + + +

Or with your account

@@ -30,7 +33,7 @@   or  Sign up
-
+
Forgot your password?
@@ -39,4 +42,4 @@
- + \ No newline at end of file diff --git a/public/modules/users/views/authentication/signup.client.view.html b/public/modules/users/views/authentication/signup.client.view.html index 1383ee4f..e2051760 100644 --- a/public/modules/users/views/authentication/signup.client.view.html +++ b/public/modules/users/views/authentication/signup.client.view.html @@ -13,10 +13,13 @@ + + +

Or with your email

-
+
@@ -48,4 +51,4 @@
- + \ No newline at end of file diff --git a/public/modules/users/views/settings/social-accounts.client.view.html b/public/modules/users/views/settings/social-accounts.client.view.html index ffc1c8f0..4712ee09 100644 --- a/public/modules/users/views/settings/social-accounts.client.view.html +++ b/public/modules/users/views/settings/social-accounts.client.view.html @@ -22,5 +22,8 @@ + + + \ No newline at end of file