Changed all the indents to the spaces(tab size 4)

This commit is contained in:
Samuel Vijaykumar M
2014-05-14 16:05:15 +05:30
parent 95037207f8
commit 7cf1fc2adb
49 changed files with 1798 additions and 1548 deletions

View File

@@ -4,129 +4,129 @@
* Module dependencies.
*/
var mongoose = require('mongoose'),
Article = mongoose.model('Article'),
_ = require('lodash');
Article = mongoose.model('Article'),
_ = require('lodash');
/**
* Get the error message from error object
*/
var getErrorMessage = function(err) {
var message = '';
var message = '';
if (err.code) {
switch (err.code) {
case 11000:
case 11001:
message = 'Article already exists';
break;
default:
message = 'Something went wrong';
}
} else {
for (var errName in err.errors) {
if (err.errors[errName].message) message = err.errors[errName].message;
}
}
if (err.code) {
switch (err.code) {
case 11000:
case 11001:
message = 'Article already exists';
break;
default:
message = 'Something went wrong';
}
} else {
for (var errName in err.errors) {
if (err.errors[errName].message) message = err.errors[errName].message;
}
}
return message;
return message;
};
/**
* Create a article
*/
exports.create = function(req, res) {
var article = new Article(req.body);
article.user = req.user;
var article = new Article(req.body);
article.user = req.user;
article.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(article);
}
});
article.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(article);
}
});
};
/**
* Show the current article
*/
exports.read = function(req, res) {
res.jsonp(req.article);
res.jsonp(req.article);
};
/**
* Update a article
*/
exports.update = function(req, res) {
var article = req.article;
var article = req.article;
article = _.extend(article, req.body);
article = _.extend(article, req.body);
article.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(article);
}
});
article.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(article);
}
});
};
/**
* Delete an article
*/
exports.delete = function(req, res) {
var article = req.article;
var article = req.article;
article.remove(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(article);
}
});
article.remove(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(article);
}
});
};
/**
* List of Articles
*/
exports.list = function(req, res) {
Article.find().sort('-created').populate('user', 'displayName').exec(function(err, articles) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(articles);
}
});
Article.find().sort('-created').populate('user', 'displayName').exec(function(err, articles) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(articles);
}
});
};
/**
* Article middleware
*/
exports.articleByID = function(req, res, next, id) {
Article.findById(id).populate('user', 'displayName').exec(function(err, article) {
if (err) return next(err);
if (!article) return next(new Error('Failed to load article ' + id));
req.article = article;
next();
});
Article.findById(id).populate('user', 'displayName').exec(function(err, article) {
if (err) return next(err);
if (!article) return next(new Error('Failed to load article ' + id));
req.article = article;
next();
});
};
/**
* Article authorization middleware
*/
exports.hasAuthorization = function(req, res, next) {
if (req.article.user.id !== req.user.id) {
return res.send(403, {
message: 'User is not authorized'
});
}
next();
};
if (req.article.user.id !== req.user.id) {
return res.send(403, {
message: 'User is not authorized'
});
}
next();
};

View File

@@ -4,7 +4,7 @@
* Module dependencies.
*/
exports.index = function(req, res) {
res.render('index', {
user: req.user || null
});
};
res.render('index', {
user: req.user || null
});
};

View File

@@ -4,377 +4,377 @@
* Module dependencies.
*/
var mongoose = require('mongoose'),
passport = require('passport'),
User = mongoose.model('User'),
_ = require('lodash');
passport = require('passport'),
User = mongoose.model('User'),
_ = require('lodash');
/**
* Get the error message from error object
*/
var getErrorMessage = function(err) {
var message = '';
var message = '';
if (err.code) {
switch (err.code) {
case 11000:
case 11001:
message = 'Username already exists';
break;
default:
message = 'Something went wrong';
}
} else {
for (var errName in err.errors) {
if (err.errors[errName].message) message = err.errors[errName].message;
}
}
if (err.code) {
switch (err.code) {
case 11000:
case 11001:
message = 'Username already exists';
break;
default:
message = 'Something went wrong';
}
} else {
for (var errName in err.errors) {
if (err.errors[errName].message) message = err.errors[errName].message;
}
}
return message;
return message;
};
/**
* Signup
*/
exports.signup = function(req, res) {
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
// Init Variables
var user = new User(req.body);
var message = null;
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
// Add missing user fields
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
// Init Variables
var user = new User(req.body);
var message = null;
// Then save the user
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
// Add missing user fields
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
});
// Then save the user
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
});
};
/**
* Signin after passport authentication
*/
exports.signin = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err || !user) {
res.send(400, info);
} else {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
passport.authenticate('local', function(err, user, info) {
if (err || !user) {
res.send(400, info);
} else {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
})(req, res, next);
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
})(req, res, next);
};
/**
* Update user details
*/
exports.update = function(req, res) {
// Init Variables
var user = req.user;
var message = null;
// Init Variables
var user = req.user;
var message = null;
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
if (user) {
// Merge existing user
user = _.extend(user, req.body);
user.updated = Date.now();
user.displayName = user.firstName + ' ' + user.lastName;
if (user) {
// Merge existing user
user = _.extend(user, req.body);
user.updated = Date.now();
user.displayName = user.firstName + ' ' + user.lastName;
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
});
} else {
res.send(400, {
message: 'User is not signed in'
});
}
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
});
} else {
res.send(400, {
message: 'User is not signed in'
});
}
};
/**
* Change Password
*/
exports.changePassword = function(req, res, next) {
// Init Variables
var passwordDetails = req.body;
var message = null;
// Init Variables
var passwordDetails = req.body;
var message = null;
if (req.user) {
User.findById(req.user.id, function(err, user) {
if (!err && user) {
if (user.authenticate(passwordDetails.currentPassword)) {
if (passwordDetails.newPassword === passwordDetails.verifyPassword) {
user.password = passwordDetails.newPassword;
if (req.user) {
User.findById(req.user.id, function(err, user) {
if (!err && user) {
if (user.authenticate(passwordDetails.currentPassword)) {
if (passwordDetails.newPassword === passwordDetails.verifyPassword) {
user.password = passwordDetails.newPassword;
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.send({
message: 'Password changed successfully'
});
}
});
}
});
} else {
res.send(400, {
message: 'Passwords do not match'
});
}
} else {
res.send(400, {
message: 'Current password is incorrect'
});
}
} else {
res.send(400, {
message: 'User is not found'
});
}
});
} else {
res.send(400, {
message: 'User is not signed in'
});
}
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.send({
message: 'Password changed successfully'
});
}
});
}
});
} else {
res.send(400, {
message: 'Passwords do not match'
});
}
} else {
res.send(400, {
message: 'Current password is incorrect'
});
}
} else {
res.send(400, {
message: 'User is not found'
});
}
});
} else {
res.send(400, {
message: 'User is not signed in'
});
}
};
/**
* Signout
*/
exports.signout = function(req, res) {
req.logout();
res.redirect('/');
req.logout();
res.redirect('/');
};
/**
* Send User
*/
exports.me = function(req, res) {
res.jsonp(req.user || null);
res.jsonp(req.user || null);
};
/**
* OAuth callback
*/
exports.oauthCallback = function(strategy) {
return function(req, res, next) {
passport.authenticate(strategy, function(err, user, redirectURL) {
if (err || !user) {
return res.redirect('/#!/signin');
}
req.login(user, function(err) {
if (err) {
return res.redirect('/#!/signin');
}
return function(req, res, next) {
passport.authenticate(strategy, function(err, user, redirectURL) {
if (err || !user) {
return res.redirect('/#!/signin');
}
req.login(user, function(err) {
if (err) {
return res.redirect('/#!/signin');
}
return res.redirect(redirectURL || '/');
});
})(req, res, next);
};
return res.redirect(redirectURL || '/');
});
})(req, res, next);
};
};
/**
* User middleware
*/
exports.userByID = function(req, res, next, id) {
User.findOne({
_id: id
}).exec(function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + id));
req.profile = user;
next();
});
User.findOne({
_id: id
}).exec(function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + id));
req.profile = user;
next();
});
};
/**
* Require login routing middleware
*/
exports.requiresLogin = function(req, res, next) {
if (!req.isAuthenticated()) {
return res.send(401, {
message: 'User is not logged in'
});
}
if (!req.isAuthenticated()) {
return res.send(401, {
message: 'User is not logged in'
});
}
next();
next();
};
/**
* User authorizations routing middleware
*/
exports.hasAuthorization = function(roles) {
var _this = this;
var _this = this;
return function(req, res, next) {
_this.requiresLogin(req, res, function() {
if (_.intersection(req.user.roles, roles).length) {
return next();
} else {
return res.send(403, {
message: 'User is not authorized'
});
}
});
};
return function(req, res, next) {
_this.requiresLogin(req, res, function() {
if (_.intersection(req.user.roles, roles).length) {
return next();
} else {
return res.send(403, {
message: 'User is not authorized'
});
}
});
};
};
/**
* 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;
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 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 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]
};
// 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.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
});
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
User.findById(req.user.id, function(err, user) {
if (err) {
return done(err);
} else {
// Check if user exists, is not signed in using this provider, and doesn't have that provider data already configured
if (user && 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;
// 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
User.findById(req.user.id, function(err, user) {
if (err) {
return done(err);
} else {
// Check if user exists, is not signed in using this provider, and doesn't have that provider data already configured
if (user && 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');
// 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(err, user);
}
}
});
}
// And save the user
user.save(function(err) {
return done(err, user, '/#!/settings/accounts');
});
} else {
return done(err, user);
}
}
});
}
};
/**
* Remove OAuth provider
*/
exports.removeOAuthProvider = function(req, res, next) {
var user = req.user;
var provider = req.param('provider');
var user = req.user;
var provider = req.param('provider');
if (user && provider) {
// Delete the additional provider
if (user.additionalProvidersData[provider]) {
delete user.additionalProvidersData[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');
}
// Then tell mongoose that we've updated the additionalProvidersData field
user.markModified('additionalProvidersData');
}
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
});
}
};
user.save(function(err) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.send(400, err);
} else {
res.jsonp(user);
}
});
}
});
}
};

