Fix menu service defaults

This commit is contained in:
Amos Haviv
2014-08-05 15:35:49 +03:00
13 changed files with 192 additions and 119 deletions

View File

@@ -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);
}
});
}
});
}
};

View File

@@ -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);
}
});
}
});
}
};

View File

@@ -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);

View File

@@ -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: {

View File

@@ -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: {

5
config/env/test.js vendored
View File

@@ -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: {

View File

@@ -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);
}
));
};

View File

@@ -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",

View File

@@ -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
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -13,6 +13,9 @@
<a href="/auth/linkedin" class="undecorated-link">
<img src="/modules/users/img/buttons/linkedin.png">
</a>
<a href="/auth/github" class="undecorated-link">
<img src="/modules/users/img/buttons/github.png">
</a>
</div>
<h3 class="col-md-12 text-center">Or with your account</h3>
<div class="col-xs-offset-2 col-xs-8 col-md-offset-5 col-md-2">
@@ -30,7 +33,7 @@
<button type="submit" class="btn btn-primary">Sign in</button>&nbsp; or&nbsp;
<a href="/#!/signup">Sign up</a>
</div>
<div class"forgot-password">
<div class "forgot-password">
<a href="/#!/password/forgot">Forgot your password?</a>
</div>
<div data-ng-show="error" class="text-center text-danger">
@@ -39,4 +42,4 @@
</fieldset>
</form>
</div>
</section>
</section>

View File

@@ -13,10 +13,13 @@
<a href="/auth/linkedin" class="undecorated-link">
<img src="/modules/users/img/buttons/linkedin.png">
</a>
<a href="/auth/github" class="undecorated-link">
<img src="/modules/users/img/buttons/github.png">
</a>
</div>
<h3 class="col-md-12 text-center">Or with your email</h3>
<div class="col-xs-offset-2 col-xs-8 col-md-offset-5 col-md-2">
<form name="userForm" data-ng-submit="signup()" class="signin form-horizontal" novalidate autocomplete="off">
<form name="userForm" data-ng-submit="signup()" class="signin form-horizontal" novalidate autocomplete="off">
<fieldset>
<div class="form-group">
<label for="firstName">First Name</label>
@@ -48,4 +51,4 @@
</fieldset>
</form>
</div>
</section>
</section>

View File

@@ -22,5 +22,8 @@
<a href="/auth/linkedin" data-ng-hide="isConnectedSocialAccount('linkedin')" class="undecorated-link">
<img src="/modules/users/img/buttons/linkedin.png">
</a>
<a href="/auth/github" data-ng-hide="isConnectedSocialAccount('github')" class="undecorated-link">
<img src="/modules/users/img/buttons/github.png">
</a>
</div>
</section>