View File

@@ -4,31 +4,31 @@
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
Schema = mongoose.Schema;
/**
* Article Schema
*/
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Article', ArticleSchema);
mongoose.model('Article', ArticleSchema);

View File

@@ -4,136 +4,136 @@
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
crypto = require('crypto');
Schema = mongoose.Schema,
crypto = require('crypto');
/**
* A Validation function for local strategy properties
*/
var validateLocalStrategyProperty = function(property) {
return ((this.provider !== 'local' && !this.updated) || property.length);
return ((this.provider !== 'local' && !this.updated) || property.length);
};
/**
* A Validation function for local strategy password
*/
var validateLocalStrategyPassword = function(password) {
return (this.provider !== 'local' || (password && password.length > 6));
return (this.provider !== 'local' || (password && password.length > 6));
};
/**
* User Schema
*/
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\@.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: true,
required: 'Please fill in a username',
trim: true
},
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
}
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\@.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: true,
required: 'Please fill in a username',
trim: true
},
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
}
});
/**
* Hook a pre save method to hash the password
*/
UserSchema.pre('save', function(next) {
if (this.password && this.password.length > 6) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
if (this.password && this.password.length > 6) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
next();
next();
});
/**
* Create instance method for hashing a password
*/
UserSchema.methods.hashPassword = function(password) {
if (this.salt && password) {
return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
} else {
return password;
}
if (this.salt && password) {
return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
} else {
return password;
}
};
/**
* Create instance method for authenticating user
*/
UserSchema.methods.authenticate = function(password) {
return this.password === this.hashPassword(password);
return this.password === this.hashPassword(password);
};
/**
* Find possible not used username
*/
UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
var _this = this;
var possibleUsername = username + (suffix || '');
var _this = this;
var possibleUsername = username + (suffix || '');
_this.findOne({
username: possibleUsername
}, function(err, user) {
if (!err) {
if (!user) {
callback(possibleUsername);
} else {
return _this.findUniqueUsername(username, (suffix || 0) + 1, callback);
}
} else {
callback(null);
}
});
_this.findOne({
username: possibleUsername
}, function(err, user) {
if (!err) {
if (!user) {
callback(possibleUsername);
} else {
return _this.findUniqueUsername(username, (suffix || 0) + 1, callback);
}
} else {
callback(null);
}
});
};
mongoose.model('User', UserSchema);
mongoose.model('User', UserSchema);

View File

@@ -4,19 +4,19 @@
* Module dependencies.
*/
var users = require('../../app/controllers/users'),
articles = require('../../app/controllers/articles');
articles = require('../../app/controllers/articles');
module.exports = function(app) {
// Article Routes
app.route('/articles')
.get(articles.list)
.post(users.requiresLogin, articles.create);
app.route('/articles/:articleId')
.get(articles.read)
.put(users.requiresLogin, articles.hasAuthorization, articles.update)
.delete(users.requiresLogin, articles.hasAuthorization, articles.delete);
// Article Routes
app.route('/articles')
.get(articles.list)
.post(users.requiresLogin, articles.create);
// Finish by binding the article middleware
app.param('articleId', articles.articleByID);
};
app.route('/articles/:articleId')
.get(articles.read)
.put(users.requiresLogin, articles.hasAuthorization, articles.update)
.delete(users.requiresLogin, articles.hasAuthorization, articles.delete);
// Finish by binding the article middleware
app.param('articleId', articles.articleByID);
};

View File

@@ -1,7 +1,7 @@
'use strict';
module.exports = function(app) {
// Root routing
var core = require('../../app/controllers/core');
app.route('/').get(core.index);
};
// Root routing
var core = require('../../app/controllers/core');
app.route('/').get(core.index);
};

View File

@@ -6,41 +6,41 @@
var passport = require('passport');
module.exports = function(app) {
// User Routes
var users = require('../../app/controllers/users');
app.route('/users/me').get(users.me);
app.route('/users').put(users.update);
app.route('/users/password').post(users.changePassword);
app.route('/users/accounts').delete(users.removeOAuthProvider);
// User Routes
var users = require('../../app/controllers/users');
app.route('/users/me').get(users.me);
app.route('/users').put(users.update);
app.route('/users/password').post(users.changePassword);
app.route('/users/accounts').delete(users.removeOAuthProvider);
// Setting up the users api
app.route('/auth/signup').post(users.signup);
app.route('/auth/signin').post(users.signin);
app.route('/auth/signout').get(users.signout);
// Setting up the users api
app.route('/auth/signup').post(users.signup);
app.route('/auth/signin').post(users.signin);
app.route('/auth/signout').get(users.signout);
// Setting the facebook oauth routes
app.route('/auth/facebook').get(passport.authenticate('facebook', {
scope: ['email']
}));
app.route('/auth/facebook/callback').get(users.oauthCallback('facebook'));
// Setting the facebook oauth routes
app.route('/auth/facebook').get(passport.authenticate('facebook', {
scope: ['email']
}));
app.route('/auth/facebook/callback').get(users.oauthCallback('facebook'));
// Setting the twitter oauth routes
app.route('/auth/twitter').get(passport.authenticate('twitter'));
app.route('/auth/twitter/callback').get(users.oauthCallback('twitter'));
// Setting the twitter oauth routes
app.route('/auth/twitter').get(passport.authenticate('twitter'));
app.route('/auth/twitter/callback').get(users.oauthCallback('twitter'));
// Setting the google oauth routes
app.route('/auth/google').get(passport.authenticate('google', {
scope: [
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email'
]
}));
app.route('/auth/google/callback').get(users.oauthCallback('google'));
// Setting the google oauth routes
app.route('/auth/google').get(passport.authenticate('google', {
scope: [
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email'
]
}));
app.route('/auth/google/callback').get(users.oauthCallback('google'));
// Setting the linkedin oauth routes
app.route('/auth/linkedin').get(passport.authenticate('linkedin'));
app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin'));
// Setting the linkedin oauth routes
app.route('/auth/linkedin').get(passport.authenticate('linkedin'));
app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin'));
// Finish by binding the user middleware
app.param('userId', users.userByID);
// Finish by binding the user middleware
app.param('userId', users.userByID);
};

View File

@@ -4,9 +4,9 @@
* Module dependencies.
*/
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Article = mongoose.model('Article');
mongoose = require('mongoose'),
User = mongoose.model('User'),
Article = mongoose.model('Article');
/**
* Globals
@@ -17,48 +17,48 @@ var user, article;
* Unit tests
*/
describe('Article Model Unit Tests:', function() {
beforeEach(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password'
});
beforeEach(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password'
});
user.save(function() {
article = new Article({
title: 'Article Title',
content: 'Article Content',
user: user
});
user.save(function() {
article = new Article({
title: 'Article Title',
content: 'Article Content',
user: user
});
done();
});
});
done();
});
});
describe('Method Save', function() {
it('should be able to save without problems', function(done) {
return article.save(function(err) {
should.not.exist(err);
done();
});
});
describe('Method Save', function() {
it('should be able to save without problems', function(done) {
return article.save(function(err) {
should.not.exist(err);
done();
});
});
it('should be able to show an error when try to save without title', function(done) {
article.title = '';
it('should be able to show an error when try to save without title', function(done) {
article.title = '';
return article.save(function(err) {
should.exist(err);
done();
});
});
});
return article.save(function(err) {
should.exist(err);
done();
});
});
});
afterEach(function(done) {
Article.remove().exec();
User.remove().exec();
done();
});
});
afterEach(function(done) {
Article.remove().exec();
User.remove().exec();
done();
});
});

View File

@@ -4,8 +4,8 @@
* Module dependencies.
*/
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User');
mongoose = require('mongoose'),
User = mongoose.model('User');
/**
* Globals
@@ -16,60 +16,60 @@ var user, user2;
* Unit tests
*/
describe('User Model Unit Tests:', function() {
before(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password',
provider: 'local'
});
user2 = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password',
provider: 'local'
});
before(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password',
provider: 'local'
});
user2 = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password',
provider: 'local'
});
done();
});
done();
});
describe('Method Save', function() {
it('should begin with no users', function(done) {
User.find({}, function(err, users) {
users.should.have.length(0);
done();
});
});
describe('Method Save', function() {
it('should begin with no users', function(done) {
User.find({}, function(err, users) {
users.should.have.length(0);
done();
});
});
it('should be able to save whithout problems', function(done) {
user.save(done);
});
it('should be able to save whithout problems', function(done) {
user.save(done);
});
it('should fail to save an existing user again', function(done) {
user.save();
return user2.save(function(err) {
should.exist(err);
done();
});
});
it('should fail to save an existing user again', function(done) {
user.save();
return user2.save(function(err) {
should.exist(err);
done();
});
});
it('should be able to show an error when try to save without first name', function(done) {
user.firstName = '';
return user.save(function(err) {
should.exist(err);
done();
});
});
});
it('should be able to show an error when try to save without first name', function(done) {
user.firstName = '';
return user.save(function(err) {
should.exist(err);
done();
});
});
});
after(function(done) {
User.remove().exec();
done();
});
});
after(function(done) {
User.remove().exec();
done();
});
});

View File

@@ -34,7 +34,7 @@ module.exports.getGlobbedFiles = function(globPatterns, removeRoot) {
});
} else if (_.isString(globPatterns)) {
if (urlRegex.test(globPatterns)) {
output.push(globPatterns);
output.push(globPatterns);
} else {
glob(globPatterns, {
sync: true
@@ -73,4 +73,4 @@ module.exports.getJavaScriptAssets = function(includeTests) {
module.exports.getCSSAssets = function() {
var output = this.getGlobbedFiles(this.assets.lib.css.concat(this.assets.css), 'public/');
return output;
};
};

76
config/env/all.js vendored
View File

@@ -1,42 +1,42 @@
'use strict';
module.exports = {
app: {
title: 'MEAN.JS',
description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
keywords: 'mongodb, express, angularjs, node.js, mongoose, passport'
},
port: process.env.PORT || 3000,
templateEngine: 'swig',
sessionSecret: 'MEAN',
sessionCollection: 'sessions',
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
],
js: [
'public/lib/angular/angular.js',
'public/lib/angular-resource/angular-resource.js',
'public/lib/angular-animate/angular-animate.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/angular-ui-utils/ui-utils.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.js'
]
},
css: [
'public/modules/**/css/*.css'
],
js: [
'public/config.js',
'public/application.js',
'public/modules/*/*.js',
'public/modules/*/*[!tests]*/*.js'
],
tests: [
'public/lib/angular-mocks/angular-mocks.js',
'public/modules/*/tests/*.js'
]
}
app: {
title: 'MEAN.JS',
description: 'Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js',
keywords: 'mongodb, express, angularjs, node.js, mongoose, passport'
},
port: process.env.PORT || 3000,
templateEngine: 'swig',
sessionSecret: 'MEAN',
sessionCollection: 'sessions',
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
],
js: [
'public/lib/angular/angular.js',
'public/lib/angular-resource/angular-resource.js',
'public/lib/angular-animate/angular-animate.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/angular-ui-utils/ui-utils.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.js'
]
},
css: [
'public/modules/**/css/*.css'
],
js: [
'public/config.js',
'public/application.js',
'public/modules/*/*.js',
'public/modules/*/*[!tests]*/*.js'
],
tests: [
'public/lib/angular-mocks/angular-mocks.js',
'public/modules/*/tests/*.js'
]
}
};

View File

@@ -1,28 +1,28 @@
'use strict';
module.exports = {
db: 'mongodb://localhost/mean-dev',
app: {
title: 'MEAN.JS - Development Environment'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
callbackURL: 'http://localhost:3000/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}
db: 'mongodb://localhost/mean-dev',
app: {
title: 'MEAN.JS - Development Environment'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
callbackURL: 'http://localhost:3000/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}
};

View File

@@ -1,43 +1,43 @@
'use strict';
module.exports = {
db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://localhost/mean',
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
],
js: [
'public/lib/angular/angular.min.js',
'public/lib/angular-resource/angular-resource.min.js',
'public/lib/angular-animate/angular-animate.min.js',
'public/lib/angular-ui-router/release/angular-ui-router.min.js',
'public/lib/angular-ui-utils/ui-utils.min.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
]
},
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
callbackURL: 'http://localhost:3000/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}
db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://localhost/mean',
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
],
js: [
'public/lib/angular/angular.min.js',
'public/lib/angular-resource/angular-resource.min.js',
'public/lib/angular-animate/angular-animate.min.js',
'public/lib/angular-ui-router/release/angular-ui-router.min.js',
'public/lib/angular-ui-utils/ui-utils.min.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
]
},
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
callbackURL: 'http://localhost:3000/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}
};

50
config/env/test.js vendored
View File

@@ -1,29 +1,29 @@
'use strict';
module.exports = {
db: 'mongodb://localhost/mean-test',
port: 3001,
app: {
title: 'MEAN.JS - Test Environment'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
callbackURL: 'http://localhost:3000/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}
db: 'mongodb://localhost/mean-test',
port: 3001,
app: {
title: 'MEAN.JS - Test Environment'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
callbackURL: 'http://localhost:3000/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
callbackURL: 'http://localhost:3000/auth/linkedin/callback'
}
};

View File

@@ -4,137 +4,137 @@
* Module dependencies.
*/
var express = require('express'),
morgan = require('morgan'),
bodyParser = require('body-parser'),
session = require('express-session'),
compress = require('compression'),
methodOverride = require('method-override'),
cookieParser = require('cookie-parser'),
helmet = require('helmet'),
passport = require('passport'),
mongoStore = require('connect-mongo')({
session: session
}),
flash = require('connect-flash'),
config = require('./config'),
consolidate = require('consolidate'),
path = require('path');
morgan = require('morgan'),
bodyParser = require('body-parser'),
session = require('express-session'),
compress = require('compression'),
methodOverride = require('method-override'),
cookieParser = require('cookie-parser'),
helmet = require('helmet'),
passport = require('passport'),
mongoStore = require('connect-mongo')({
session: session
}),
flash = require('connect-flash'),
config = require('./config'),
consolidate = require('consolidate'),
path = require('path');
module.exports = function(db) {
// Initialize express app
var app = express();
// Initialize express app
var app = express();
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
// Setting application local variables
app.locals.title = config.app.title;
app.locals.description = config.app.description;
app.locals.keywords = config.app.keywords;
app.locals.facebookAppId = config.facebook.clientID;
app.locals.jsFiles = config.getJavaScriptAssets();
app.locals.cssFiles = config.getCSSAssets();
// Setting application local variables
app.locals.title = config.app.title;
app.locals.description = config.app.description;
app.locals.keywords = config.app.keywords;
app.locals.facebookAppId = config.facebook.clientID;
app.locals.jsFiles = config.getJavaScriptAssets();
app.locals.cssFiles = config.getCSSAssets();
// Passing the request url to environment locals
app.use(function(req, res, next) {
res.locals.url = req.protocol + ':// ' + req.headers.host + req.url;
next();
});
// Passing the request url to environment locals
app.use(function(req, res, next) {
res.locals.url = req.protocol + ':// ' + req.headers.host + req.url;
next();
});
// Should be placed before express.static
app.use(compress({
filter: function(req, res) {
return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
},
level: 9
}));
// Should be placed before express.static
app.use(compress({
filter: function(req, res) {
return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
},
level: 9
}));
// Showing stack errors
app.set('showStackError', true);
// Showing stack errors
app.set('showStackError', true);
// Set swig as the template engine
app.engine('server.view.html', consolidate[config.templateEngine]);
// Set swig as the template engine
app.engine('server.view.html', consolidate[config.templateEngine]);
// Set views path and view engine
app.set('view engine', 'server.view.html');
app.set('views', './app/views');
// Set views path and view engine
app.set('view engine', 'server.view.html');
app.set('views', './app/views');
// Environment dependent middleware
if (process.env.NODE_ENV === 'development') {
// Enable logger (morgan)
app.use(morgan('dev'));
// Environment dependent middleware
if (process.env.NODE_ENV === 'development') {
// Enable logger (morgan)
app.use(morgan('dev'));
// Disable views cache
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
app.locals.cache = 'memory';
}
// Disable views cache
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
app.locals.cache = 'memory';
}
// Request body parsing middleware should be above methodOverride
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(methodOverride());
// Request body parsing middleware should be above methodOverride
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(methodOverride());
// Enable jsonp
app.enable('jsonp callback');
// Enable jsonp
app.enable('jsonp callback');
// CookieParser should be above session
app.use(cookieParser());
// CookieParser should be above session
app.use(cookieParser());
// Express MongoDB session storage
app.use(session({
secret: config.sessionSecret,
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// Express MongoDB session storage
app.use(session({
secret: config.sessionSecret,
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// use passport session
app.use(passport.initialize());
app.use(passport.session());
// use passport session
app.use(passport.initialize());
app.use(passport.session());
// connect flash for flash messages
app.use(flash());
// connect flash for flash messages
app.use(flash());
// Use helmet to secure Express headers
app.use(helmet.xframe());
app.use(helmet.iexss());
app.use(helmet.contentTypeOptions());
app.use(helmet.ienoopen());
app.disable('x-powered-by');
// Setting the app router and static folder
app.use(express.static(path.resolve('./public')));
// Use helmet to secure Express headers
app.use(helmet.xframe());
app.use(helmet.iexss());
app.use(helmet.contentTypeOptions());
app.use(helmet.ienoopen());
app.disable('x-powered-by');
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
// Setting the app router and static folder
app.use(express.static(path.resolve('./public')));
// Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
// Log it
console.error(err.stack);
// Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Error page
res.status(500).render('500', {
error: err.stack
});
});
// Log it
console.error(err.stack);
// Assume 404 since no middleware responded
app.use(function(req, res) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not Found'
});
});
// Error page
res.status(500).render('500', {
error: err.stack
});
});
return app;
// Assume 404 since no middleware responded
app.use(function(req, res) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not Found'
});
});
return app;
};

View File

@@ -16,19 +16,19 @@ module.exports = function() {
glob('./config/env/' + process.env.NODE_ENV + '.js', {
sync: true
}, function(err, environmentFiles) {
console.log();
if (!environmentFiles.length) {
if(process.env.NODE_ENV) {
console.log('\x1b[31m', 'No configuration file found for "' + process.env.NODE_ENV + '" environment using development instead');
} else {
console.log('\x1b[31m', 'NODE_ENV is not defined! Using default development environment');
}
console.log();
if (!environmentFiles.length) {
if (process.env.NODE_ENV) {
console.log('\x1b[31m', 'No configuration file found for "' + process.env.NODE_ENV + '" environment using development instead');
} else {
console.log('\x1b[31m', 'NODE_ENV is not defined! Using default development environment');
}
process.env.NODE_ENV = 'development';
} else {
console.log('\x1b[7m', 'Application loaded using the "' + process.env.NODE_ENV + '" environment configuration');
}
console.log('\x1b[0m');
process.env.NODE_ENV = 'development';
} else {
console.log('\x1b[7m', 'Application loaded using the "' + process.env.NODE_ENV + '" environment configuration');
}
console.log('\x1b[0m');
});
/**

View File

@@ -1,27 +1,27 @@
'use strict';
var passport = require('passport'),
User = require('mongoose').model('User'),
path = require('path'),
config = require('./config');
User = require('mongoose').model('User'),
path = require('path'),
config = require('./config');
module.exports = function() {
// Serialize sessions
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// Serialize sessions
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// Deserialize sessions
passport.deserializeUser(function(id, done) {
User.findOne({
_id: id
}, '-salt -password', function(err, user) {
done(err, user);
});
});
// Deserialize sessions
passport.deserializeUser(function(id, done) {
User.findOne({
_id: id
}, '-salt -password', function(err, user) {
done(err, user);
});
});
// Initialize strategies
config.getGlobbedFiles('./config/strategies/**/*.js').forEach(function(strategy) {
require(path.resolve(strategy))();
});
};
// Initialize strategies
config.getGlobbedFiles('./config/strategies/**/*.js').forEach(function(strategy) {
require(path.resolve(strategy))();
});
};

View File

@@ -4,39 +4,39 @@
* Module dependencies.
*/
var passport = require('passport'),
url = require('url'),
FacebookStrategy = require('passport-facebook').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
url = require('url'),
FacebookStrategy = require('passport-facebook').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
module.exports = function() {
// Use facebook strategy
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.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;
// Use facebook strategy
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.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 = {
firstName: profile.name.givenName,
lastName: profile.name.familyName,
displayName: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'facebook',
providerIdentifierField: 'id',
providerData: providerData
};
// Create the user OAuth profile
var providerUserProfile = {
firstName: profile.name.givenName,
lastName: profile.name.familyName,
displayName: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'facebook',
providerIdentifierField: 'id',
providerData: providerData
};
// Save the user OAuth profile
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
// Save the user OAuth profile
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
};

View File

@@ -39,4 +39,4 @@ module.exports = function() {
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
};
};

View File

@@ -4,40 +4,40 @@
* Module dependencies.
*/
var passport = require('passport'),
url = require('url'),
LinkedInStrategy = require('passport-linkedin').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
url = require('url'),
LinkedInStrategy = require('passport-linkedin').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
module.exports = function() {
// Use linkedin strategy
passport.use(new LinkedInStrategy({
consumerKey: config.linkedin.clientID,
consumerSecret: config.linkedin.clientSecret,
callbackURL: config.linkedin.callbackURL,
passReqToCallback: true,
profileFields: ['id', 'first-name', 'last-name', 'email-address']
},
function(req, accessToken, refreshToken, profile, done) {
// Set the provider data and include tokens
var providerData = profile._json;
providerData.accessToken = accessToken;
providerData.refreshToken = refreshToken;
// Use linkedin strategy
passport.use(new LinkedInStrategy({
consumerKey: config.linkedin.clientID,
consumerSecret: config.linkedin.clientSecret,
callbackURL: config.linkedin.callbackURL,
passReqToCallback: true,
profileFields: ['id', 'first-name', 'last-name', 'email-address']
},
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 = {
firstName: profile.name.givenName,
lastName: profile.name.familyName,
displayName: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'linkedin',
providerIdentifierField: 'id',
providerData: providerData
};
// Create the user OAuth profile
var providerUserProfile = {
firstName: profile.name.givenName,
lastName: profile.name.familyName,
displayName: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'linkedin',
providerIdentifierField: 'id',
providerData: providerData
};
// Save the user OAuth profile
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
// Save the user OAuth profile
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
};

View File

@@ -4,35 +4,35 @@
* Module dependencies.
*/
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
User = require('mongoose').model('User');
LocalStrategy = require('passport-local').Strategy,
User = require('mongoose').model('User');
module.exports = function() {
// Use local strategy
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Unknown user'
});
}
if (!user.authenticate(password)) {
return done(null, false, {
message: 'Invalid password'
});
}
return done(null, user);
});
}
));
};
// Use local strategy
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Unknown user'
});
}
if (!user.authenticate(password)) {
return done(null, false, {
message: 'Invalid password'
});
}
return done(null, user);
});
}
));
};

View File

@@ -4,36 +4,36 @@
* Module dependencies.
*/
var passport = require('passport'),
url = require('url'),
TwitterStrategy = require('passport-twitter').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
url = require('url'),
TwitterStrategy = require('passport-twitter').Strategy,
config = require('../config'),
users = require('../../app/controllers/users');
module.exports = function() {
// Use twitter strategy
passport.use(new TwitterStrategy({
consumerKey: config.twitter.clientID,
consumerSecret: config.twitter.clientSecret,
callbackURL: config.twitter.callbackURL,
passReqToCallback: true
},
function(req, token, tokenSecret, profile, done) {
// Set the provider data and include tokens
var providerData = profile._json;
providerData.token = token;
providerData.tokenSecret = tokenSecret;
// Use twitter strategy
passport.use(new TwitterStrategy({
consumerKey: config.twitter.clientID,
consumerSecret: config.twitter.clientSecret,
callbackURL: config.twitter.callbackURL,
passReqToCallback: true
},
function(req, token, tokenSecret, profile, done) {
// Set the provider data and include tokens
var providerData = profile._json;
providerData.token = token;
providerData.tokenSecret = tokenSecret;
// Create the user OAuth profile
var providerUserProfile = {
displayName: profile.displayName,
username: profile.username,
provider: 'twitter',
providerIdentifierField: 'id_str',
providerData: providerData
};
// Create the user OAuth profile
var providerUserProfile = {
displayName: profile.displayName,
username: profile.username,
provider: 'twitter',
providerIdentifierField: 'id_str',
providerData: providerData
};
// Save the user OAuth profile
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
// Save the user OAuth profile
users.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
};

View File

@@ -113,11 +113,11 @@ module.exports = function(grunt) {
// A Task for loading the configuration object
grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() {
var init = require('./config/init')();
var config = require('./config/config');
var init = require('./config/init')();
var config = require('./config/config');
grunt.config.set('applicationJavaScriptFiles', config.assets.js);
grunt.config.set('applicationCSSFiles', config.assets.css);
grunt.config.set('applicationJavaScriptFiles', config.assets.js);
grunt.config.set('applicationCSSFiles', config.assets.css);
});
// Default task(s).
@@ -127,8 +127,8 @@ module.exports = function(grunt) {
grunt.registerTask('lint', ['jshint', 'csslint']);
// Build task(s).
grunt.registerTask('build', ['jshint', 'csslint', 'loadConfig' ,'uglify', 'cssmin']);
grunt.registerTask('build', ['jshint', 'csslint', 'loadConfig', 'uglify', 'cssmin']);
// Test task.
grunt.registerTask('test', ['env:test', 'mochaTest', 'karma:unit']);
};
};

View File

@@ -7,46 +7,46 @@ var applicationConfiguration = require('./config/config');
// Karma configuration
module.exports = function(config) {
config.set({
// Frameworks to use
frameworks: ['jasmine'],
config.set({
// Frameworks to use
frameworks: ['jasmine'],
// List of files / patterns to load in the browser
files: applicationConfiguration.assets.lib.js.concat(applicationConfiguration.assets.js, applicationConfiguration.assets.tests),
// List of files / patterns to load in the browser
files: applicationConfiguration.assets.lib.js.concat(applicationConfiguration.assets.js, applicationConfiguration.assets.tests),
// Test results reporter to use
// Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
//reporters: ['progress'],
reporters: ['progress'],
// Test results reporter to use
// Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
//reporters: ['progress'],
reporters: ['progress'],
// Web server port
port: 9876,
// Web server port
port: 9876,
// Enable / disable colors in the output (reporters and logs)
colors: true,
// Enable / disable colors in the output (reporters and logs)
colors: true,
// Level of logging
// Possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// Level of logging
// Possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// Enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// If true, it capture browsers, run tests and exit
singleRun: true
});
// Continuous Integration mode
// If true, it capture browsers, run tests and exit
singleRun: true
});
};

View File

@@ -5,16 +5,16 @@ angular.module(ApplicationConfiguration.applicationModuleName, ApplicationConfig
// Setting HTML5 Location Mode
angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider',
function($locationProvider) {
$locationProvider.hashPrefix('!');
}
function($locationProvider) {
$locationProvider.hashPrefix('!');
}
]);
//Then define the init function for starting up the application
angular.element(document).ready(function() {
//Fixing facebook bug with redirect
if (window.location.hash === '#_=_') window.location.hash = '#!';
//Fixing facebook bug with redirect
if (window.location.hash === '#_=_') window.location.hash = '#!';
//Then init the app
angular.bootstrap(document, [ApplicationConfiguration.applicationModuleName]);
});
//Then init the app
angular.bootstrap(document, [ApplicationConfiguration.applicationModuleName]);
});

View File

@@ -2,22 +2,22 @@
// Init the application configuration module for AngularJS application
var ApplicationConfiguration = (function() {
// Init module configuration options
var applicationModuleName = 'mean';
var applicationModuleVendorDependencies = ['ngResource', 'ngAnimate', 'ui.router', 'ui.bootstrap', 'ui.utils'];
// Init module configuration options
var applicationModuleName = 'mean';
var applicationModuleVendorDependencies = ['ngResource', 'ngAnimate', 'ui.router', 'ui.bootstrap', 'ui.utils'];
// Add a new vertical module
var registerModule = function(moduleName) {
// Create angular module
angular.module(moduleName, []);
// Add a new vertical module
var registerModule = function(moduleName) {
// Create angular module
angular.module(moduleName, []);
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
};
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
};
return {
applicationModuleName: applicationModuleName,
applicationModuleVendorDependencies: applicationModuleVendorDependencies,
registerModule: registerModule
};
})();
return {
applicationModuleName: applicationModuleName,
applicationModuleVendorDependencies: applicationModuleVendorDependencies,
registerModule: registerModule
};
})();

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
'use strict';
// Use Applicaion configuration module to register a new module
ApplicationConfiguration.registerModule('articles');
ApplicationConfiguration.registerModule('articles');

View File

@@ -2,9 +2,9 @@
// Configuring the Articles module
angular.module('articles').run(['Menus',
function(Menus) {
// Set top bar menu items
Menus.addMenuItem('topbar', 'Articles', 'articles');
Menus.addMenuItem('topbar', 'New Article', 'articles/create');
}
]);
function(Menus) {
// Set top bar menu items
Menus.addMenuItem('topbar', 'Articles', 'articles');
Menus.addMenuItem('topbar', 'New Article', 'articles/create');
}
]);

View File

@@ -2,24 +2,24 @@
// Setting up route
angular.module('articles').config(['$stateProvider',
function($stateProvider) {
// Articles state routing
$stateProvider.
state('listArticles', {
url: '/articles',
templateUrl: 'modules/articles/views/list-articles.client.view.html'
}).
state('createArticle', {
url: '/articles/create',
templateUrl: 'modules/articles/views/create-article.client.view.html'
}).
state('viewArticle', {
url: '/articles/:articleId',
templateUrl: 'modules/articles/views/view-article.client.view.html'
}).
state('editArticle', {
url: '/articles/:articleId/edit',
templateUrl: 'modules/articles/views/edit-article.client.view.html'
});
}
]);
function($stateProvider) {
// Articles state routing
$stateProvider.
state('listArticles', {
url: '/articles',
templateUrl: 'modules/articles/views/list-articles.client.view.html'
}).
state('createArticle', {
url: '/articles/create',
templateUrl: 'modules/articles/views/create-article.client.view.html'
}).
state('viewArticle', {
url: '/articles/:articleId',
templateUrl: 'modules/articles/views/view-article.client.view.html'
}).
state('editArticle', {
url: '/articles/:articleId/edit',
templateUrl: 'modules/articles/views/edit-article.client.view.html'
});
}
]);

View File

@@ -1,58 +1,58 @@
'use strict';
angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
function($scope, $stateParams, $location, Authentication, Articles) {
$scope.authentication = Authentication;
function($scope, $stateParams, $location, Authentication, Articles) {
$scope.authentication = Authentication;
$scope.create = function() {
var article = new Articles({
title: this.title,
content: this.content
});
article.$save(function(response) {
$location.path('articles/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
$scope.create = function() {
var article = new Articles({
title: this.title,
content: this.content
});
article.$save(function(response) {
$location.path('articles/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
this.title = '';
this.content = '';
};
this.title = '';
this.content = '';
};
$scope.remove = function(article) {
if (article) {
article.$remove();
$scope.remove = function(article) {
if (article) {
article.$remove();
for (var i in $scope.articles) {
if ($scope.articles[i] === article) {
$scope.articles.splice(i, 1);
}
}
} else {
$scope.article.$remove(function() {
$location.path('articles');
});
}
};
for (var i in $scope.articles) {
if ($scope.articles[i] === article) {
$scope.articles.splice(i, 1);
}
}
} else {
$scope.article.$remove(function() {
$location.path('articles');
});
}
};
$scope.update = function() {
var article = $scope.article;
$scope.update = function() {
var article = $scope.article;
article.$update(function() {
$location.path('articles/' + article._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
article.$update(function() {
$location.path('articles/' + article._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.find = function() {
$scope.articles = Articles.query();
};
$scope.find = function() {
$scope.articles = Articles.query();
};
$scope.findOne = function() {
$scope.article = Articles.get({
articleId: $stateParams.articleId
});
};
}
]);
$scope.findOne = function() {
$scope.article = Articles.get({
articleId: $stateParams.articleId
});
};
}
]);

View File

@@ -1,12 +1,14 @@
'use strict';
//Articles service used for communicating with the articles REST endpoints
angular.module('articles').factory('Articles', ['$resource', function($resource) {
return $resource('articles/:articleId', {
articleId: '@_id'
}, {
update: {
method: 'PUT'
}
});
}]);
angular.module('articles').factory('Articles', ['$resource',
function($resource) {
return $resource('articles/:articleId', {
articleId: '@_id'
}, {
update: {
method: 'PUT'
}
});
}
]);

View File

@@ -1,170 +1,170 @@
'use strict';
(function() {
// Articles Controller Spec
describe('ArticlesController', function() {
// Initialize global variables
var ArticlesController,
scope,
$httpBackend,
$stateParams,
$location;
// Articles Controller Spec
describe('ArticlesController', function() {
// Initialize global variables
var ArticlesController,
scope,
$httpBackend,
$stateParams,
$location;
// The $resource service augments the response object with methods for updating and deleting the resource.
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
// the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
// When the toEqualData matcher compares two objects, it takes only object properties into
// account and ignores methods.
beforeEach(function() {
jasmine.addMatchers({
toEqualData: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
return {
pass: angular.equals(actual, expected)
};
}
};
}
});
});
// The $resource service augments the response object with methods for updating and deleting the resource.
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
// the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
// When the toEqualData matcher compares two objects, it takes only object properties into
// account and ignores methods.
beforeEach(function() {
jasmine.addMatchers({
toEqualData: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
return {
pass: angular.equals(actual, expected)
};
}
};
}
});
});
// Then we can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// Then we can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
// Set a new global scope
scope = $rootScope.$new();
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
// Set a new global scope
scope = $rootScope.$new();
// Point global variables to injected services
$stateParams = _$stateParams_;
$httpBackend = _$httpBackend_;
$location = _$location_;
// Point global variables to injected services
$stateParams = _$stateParams_;
$httpBackend = _$httpBackend_;
$location = _$location_;
// Initialize the Articles controller.
ArticlesController = $controller('ArticlesController', {
$scope: scope
});
}));
// Initialize the Articles controller.
ArticlesController = $controller('ArticlesController', {
$scope: scope
});
}));
it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Articles) {
// Create sample article using the Articles service
var sampleArticle = new Articles({
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Articles) {
// Create sample article using the Articles service
var sampleArticle = new Articles({
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
// Create a sample articles array that includes the new article
var sampleArticles = [sampleArticle];
// Create a sample articles array that includes the new article
var sampleArticles = [sampleArticle];
// Set GET response
$httpBackend.expectGET('articles').respond(sampleArticles);
// Set GET response
$httpBackend.expectGET('articles').respond(sampleArticles);
// Run controller functionality
scope.find();
$httpBackend.flush();
// Run controller functionality
scope.find();
$httpBackend.flush();
// Test scope value
expect(scope.articles).toEqualData(sampleArticles);
}));
// Test scope value
expect(scope.articles).toEqualData(sampleArticles);
}));
it('$scope.findOne() should create an array with one article object fetched from XHR using a articleId URL parameter', inject(function(Articles) {
// Define a sample article object
var sampleArticle = new Articles({
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
it('$scope.findOne() should create an array with one article object fetched from XHR using a articleId URL parameter', inject(function(Articles) {
// Define a sample article object
var sampleArticle = new Articles({
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
// Set the URL parameter
$stateParams.articleId = '525a8422f6d0f87f0e407a33';
// Set the URL parameter
$stateParams.articleId = '525a8422f6d0f87f0e407a33';
// Set GET response
$httpBackend.expectGET(/articles\/([0-9a-fA-F]{24})$/).respond(sampleArticle);
// Set GET response
$httpBackend.expectGET(/articles\/([0-9a-fA-F]{24})$/).respond(sampleArticle);
// Run controller functionality
scope.findOne();
$httpBackend.flush();
// Run controller functionality
scope.findOne();
$httpBackend.flush();
// Test scope value
expect(scope.article).toEqualData(sampleArticle);
}));
// Test scope value
expect(scope.article).toEqualData(sampleArticle);
}));
it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Articles) {
// Create a sample article object
var sampleArticlePostData = new Articles({
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Articles) {
// Create a sample article object
var sampleArticlePostData = new Articles({
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
// Create a sample article response
var sampleArticleResponse = new Articles({
_id: '525cf20451979dea2c000001',
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
// Create a sample article response
var sampleArticleResponse = new Articles({
_id: '525cf20451979dea2c000001',
title: 'An Article about MEAN',
content: 'MEAN rocks!'
});
// Fixture mock form input values
scope.title = 'An Article about MEAN';
scope.content = 'MEAN rocks!';
// Fixture mock form input values
scope.title = 'An Article about MEAN';
scope.content = 'MEAN rocks!';
// Set POST response
$httpBackend.expectPOST('articles', sampleArticlePostData).respond(sampleArticleResponse);
// Set POST response
$httpBackend.expectPOST('articles', sampleArticlePostData).respond(sampleArticleResponse);
// Run controller functionality
scope.create();
$httpBackend.flush();
// Run controller functionality
scope.create();
$httpBackend.flush();
// Test form inputs are reset
expect(scope.title).toEqual('');
expect(scope.content).toEqual('');
// Test form inputs are reset
expect(scope.title).toEqual('');
expect(scope.content).toEqual('');
// Test URL redirection after the article was created
expect($location.path()).toBe('/articles/' + sampleArticleResponse._id);
}));
// Test URL redirection after the article was created
expect($location.path()).toBe('/articles/' + sampleArticleResponse._id);
}));
it('$scope.update() should update a valid article', inject(function(Articles) {
// Define a sample article put data
var sampleArticlePutData = new Articles({
_id: '525cf20451979dea2c000001',
title: 'An Article about MEAN',
content: 'MEAN Rocks!'
});
it('$scope.update() should update a valid article', inject(function(Articles) {
// Define a sample article put data
var sampleArticlePutData = new Articles({
_id: '525cf20451979dea2c000001',
title: 'An Article about MEAN',
content: 'MEAN Rocks!'
});
// Mock article in scope
scope.article = sampleArticlePutData;
// Mock article in scope
scope.article = sampleArticlePutData;
// Set PUT response
$httpBackend.expectPUT(/articles\/([0-9a-fA-F]{24})$/).respond();
// Set PUT response
$httpBackend.expectPUT(/articles\/([0-9a-fA-F]{24})$/).respond();
// Run controller functionality
scope.update();
$httpBackend.flush();
// Run controller functionality
scope.update();
$httpBackend.flush();
// Test URL location to new object
expect($location.path()).toBe('/articles/' + sampleArticlePutData._id);
}));
// Test URL location to new object
expect($location.path()).toBe('/articles/' + sampleArticlePutData._id);
}));
it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Articles) {
// Create new article object
var sampleArticle = new Articles({
_id: '525a8422f6d0f87f0e407a33'
});
it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Articles) {
// Create new article object
var sampleArticle = new Articles({
_id: '525a8422f6d0f87f0e407a33'
});
// Create new articles array and include the article
scope.articles = [sampleArticle];
// Create new articles array and include the article
scope.articles = [sampleArticle];
// Set expected DELETE response
$httpBackend.expectDELETE(/articles\/([0-9a-fA-F]{24})$/).respond(204);
// Set expected DELETE response
$httpBackend.expectDELETE(/articles\/([0-9a-fA-F]{24})$/).respond(204);
// Run controller functionality
scope.remove(sampleArticle);
$httpBackend.flush();
// Run controller functionality
scope.remove(sampleArticle);
$httpBackend.flush();
// Test array after successful delete
expect(scope.articles.length).toBe(0);
}));
});
}());
// Test array after successful delete
expect(scope.articles.length).toBe(0);
}));
});
}());

View File

@@ -2,15 +2,15 @@
// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// Redirect to home view when route not found
$urlRouterProvider.otherwise('/');
function($stateProvider, $urlRouterProvider) {
// Redirect to home view when route not found
$urlRouterProvider.otherwise('/');
// Home state routing
$stateProvider.
state('home', {
url: '/',
templateUrl: 'modules/core/views/home.client.view.html'
});
}
]);
// Home state routing
$stateProvider.
state('home', {
url: '/',
templateUrl: 'modules/core/views/home.client.view.html'
});
}
]);

View File

@@ -1,13 +1,13 @@
'use strict';
angular.module('core').controller('HeaderController', ['$scope', 'Authentication', 'Menus',
function($scope, Authentication, Menus) {
$scope.authentication = Authentication;
$scope.isCollapsed = false;
$scope.menu = Menus.getMenu('topbar');
function($scope, Authentication, Menus) {
$scope.authentication = Authentication;
$scope.isCollapsed = false;
$scope.menu = Menus.getMenu('topbar');
$scope.toggleCollapsibleMenu = function() {
$scope.isCollapsed = !$scope.isCollapsed;
};
}
]);
$scope.toggleCollapsibleMenu = function() {
$scope.isCollapsed = !$scope.isCollapsed;
};
}
]);

View File

@@ -1,5 +1,7 @@
'use strict';
angular.module('core').controller('HomeController', ['$scope', 'Authentication', function ($scope, Authentication) {
$scope.authentication = Authentication;
}]);
angular.module('core').controller('HomeController', ['$scope', 'Authentication',
function($scope, Authentication) {
$scope.authentication = Authentication;
}
]);

View File

@@ -1,4 +1,4 @@
'use strict';
// Use Applicaion configuration module to register a new module
ApplicationConfiguration.registerModule('core');
ApplicationConfiguration.registerModule('core');

View File

@@ -2,113 +2,114 @@
//Menu service used for managing menus
angular.module('core').service('Menus', [
function() {
// Define a set of default roles
this.defaultRoles = ['user'];
// Define the menus object
this.menus = {};
function() {
// Define a set of default roles
this.defaultRoles = ['user'];
// 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;
}
}
}
} else {
return this.isPublic;
}
// Define the menus object
this.menus = {};
return false;
};
// 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;
}
}
}
} else {
return this.isPublic;
}
// Validate menu existance
this.validateMenuExistance = function(menuId) {
if (menuId && menuId.length) {
if (this.menus[menuId]) {
return true;
} else {
throw new Error('Menu does not exists');
}
} else {
throw new Error('MenuId was not provided');
}
return false;
};
return false;
};
// Validate menu existance
this.validateMenuExistance = function(menuId) {
if (menuId && menuId.length) {
if (this.menus[menuId]) {
return true;
} else {
throw new Error('Menu does not exists');
}
} else {
throw new Error('MenuId was not provided');
}
// Get the menu object by menu id
this.getMenu = function(menuId) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
return false;
};
// Return the menu object
return this.menus[menuId];
};
// Get the menu object by menu id
this.getMenu = function(menuId) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Add new menu object by menu id
this.addMenu = function(menuId, isPublic, roles) {
// Create the new menu
this.menus[menuId] = {
isPublic: isPublic || false,
roles: roles || this.defaultRoles,
items: [],
shouldRender: shouldRender
};
// Return the menu object
return this.menus[menuId];
};
// Return the menu object
return this.menus[menuId];
};
// Add new menu object by menu id
this.addMenu = function(menuId, isPublic, roles) {
// Create the new menu
this.menus[menuId] = {
isPublic: isPublic || false,
roles: roles || this.defaultRoles,
items: [],
shouldRender: shouldRender
};
// Remove existing menu object by menu id
this.removeMenu = function(menuId) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
return this.menus[menuId];
};
// Return the menu object
delete this.menus[menuId];
};
// Remove existing menu object by menu id
this.removeMenu = function(menuId) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Add menu item object
this.addMenuItem = function(menuId, menuItemTitle, menuItemURL, menuItemUIRoute, isPublic, roles) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
delete this.menus[menuId];
};
// Push new menu item
this.menus[menuId].items.push({
title: menuItemTitle,
link: menuItemURL,
uiRoute: menuItemUIRoute || ('/' + menuItemURL),
isPublic: isPublic || this.menus[menuId].isPublic,
roles: roles || this.defaultRoles,
shouldRender: shouldRender
});
// Add menu item object
this.addMenuItem = function(menuId, menuItemTitle, menuItemURL, menuItemUIRoute, isPublic, roles) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
return this.menus[menuId];
};
// Push new menu item
this.menus[menuId].items.push({
title: menuItemTitle,
link: menuItemURL,
uiRoute: menuItemUIRoute || ('/' + menuItemURL),
isPublic: isPublic || this.menus[menuId].isPublic,
roles: roles || this.defaultRoles,
shouldRender: shouldRender
});
// Remove existing menu object by menu id
this.removeMenuItem = function(menuId, menuItemURL) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
return this.menus[menuId];
};
// Search for menu item to remove
for (var itemIndex in this.menus[menuId].items) {
if (this.menus[menuId].items[itemIndex].link === menuItemURL) {
this.menus[menuId].items.splice(itemIndex, 1);
}
}
// Remove existing menu object by menu id
this.removeMenuItem = function(menuId, menuItemURL) {
// Validate that the menu exists
this.validateMenuExistance(menuId);
// Return the menu object
return this.menus[menuId];
};
// Search for menu item to remove
for (var itemIndex in this.menus[menuId].items) {
if (this.menus[menuId].items[itemIndex].link === menuItemURL) {
this.menus[menuId].items.splice(itemIndex, 1);
}
}
//Adding the topbar menu
this.addMenu('topbar');
}
// Return the menu object
return this.menus[menuId];
};
//Adding the topbar menu
this.addMenu('topbar');
}
]);

View File

@@ -1,24 +1,24 @@
'use strict';
(function() {
describe('HeaderController', function() {
//Initialize global variables
var scope,
HeaderController;
describe('HeaderController', function() {
//Initialize global variables
var scope,
HeaderController;
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
HeaderController = $controller('HeaderController', {
$scope: scope
});
}));
HeaderController = $controller('HeaderController', {
$scope: scope
});
}));
it('should expose the authentication service', function() {
expect(scope.authentication).toBeTruthy();
});
});
})();
it('should expose the authentication service', function() {
expect(scope.authentication).toBeTruthy();
});
});
})();

View File

@@ -1,24 +1,24 @@
'use strict';
(function() {
describe('HomeController', function() {
//Initialize global variables
var scope,
HomeController;
describe('HomeController', function() {
//Initialize global variables
var scope,
HomeController;
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
HomeController = $controller('HomeController', {
$scope: scope
});
}));
HomeController = $controller('HomeController', {
$scope: scope
});
}));
it('should expose the authentication service', function() {
expect(scope.authentication).toBeTruthy();
});
});
})();
it('should expose the authentication service', function() {
expect(scope.authentication).toBeTruthy();
});
});
})();

View File

@@ -2,29 +2,29 @@
// Config HTTP Error Handling
angular.module('users').config(['$httpProvider',
function($httpProvider) {
// Set the httpProvider "not authorized" interceptor
$httpProvider.interceptors.push(['$q', '$location', 'Authentication',
function($q, $location, Authentication) {
return {
responseError: function(rejection) {
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.user = null;
function($httpProvider) {
// Set the httpProvider "not authorized" interceptor
$httpProvider.interceptors.push(['$q', '$location', 'Authentication',
function($q, $location, Authentication) {
return {
responseError: function(rejection) {
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.user = null;
// Redirect to signin page
$location.path('signin');
break;
case 403:
// Add unauthorized behaviour
break;
}
// Redirect to signin page
$location.path('signin');
break;
case 403:
// Add unauthorized behaviour
break;
}
return $q.reject(rejection);
}
};
}
]);
}
]);
return $q.reject(rejection);
}
};
}
]);
}
]);

View File

@@ -2,28 +2,28 @@
// Setting up route
angular.module('users').config(['$stateProvider',
function($stateProvider) {
// Users state routing
$stateProvider.
state('profile', {
url: '/settings/profile',
templateUrl: 'modules/users/views/settings/edit-profile.client.view.html'
}).
state('password', {
url: '/settings/password',
templateUrl: 'modules/users/views/settings/change-password.client.view.html'
}).
state('accounts', {
url: '/settings/accounts',
templateUrl: 'modules/users/views/settings/social-accounts.client.view.html'
}).
state('signup', {
url: '/signup',
templateUrl: 'modules/users/views/signup.client.view.html'
}).
state('signin', {
url: '/signin',
templateUrl: 'modules/users/views/signin.client.view.html'
});
}
]);
function($stateProvider) {
// Users state routing
$stateProvider.
state('profile', {
url: '/settings/profile',
templateUrl: 'modules/users/views/settings/edit-profile.client.view.html'
}).
state('password', {
url: '/settings/password',
templateUrl: 'modules/users/views/settings/change-password.client.view.html'
}).
state('accounts', {
url: '/settings/accounts',
templateUrl: 'modules/users/views/settings/social-accounts.client.view.html'
}).
state('signup', {
url: '/signup',
templateUrl: 'modules/users/views/signup.client.view.html'
}).
state('signin', {
url: '/signin',
templateUrl: 'modules/users/views/signin.client.view.html'
});
}
]);

View File

@@ -31,4 +31,4 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$http
});
};
}
]);
]);

View File

@@ -1,67 +1,67 @@
'use strict';
angular.module('users').controller('SettingsController', ['$scope', '$http', '$location', 'Users', 'Authentication',
function($scope, $http, $location, Users, Authentication) {
$scope.user = Authentication.user;
function($scope, $http, $location, Users, Authentication) {
$scope.user = Authentication.user;
// If user is not signed in then redirect back home
if (!$scope.user) $location.path('/');
// If user is not signed in then redirect back home
if (!$scope.user) $location.path('/');
// Check if there are additional accounts
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
for (var i in $scope.user.additionalProvidersData) {
return true;
}
// Check if there are additional accounts
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
for (var i in $scope.user.additionalProvidersData) {
return true;
}
return false;
};
// Check if provider is already in use with current user
$scope.isConnectedSocialAccount = function(provider) {
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
};
return false;
};
// Remove a user social account
$scope.removeUserSocialAccount = function(provider) {
$scope.success = $scope.error = null;
// Check if provider is already in use with current user
$scope.isConnectedSocialAccount = function(provider) {
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
};
$http.delete('/users/accounts', {
params: {
provider: provider
}
}).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.user = Authentication.user = response;
}).error(function(response) {
$scope.error = response.message;
});
};
// Remove a user social account
$scope.removeUserSocialAccount = function(provider) {
$scope.success = $scope.error = null;
// Update a user profile
$scope.updateUserProfile = function() {
$scope.success = $scope.error = null;
var user = new Users($scope.user);
$http.delete('/users/accounts', {
params: {
provider: provider
}
}).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.user = Authentication.user = response;
}).error(function(response) {
$scope.error = response.message;
});
};
user.$update(function(response) {
$scope.success = true;
Authentication.user = response;
}, function(response) {
$scope.error = response.data.message;
});
};
// Update a user profile
$scope.updateUserProfile = function() {
$scope.success = $scope.error = null;
var user = new Users($scope.user);
// Change user password
$scope.changeUserPassword = function() {
$scope.success = $scope.error = null;
user.$update(function(response) {
$scope.success = true;
Authentication.user = response;
}, function(response) {
$scope.error = response.data.message;
});
};
$http.post('/users/password', $scope.passwordDetails).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.passwordDetails = null;
}).error(function(response) {
$scope.error = response.message;
});
};
}
]);
// Change user password
$scope.changeUserPassword = function() {
$scope.success = $scope.error = null;
$http.post('/users/password', $scope.passwordDetails).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.passwordDetails = null;
}).error(function(response) {
$scope.error = response.message;
});
};
}
]);

View File

@@ -2,13 +2,14 @@
// Authentication service for user variables
angular.module('users').factory('Authentication', [
function() {
var _this = this;
_this._data = {
user: window.user
};
function() {
var _this = this;
return _this._data;
}
]);
_this._data = {
user: window.user
};
return _this._data;
}
]);

View File

@@ -2,11 +2,11 @@
// Users service used for communicating with the users REST endpoint
angular.module('users').factory('Users', ['$resource',
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
}
});
}
]);
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
}
});
}
]);

View File

@@ -1,4 +1,4 @@
'use strict';
// Use Applicaion configuration module to register a new module
ApplicationConfiguration.registerModule('users');
ApplicationConfiguration.registerModule('users');

View File

@@ -3,8 +3,8 @@
* Module dependencies.
*/
var init = require('./config/init')(),
config = require('./config/config'),
mongoose = require('mongoose');
config = require('./config/config'),
mongoose = require('mongoose');
/**
* Main application entry file.