mirror of
https://github.com/taobataoma/meanTorrent.git
synced 2026-02-26 08:11:01 +01:00
Merge commit 'b43c80e2c097b11114f4e4f01b9718321721a89b'
* commit 'b43c80e2c097b11114f4e4f01b9718321721a89b': feat(build): Update dependencies (#1847) fix(travis): Fix Travis failing on webdriver issues (#1845) fix(eslint): Inconsistent spacing before function parentheses (#1844) fix(mongodb): update ssl connection settings (#1809) Remove deprecated crypto package (#1843) feat(config): Mongo Seed 2.0 (#1808) fix(users): don't fail on missing old image on image upload (#1839) feat(build): Turn on mangling for uglify (#1841) fix(gulp): fix broken test:server:watch task (#1842) feat(core): Enhancement page title directive (#1686) feat(user): Add email support to forgot password (#1834) fix(mocha): update mochajs version to reduce vulnerabilities (#1830) refactor(menus): Refactor to the Menus client service to use functional loops/filters (#1575) feat(config): Mongoose 4.11 upgrade (#1818) # Conflicts: # config/env/development.js # config/lib/app.js # modules/articles/server/models/article.server.model.js # modules/chat/client/config/chat.client.routes.js # modules/core/client/directives/page-title.client.directive.js # modules/core/client/services/menu.client.service.js # modules/users/client/config/users-admin.client.routes.js # modules/users/client/views/password/forgot-password.client.view.html # modules/users/server/models/user.server.model.js # package.json
This commit is contained in:
@@ -41,7 +41,11 @@ module.exports = {
|
||||
'one-var': [0, 'never'],
|
||||
'one-var-declaration-per-line': [2, 'always'],
|
||||
'padded-blocks': 0,
|
||||
'space-before-function-paren': 0,
|
||||
'space-before-function-paren': ['error', {
|
||||
'anonymous': 'always',
|
||||
'named': 'never',
|
||||
'asyncArrow': 'always'
|
||||
}],
|
||||
'space-in-parens': [2, 'never'],
|
||||
'spaced-comment': 0,
|
||||
strict: 0,
|
||||
|
||||
@@ -31,6 +31,7 @@ addons:
|
||||
- clang
|
||||
- google-chrome-stable
|
||||
before_install:
|
||||
- npm install webdriver-manager -g && webdriver-manager update
|
||||
- npm install nsp -g
|
||||
# - npm install snyk -g
|
||||
- 'export PATH=$PATH:/usr/lib/chromium-browser/'
|
||||
@@ -44,7 +45,8 @@ after_script:
|
||||
- nsp check
|
||||
# - snyk test
|
||||
- gulp test:coverage
|
||||
- node_modules/.bin/lcov-result-merger 'coverage/**/lcov.info' | node_modules/coveralls/bin/coveralls.js
|
||||
- npm install lcov-result-merger@~1.2.0 -g
|
||||
- lcov-result-merger 'coverage/**/lcov.info' | node_modules/coveralls/bin/coveralls.js
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
|
||||
66
config/env/development.js
vendored
66
config/env/development.js
vendored
@@ -73,25 +73,53 @@ module.exports = {
|
||||
seedDB: {
|
||||
seed: process.env.MONGO_SEED === 'true',
|
||||
options: {
|
||||
logResults: process.env.MONGO_SEED_LOG_RESULTS !== 'false',
|
||||
seedUser: {
|
||||
username: process.env.MONGO_SEED_USER_USERNAME || 'seeduser',
|
||||
provider: 'local',
|
||||
email: process.env.MONGO_SEED_USER_EMAIL || 'user@localhost.com',
|
||||
firstName: 'User',
|
||||
lastName: 'Local',
|
||||
displayName: 'User Local',
|
||||
roles: ['user']
|
||||
logResults: process.env.MONGO_SEED_LOG_RESULTS !== 'false'
|
||||
},
|
||||
// Order of collections in configuration will determine order of seeding.
|
||||
// i.e. given these settings, the User seeds will be complete before
|
||||
// Article seed is performed.
|
||||
collections: [{
|
||||
model: 'User',
|
||||
docs: [{
|
||||
data: {
|
||||
username: 'local-admin',
|
||||
email: 'admin@localhost.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'Local',
|
||||
roles: ['admin', 'user']
|
||||
}
|
||||
}, {
|
||||
// Set to true to overwrite this document
|
||||
// when it already exists in the collection.
|
||||
// If set to false, or missing, the seed operation
|
||||
// will skip this document to avoid overwriting it.
|
||||
overwrite: true,
|
||||
data: {
|
||||
username: 'local-user',
|
||||
email: 'user@localhost.com',
|
||||
firstName: 'User',
|
||||
lastName: 'Local',
|
||||
roles: ['user']
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
model: 'Article',
|
||||
options: {
|
||||
// Override log results setting at the
|
||||
// collection level.
|
||||
logResults: true
|
||||
},
|
||||
seedAdmin: {
|
||||
username: process.env.MONGO_SEED_ADMIN_USERNAME || 'seedadmin',
|
||||
provider: 'local',
|
||||
email: process.env.MONGO_SEED_ADMIN_EMAIL || 'admin@localhost.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'Local',
|
||||
displayName: 'Admin Local',
|
||||
roles: ['user', 'admin']
|
||||
}
|
||||
}
|
||||
skip: {
|
||||
// Skip collection when this query returns results.
|
||||
// e.g. {}: Only seeds collection when it is empty.
|
||||
when: {} // Mongoose qualified query
|
||||
},
|
||||
docs: [{
|
||||
data: {
|
||||
title: 'First Article',
|
||||
content: 'This is a seeded Article for the development environment'
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
5
config/env/local.example.js
vendored
5
config/env/local.example.js
vendored
@@ -20,10 +20,7 @@
|
||||
module.exports = {
|
||||
db: {
|
||||
uri: 'mongodb://localhost/local-dev',
|
||||
options: {
|
||||
user: '',
|
||||
pass: ''
|
||||
}
|
||||
options: {}
|
||||
},
|
||||
sessionSecret: process.env.SESSION_SECRET || 'youshouldchangethistosomethingsecret',
|
||||
facebook: {
|
||||
|
||||
62
config/env/production.js
vendored
62
config/env/production.js
vendored
@@ -15,22 +15,20 @@ module.exports = {
|
||||
db: {
|
||||
uri: process.env.MONGOHQ_URL || process.env.MONGODB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/mean-dev-v2',
|
||||
options: {
|
||||
user: '',
|
||||
pass: ''
|
||||
/**
|
||||
* Uncomment to enable ssl certificate based authentication to mongodb
|
||||
* servers. Adjust the settings below for your specific certificate
|
||||
* setup.
|
||||
* for connect to a replicaset, rename server:{...} to replset:{...}
|
||||
server: {
|
||||
ssl: true,
|
||||
sslValidate: false,
|
||||
checkServerIdentity: false,
|
||||
sslCA: fs.readFileSync('./config/sslcerts/ssl-ca.pem'),
|
||||
sslCert: fs.readFileSync('./config/sslcerts/ssl-cert.pem'),
|
||||
sslKey: fs.readFileSync('./config/sslcerts/ssl-key.pem'),
|
||||
sslPass: '1234'
|
||||
}
|
||||
* Uncomment to enable ssl certificate based authentication to mongodb
|
||||
* servers. Adjust the settings below for your specific certificate
|
||||
* setup.
|
||||
* for connect to a replicaset, rename server:{...} to replset:{...}
|
||||
|
||||
ssl: true,
|
||||
sslValidate: false,
|
||||
checkServerIdentity: false,
|
||||
sslCA: fs.readFileSync('./config/sslcerts/ssl-ca.pem'),
|
||||
sslCert: fs.readFileSync('./config/sslcerts/ssl-cert.pem'),
|
||||
sslKey: fs.readFileSync('./config/sslcerts/ssl-key.pem'),
|
||||
sslPass: '1234'
|
||||
|
||||
*/
|
||||
},
|
||||
// Enable mongoose debug mode
|
||||
@@ -93,25 +91,19 @@ module.exports = {
|
||||
seedDB: {
|
||||
seed: process.env.MONGO_SEED === 'true',
|
||||
options: {
|
||||
logResults: process.env.MONGO_SEED_LOG_RESULTS !== 'false',
|
||||
seedUser: {
|
||||
username: process.env.MONGO_SEED_USER_USERNAME || 'seeduser',
|
||||
provider: 'local',
|
||||
email: process.env.MONGO_SEED_USER_EMAIL || 'user@localhost.com',
|
||||
firstName: 'User',
|
||||
lastName: 'Local',
|
||||
displayName: 'User Local',
|
||||
roles: ['user']
|
||||
},
|
||||
seedAdmin: {
|
||||
username: process.env.MONGO_SEED_ADMIN_USERNAME || 'seedadmin',
|
||||
provider: 'local',
|
||||
email: process.env.MONGO_SEED_ADMIN_EMAIL || 'admin@localhost.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'Local',
|
||||
displayName: 'Admin Local',
|
||||
roles: ['user', 'admin']
|
||||
}
|
||||
}
|
||||
logResults: process.env.MONGO_SEED_LOG_RESULTS !== 'false'
|
||||
},
|
||||
collections: [{
|
||||
model: 'User',
|
||||
docs: [{
|
||||
data: {
|
||||
username: 'local-admin',
|
||||
email: 'admin@localhost.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'Local',
|
||||
roles: ['admin', 'user']
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
59
config/env/test.js
vendored
59
config/env/test.js
vendored
@@ -5,10 +5,7 @@ var defaultEnvConfig = require('./default');
|
||||
module.exports = {
|
||||
db: {
|
||||
uri: process.env.MONGOHQ_URL || process.env.MONGODB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/mean-test',
|
||||
options: {
|
||||
user: '',
|
||||
pass: ''
|
||||
},
|
||||
options: {},
|
||||
// Enable mongoose debug mode
|
||||
debug: process.env.MONGODB_DEBUG || false
|
||||
},
|
||||
@@ -83,25 +80,39 @@ module.exports = {
|
||||
seedDB: {
|
||||
seed: process.env.MONGO_SEED === 'true',
|
||||
options: {
|
||||
logResults: process.env.MONGO_SEED_LOG_RESULTS !== 'false',
|
||||
seedUser: {
|
||||
username: process.env.MONGO_SEED_USER_USERNAME || 'seeduser',
|
||||
provider: 'local',
|
||||
email: process.env.MONGO_SEED_USER_EMAIL || 'user@localhost.com',
|
||||
firstName: 'User',
|
||||
lastName: 'Local',
|
||||
displayName: 'User Local',
|
||||
roles: ['user']
|
||||
},
|
||||
seedAdmin: {
|
||||
username: process.env.MONGO_SEED_ADMIN_USERNAME || 'seedadmin',
|
||||
provider: 'local',
|
||||
email: process.env.MONGO_SEED_ADMIN_EMAIL || 'admin@localhost.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'Local',
|
||||
displayName: 'Admin Local',
|
||||
roles: ['user', 'admin']
|
||||
}
|
||||
}
|
||||
// Default to not log results for tests
|
||||
logResults: process.env.MONGO_SEED_LOG_RESULTS === 'true'
|
||||
},
|
||||
collections: [{
|
||||
model: 'User',
|
||||
docs: [{
|
||||
overwrite: true,
|
||||
data: {
|
||||
username: 'seedadmin',
|
||||
email: 'admin@localhost.com',
|
||||
firstName: 'Admin',
|
||||
lastName: 'Local',
|
||||
roles: ['admin', 'user']
|
||||
}
|
||||
}, {
|
||||
overwrite: true,
|
||||
data: {
|
||||
username: 'seeduser',
|
||||
email: 'user@localhost.com',
|
||||
firstName: 'User',
|
||||
lastName: 'Local',
|
||||
roles: ['user']
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
model: 'Article',
|
||||
docs: [{
|
||||
overwrite: true,
|
||||
data: {
|
||||
title: 'Test Article',
|
||||
content: 'Code coverage test article!'
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
var config = require('../config'),
|
||||
mongoose = require('./mongoose'),
|
||||
mongooseService = require('./mongoose'),
|
||||
express = require('./express'),
|
||||
chalk = require('chalk'),
|
||||
seed = require('./seed'),
|
||||
seed = require('./mongo-seed'),
|
||||
ircConfig = config.meanTorrentConfig.ircAnnounce;
|
||||
|
||||
function seedDB() {
|
||||
@@ -17,11 +17,11 @@ function seedDB() {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Models
|
||||
mongoose.loadModels(seedDB);
|
||||
|
||||
module.exports.init = function init(callback) {
|
||||
mongoose.connect(function (db) {
|
||||
mongooseService.connect(function (db) {
|
||||
// Initialize Models
|
||||
mongooseService.loadModels(seedDB);
|
||||
|
||||
// Initialize express
|
||||
var app = express.init(db);
|
||||
if (callback) callback(app, db, config);
|
||||
|
||||
@@ -119,7 +119,7 @@ module.exports.initSession = function (app, db) {
|
||||
},
|
||||
name: config.sessionKey,
|
||||
store: new MongoStore({
|
||||
mongooseConnection: db.connection,
|
||||
db: db,
|
||||
collection: config.sessionCollection
|
||||
})
|
||||
}));
|
||||
@@ -131,9 +131,9 @@ module.exports.initSession = function (app, db) {
|
||||
/**
|
||||
* Invoke modules server configuration
|
||||
*/
|
||||
module.exports.initModulesConfiguration = function (app, db) {
|
||||
module.exports.initModulesConfiguration = function (app) {
|
||||
config.files.server.configs.forEach(function (configPath) {
|
||||
require(path.resolve(configPath))(app, db);
|
||||
require(path.resolve(configPath))(app);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ var logger = new winston.Logger({
|
||||
// Useful for integrating with stream-related mechanism like Morgan's stream
|
||||
// option to log all HTTP requests to a file
|
||||
logger.stream = {
|
||||
write: function(msg) {
|
||||
write: function (msg) {
|
||||
logger.info(msg);
|
||||
}
|
||||
};
|
||||
|
||||
153
config/lib/mongo-seed.js
Normal file
153
config/lib/mongo-seed.js
Normal file
@@ -0,0 +1,153 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash'),
|
||||
config = require('../config'),
|
||||
mongoose = require('mongoose'),
|
||||
chalk = require('chalk');
|
||||
|
||||
exports.start = start;
|
||||
|
||||
function start(seedConfig) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
seedConfig = seedConfig || {};
|
||||
|
||||
var options = seedConfig.options || (config.seedDB ? _.clone(config.seedDB.options, true) : {});
|
||||
var collections = seedConfig.collections || (config.seedDB ? _.clone(config.seedDB.collections, true) : []);
|
||||
|
||||
if (!collections.length) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
var seeds = collections
|
||||
.filter(function (collection) {
|
||||
return collection.model;
|
||||
});
|
||||
|
||||
// Use the reduction pattern to ensure we process seeding in desired order.
|
||||
seeds.reduce(function (p, item) {
|
||||
return p.then(function () {
|
||||
return seed(item, options);
|
||||
});
|
||||
}, Promise.resolve()) // start with resolved promise for initial previous (p) item
|
||||
.then(onSuccessComplete)
|
||||
.catch(onError);
|
||||
|
||||
// Local Promise handlers
|
||||
|
||||
function onSuccessComplete() {
|
||||
if (options.logResults) {
|
||||
console.log();
|
||||
console.log(chalk.bold.green('Database Seeding: Mongo Seed complete!'));
|
||||
console.log();
|
||||
}
|
||||
|
||||
return resolve();
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
if (options.logResults) {
|
||||
console.log();
|
||||
console.log(chalk.bold.red('Database Seeding: Mongo Seed Failed!'));
|
||||
console.log(chalk.bold.red('Database Seeding: ' + err));
|
||||
console.log();
|
||||
}
|
||||
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function seed(collection, options) {
|
||||
// Merge options with collection options
|
||||
options = _.merge(options || {}, collection.options || {});
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const Model = mongoose.model(collection.model);
|
||||
const docs = collection.docs;
|
||||
|
||||
var skipWhen = collection.skip ? collection.skip.when : null;
|
||||
|
||||
if (!Model.seed) {
|
||||
return reject(new Error('Database Seeding: Invalid Model Configuration - ' + collection.model + '.seed() not implemented'));
|
||||
}
|
||||
|
||||
if (!docs || !docs.length) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
// First check if we should skip this collection
|
||||
// based on the collection's "skip.when" option.
|
||||
// NOTE: If it exists, "skip.when" should be a qualified
|
||||
// Mongoose query that will be used with Model.find().
|
||||
skipCollection()
|
||||
.then(seedDocuments)
|
||||
.then(function () {
|
||||
return resolve();
|
||||
})
|
||||
.catch(function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
|
||||
function skipCollection() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!skipWhen) {
|
||||
return resolve(false);
|
||||
}
|
||||
|
||||
Model
|
||||
.find(skipWhen)
|
||||
.exec(function (err, results) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
if (results && results.length) {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function seedDocuments(skipCollection) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (skipCollection) {
|
||||
return onComplete([{ message: chalk.yellow('Database Seeding: ' + collection.model + ' collection skipped') }]);
|
||||
}
|
||||
|
||||
var workload = docs
|
||||
.filter(function (doc) {
|
||||
return doc.data;
|
||||
})
|
||||
.map(function (doc) {
|
||||
return Model.seed(doc.data, { overwrite: doc.overwrite });
|
||||
});
|
||||
|
||||
Promise.all(workload)
|
||||
.then(onComplete)
|
||||
.catch(onError);
|
||||
|
||||
// Local Closures
|
||||
|
||||
function onComplete(responses) {
|
||||
if (options.logResults) {
|
||||
responses.forEach(function (response) {
|
||||
if (response.message) {
|
||||
console.log(chalk.magenta(response.message));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return resolve();
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
return reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var config = require('../config'),
|
||||
var _ = require('lodash'),
|
||||
config = require('../config'),
|
||||
chalk = require('chalk'),
|
||||
path = require('path'),
|
||||
mongoose = require('mongoose');
|
||||
@@ -19,30 +20,31 @@ module.exports.loadModels = function (callback) {
|
||||
};
|
||||
|
||||
// Initialize Mongoose
|
||||
module.exports.connect = function (cb) {
|
||||
var _this = this;
|
||||
|
||||
module.exports.connect = function (callback) {
|
||||
mongoose.Promise = config.db.promise;
|
||||
|
||||
var db = mongoose.connect(config.db.uri, config.db.options, function (err) {
|
||||
// Log Error
|
||||
if (err) {
|
||||
console.error(chalk.red('Could not connect to MongoDB!'));
|
||||
console.log(err);
|
||||
} else {
|
||||
var options = _.merge(config.db.options || {}, { useMongoClient: true });
|
||||
|
||||
mongoose
|
||||
.connect(config.db.uri, options)
|
||||
.then(function (connection) {
|
||||
// Enabling mongoose debug mode if required
|
||||
mongoose.set('debug', config.db.debug);
|
||||
|
||||
// Call callback FN
|
||||
if (cb) cb(db);
|
||||
}
|
||||
});
|
||||
if (callback) callback(connection.db);
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(chalk.red('Could not connect to MongoDB!'));
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
module.exports.disconnect = function (cb) {
|
||||
mongoose.disconnect(function (err) {
|
||||
console.info(chalk.yellow('Disconnected from MongoDB.'));
|
||||
cb(err);
|
||||
});
|
||||
mongoose.connection.db
|
||||
.close(function (err) {
|
||||
console.info(chalk.yellow('Disconnected from MongoDB.'));
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash'),
|
||||
config = require('../config'),
|
||||
mongoose = require('mongoose'),
|
||||
chalk = require('chalk'),
|
||||
crypto = require('crypto');
|
||||
|
||||
// global seed options object
|
||||
var seedOptions = {};
|
||||
|
||||
function removeUser (user) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var User = mongoose.model('User');
|
||||
User.find({ username: user.username }).remove(function (err) {
|
||||
if (err) {
|
||||
reject(new Error('Failed to remove local ' + user.username));
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function saveUser (user) {
|
||||
return function() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
// Then save the user
|
||||
user.save(function (err, theuser) {
|
||||
if (err) {
|
||||
reject(new Error('Failed to add local ' + user.username));
|
||||
} else {
|
||||
resolve(theuser);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function checkUserNotExists (user) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var User = mongoose.model('User');
|
||||
User.find({ username: user.username }, function (err, users) {
|
||||
if (err) {
|
||||
reject(new Error('Failed to find local account ' + user.username));
|
||||
}
|
||||
|
||||
if (users.length === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('Failed due to local account already exists: ' + user.username));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function reportSuccess (password) {
|
||||
return function (user) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (seedOptions.logResults) {
|
||||
console.log(chalk.bold.red('Database Seeding:\t\t\tLocal ' + user.username + ' added with password set to ' + password));
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// save the specified user with the password provided from the resolved promise
|
||||
function seedTheUser (user) {
|
||||
return function (password) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var User = mongoose.model('User');
|
||||
// set the new password
|
||||
user.password = password;
|
||||
|
||||
if (user.username === seedOptions.seedAdmin.username && process.env.NODE_ENV === 'production') {
|
||||
checkUserNotExists(user)
|
||||
.then(saveUser(user))
|
||||
.then(reportSuccess(password))
|
||||
.then(function () {
|
||||
resolve();
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
removeUser(user)
|
||||
.then(saveUser(user))
|
||||
.then(reportSuccess(password))
|
||||
.then(function () {
|
||||
resolve();
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// report the error
|
||||
function reportError (reject) {
|
||||
return function (err) {
|
||||
if (seedOptions.logResults) {
|
||||
console.log();
|
||||
console.log('Database Seeding:\t\t\t' + err);
|
||||
console.log();
|
||||
}
|
||||
reject(err);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.start = function start(options) {
|
||||
// Initialize the default seed options
|
||||
seedOptions = _.clone(config.seedDB.options, true);
|
||||
|
||||
// Check for provided options
|
||||
|
||||
if (_.has(options, 'logResults')) {
|
||||
seedOptions.logResults = options.logResults;
|
||||
}
|
||||
|
||||
if (_.has(options, 'seedUser')) {
|
||||
seedOptions.seedUser = options.seedUser;
|
||||
}
|
||||
|
||||
if (_.has(options, 'seedAdmin')) {
|
||||
seedOptions.seedAdmin = options.seedAdmin;
|
||||
}
|
||||
|
||||
var User = mongoose.model('User');
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var adminAccount = new User(seedOptions.seedAdmin);
|
||||
var userAccount = new User(seedOptions.seedUser);
|
||||
|
||||
// If production only seed admin if it does not exist
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
User.generateRandomPassphrase()
|
||||
.then(seedTheUser(adminAccount))
|
||||
.then(function () {
|
||||
resolve();
|
||||
})
|
||||
.catch(reportError(reject));
|
||||
} else {
|
||||
// Add both Admin and User account
|
||||
|
||||
User.generateRandomPassphrase()
|
||||
.then(seedTheUser(userAccount))
|
||||
.then(User.generateRandomPassphrase)
|
||||
.then(seedTheUser(adminAccount))
|
||||
.then(function () {
|
||||
resolve();
|
||||
})
|
||||
.catch(reportError(reject));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -74,7 +74,7 @@ module.exports = function (app, db) {
|
||||
|
||||
// Create a MongoDB storage object
|
||||
var mongoStore = new MongoStore({
|
||||
mongooseConnection: db.connection,
|
||||
db: db,
|
||||
collection: config.sessionCollection
|
||||
});
|
||||
|
||||
|
||||
89
gulpfile.js
89
gulpfile.js
@@ -109,11 +109,10 @@ gulp.task('watch:server:run-tests', function () {
|
||||
|
||||
if (filePath === path.resolve(file.path)) {
|
||||
changedTestFiles.push(f);
|
||||
plugins.refresh.changed(f);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
plugins.refresh.changed();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,7 +152,7 @@ gulp.task('uglify', function () {
|
||||
return gulp.src(assets)
|
||||
.pipe(plugins.ngAnnotate())
|
||||
.pipe(plugins.uglify({
|
||||
mangle: false
|
||||
mangle: true
|
||||
}))
|
||||
.pipe(plugins.concat('application.min.js'))
|
||||
.pipe(plugins.rev())
|
||||
@@ -304,15 +303,15 @@ gulp.task('templatecache', function () {
|
||||
|
||||
// Mocha tests task
|
||||
gulp.task('mocha', function (done) {
|
||||
// Open mongoose connections
|
||||
var mongoose = require('./config/lib/mongoose.js');
|
||||
var mongooseService = require('./config/lib/mongoose');
|
||||
var testSuites = changedTestFiles.length ? changedTestFiles : testAssets.tests.server;
|
||||
var error;
|
||||
|
||||
// Connect mongoose
|
||||
mongoose.connect(function () {
|
||||
mongoose.loadModels();
|
||||
// Run the tests
|
||||
mongooseService.connect(function (db) {
|
||||
// Load mongoose models
|
||||
mongooseService.loadModels();
|
||||
|
||||
gulp.src(testSuites)
|
||||
.pipe(plugins.mocha({
|
||||
reporter: 'spec',
|
||||
@@ -323,9 +322,13 @@ gulp.task('mocha', function (done) {
|
||||
error = err;
|
||||
})
|
||||
.on('end', function () {
|
||||
// When the tests are done, disconnect mongoose and pass the error state back to gulp
|
||||
mongoose.disconnect(function () {
|
||||
done(error);
|
||||
mongooseService.disconnect(function (err) {
|
||||
if (err) {
|
||||
console.log('Error disconnecting from database');
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
return done(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -360,7 +363,7 @@ gulp.task('karma', function (done) {
|
||||
});
|
||||
|
||||
// Run karma with coverage options set and write report
|
||||
gulp.task('karma:coverage', function(done) {
|
||||
gulp.task('karma:coverage', function (done) {
|
||||
new KarmaServer({
|
||||
configFile: __dirname + '/karma.conf.js',
|
||||
preprocessors: {
|
||||
@@ -389,20 +392,54 @@ gulp.task('karma:coverage', function(done) {
|
||||
// Drops the MongoDB database, used in e2e testing
|
||||
gulp.task('dropdb', function (done) {
|
||||
// Use mongoose configuration
|
||||
var mongoose = require('./config/lib/mongoose.js');
|
||||
var mongooseService = require('./config/lib/mongoose');
|
||||
|
||||
mongoose.connect(function (db) {
|
||||
db.connection.db.dropDatabase(function (err) {
|
||||
mongooseService.connect(function (db) {
|
||||
db.dropDatabase(function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('Successfully dropped db: ', db.connection.db.databaseName);
|
||||
console.log('Successfully dropped db: ', db.databaseName);
|
||||
}
|
||||
db.connection.db.close(done);
|
||||
|
||||
mongooseService.disconnect(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Seed Mongo database based on configuration
|
||||
gulp.task('mongo-seed', function (done) {
|
||||
var db = require('./config/lib/mongoose');
|
||||
var seed = require('./config/lib/mongo-seed');
|
||||
|
||||
// Open mongoose database connection
|
||||
db.connect(function () {
|
||||
db.loadModels();
|
||||
|
||||
seed
|
||||
.start({
|
||||
options: {
|
||||
logResults: true
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
// Disconnect and finish task
|
||||
db.disconnect(done);
|
||||
})
|
||||
.catch(function (err) {
|
||||
db.disconnect(function (disconnectError) {
|
||||
if (disconnectError) {
|
||||
console.log('Error disconnecting from the database, but was preceded by a Mongo Seed error.');
|
||||
}
|
||||
|
||||
// Finish task with error
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Downloads the selenium webdriver if protractor version is compatible
|
||||
gulp.task('webdriver_update', webdriver_update);
|
||||
|
||||
@@ -417,12 +454,12 @@ gulp.task('protractor', ['webdriver_update'], function () {
|
||||
.pipe(protractor({
|
||||
configFile: 'protractor.conf.js'
|
||||
}))
|
||||
.on('end', function() {
|
||||
.on('end', function () {
|
||||
console.log('E2E Testing complete');
|
||||
// exit with success.
|
||||
process.exit(0);
|
||||
})
|
||||
.on('error', function(err) {
|
||||
.on('error', function (err) {
|
||||
console.error('E2E Tests failed:');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
@@ -475,3 +512,17 @@ gulp.task('default', function (done) {
|
||||
gulp.task('prod', function (done) {
|
||||
runSequence(['copyLocalEnvConfig', 'makeUploadsDir', 'templatecache'], 'build', 'env:prod', 'lint', ['nodemon-nodebug', 'watch'], done);
|
||||
});
|
||||
|
||||
// Run Mongo Seed with default environment config
|
||||
gulp.task('seed', function (done) {
|
||||
runSequence('env:dev', 'mongo-seed', done);
|
||||
});
|
||||
|
||||
// Run Mongo Seed with production environment config
|
||||
gulp.task('seed:prod', function (done) {
|
||||
runSequence('env:prod', 'mongo-seed', done);
|
||||
});
|
||||
|
||||
gulp.task('seed:test', function (done) {
|
||||
runSequence('env:test', 'mongo-seed', done);
|
||||
});
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
controller: 'ArticlesAdminController',
|
||||
controllerAs: 'vm',
|
||||
data: {
|
||||
roles: ['admin']
|
||||
roles: ['admin'],
|
||||
pageTitle: '{{ articleResolve.title }}'
|
||||
},
|
||||
resolve: {
|
||||
articleResolve: getArticle
|
||||
|
||||
@@ -18,10 +18,7 @@
|
||||
url: '',
|
||||
templateUrl: '/modules/articles/client/views/list-articles.client.view.html',
|
||||
controller: 'ArticlesListController',
|
||||
controllerAs: 'vm',
|
||||
data: {
|
||||
pageTitle: 'Articles List'
|
||||
}
|
||||
controllerAs: 'vm'
|
||||
})
|
||||
.state('articles.view', {
|
||||
url: '/:articleId',
|
||||
@@ -32,7 +29,7 @@
|
||||
articleResolve: getArticle
|
||||
},
|
||||
data: {
|
||||
pageTitle: 'Article {{ articleResolve.title }}'
|
||||
pageTitle: '{{ articleResolve.title }}'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function () {
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
@@ -19,7 +19,7 @@
|
||||
// Remove existing Article
|
||||
function remove() {
|
||||
if ($window.confirm('Are you sure you want to delete?')) {
|
||||
vm.article.$remove(function() {
|
||||
vm.article.$remove(function () {
|
||||
$state.go('admin.articles.list');
|
||||
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Article deleted successfully!' });
|
||||
});
|
||||
|
||||
@@ -9,6 +9,6 @@ var path = require('path'),
|
||||
/**
|
||||
* Module init function.
|
||||
*/
|
||||
module.exports = function (app, db) {
|
||||
module.exports = function (app) {
|
||||
|
||||
};
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
* Module dependencies
|
||||
*/
|
||||
var mongoose = require('mongoose'),
|
||||
Schema = mongoose.Schema;
|
||||
Schema = mongoose.Schema,
|
||||
path = require('path'),
|
||||
config = require(path.resolve('./config/config')),
|
||||
chalk = require('chalk');
|
||||
|
||||
/**
|
||||
* Article Schema
|
||||
@@ -35,6 +38,105 @@ var ArticleSchema = new Schema({
|
||||
}
|
||||
});
|
||||
|
||||
ArticleSchema.index({user: -1, created: -1});
|
||||
ArticleSchema.statics.seed = seed;
|
||||
|
||||
mongoose.model('Article', ArticleSchema);
|
||||
|
||||
/**
|
||||
* Seeds the User collection with document (Article)
|
||||
* and provided options.
|
||||
*/
|
||||
function seed(doc, options) {
|
||||
var Article = mongoose.model('Article');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
skipDocument()
|
||||
.then(findAdminUser)
|
||||
.then(add)
|
||||
.then(function (response) {
|
||||
return resolve(response);
|
||||
})
|
||||
.catch(function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
|
||||
function findAdminUser(skip) {
|
||||
var User = mongoose.model('User');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (skip) {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
User
|
||||
.findOne({
|
||||
roles: { $in: ['admin'] }
|
||||
})
|
||||
.exec(function (err, admin) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
doc.user = admin;
|
||||
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function skipDocument() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
Article
|
||||
.findOne({
|
||||
title: doc.title
|
||||
})
|
||||
.exec(function (err, existing) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
if (!existing) {
|
||||
return resolve(false);
|
||||
}
|
||||
|
||||
if (existing && !options.overwrite) {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
// Remove Article (overwrite)
|
||||
|
||||
existing.remove(function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function add(skip) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (skip) {
|
||||
return resolve({
|
||||
message: chalk.yellow('Database Seeding: Article\t' + doc.title + ' skipped')
|
||||
});
|
||||
}
|
||||
|
||||
var article = new Article(doc);
|
||||
|
||||
article.save(function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve({
|
||||
message: 'Database Seeding: Article\t' + article.title + ' added'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ var app,
|
||||
describe('Article Admin CRUD tests', function () {
|
||||
before(function (done) {
|
||||
// Get application
|
||||
app = express.init(mongoose);
|
||||
app = express.init(mongoose.connection.db);
|
||||
agent = request.agent(app);
|
||||
|
||||
done();
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('Article CRUD tests', function () {
|
||||
|
||||
before(function (done) {
|
||||
// Get application
|
||||
app = express.init(mongoose);
|
||||
app = express.init(mongoose.connection.db);
|
||||
agent = request.agent(app);
|
||||
|
||||
done();
|
||||
@@ -119,7 +119,7 @@ describe('Article CRUD tests', function () {
|
||||
// Save the article
|
||||
articleObj.save(function () {
|
||||
// Request articles
|
||||
request(app).get('/api/articles')
|
||||
agent.get('/api/articles')
|
||||
.end(function (req, res) {
|
||||
// Set assertion
|
||||
res.body.should.be.instanceof(Array).and.have.lengthOf(1);
|
||||
@@ -137,7 +137,7 @@ describe('Article CRUD tests', function () {
|
||||
|
||||
// Save the article
|
||||
articleObj.save(function () {
|
||||
request(app).get('/api/articles/' + articleObj._id)
|
||||
agent.get('/api/articles/' + articleObj._id)
|
||||
.end(function (req, res) {
|
||||
// Set assertion
|
||||
res.body.should.be.instanceof(Object).and.have.property('title', article.title);
|
||||
@@ -150,7 +150,7 @@ describe('Article CRUD tests', function () {
|
||||
|
||||
it('should return proper error for single article with an invalid Id, if not signed in', function (done) {
|
||||
// test is not a valid mongoose Id
|
||||
request(app).get('/api/articles/test')
|
||||
agent.get('/api/articles/test')
|
||||
.end(function (req, res) {
|
||||
// Set assertion
|
||||
res.body.should.be.instanceof(Object).and.have.property('message', 'Article is invalid');
|
||||
@@ -162,7 +162,7 @@ describe('Article CRUD tests', function () {
|
||||
|
||||
it('should return proper error for single article which doesnt exist, if not signed in', function (done) {
|
||||
// This is a valid mongoose Id but a non-existent article
|
||||
request(app).get('/api/articles/559e9cd815f80b4c256a8f41')
|
||||
agent.get('/api/articles/559e9cd815f80b4c256a8f41')
|
||||
.end(function (req, res) {
|
||||
// Set assertion
|
||||
res.body.should.be.instanceof(Object).and.have.property('message', 'No article with that identifier has been found');
|
||||
@@ -202,7 +202,7 @@ describe('Article CRUD tests', function () {
|
||||
// Save the article
|
||||
articleObj.save(function () {
|
||||
// Try deleting article
|
||||
request(app).delete('/api/articles/' + articleObj._id)
|
||||
agent.delete('/api/articles/' + articleObj._id)
|
||||
.expect(403)
|
||||
.end(function (articleDeleteErr, articleDeleteRes) {
|
||||
// Set message assertion
|
||||
@@ -312,7 +312,7 @@ describe('Article CRUD tests', function () {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
request(app).get('/api/articles/' + articleObj._id)
|
||||
agent.get('/api/articles/' + articleObj._id)
|
||||
.end(function (req, res) {
|
||||
// Set assertion
|
||||
res.body.should.be.instanceof(Object).and.have.property('title', article.title);
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
controller: 'ChatController',
|
||||
controllerAs: 'vm',
|
||||
data: {
|
||||
roles: ['user', 'oper', 'admin'],
|
||||
pageTitle: 'Chat'
|
||||
roles: ['user', 'oper', 'admin']
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,13 +39,12 @@
|
||||
controller: 'ErrorController',
|
||||
controllerAs: 'vm',
|
||||
params: {
|
||||
message: function($stateParams) {
|
||||
message: function ($stateParams) {
|
||||
return $stateParams.message;
|
||||
}
|
||||
},
|
||||
data: {
|
||||
ignoreState: true,
|
||||
pageTitle: 'Not Found'
|
||||
ignoreState: true
|
||||
}
|
||||
})
|
||||
.state('bad-request', {
|
||||
@@ -54,21 +53,19 @@
|
||||
controller: 'ErrorController',
|
||||
controllerAs: 'vm',
|
||||
params: {
|
||||
message: function($stateParams) {
|
||||
message: function ($stateParams) {
|
||||
return $stateParams.message;
|
||||
}
|
||||
},
|
||||
data: {
|
||||
ignoreState: true,
|
||||
pageTitle: 'Bad Request'
|
||||
ignoreState: true
|
||||
}
|
||||
})
|
||||
.state('forbidden', {
|
||||
url: '/forbidden',
|
||||
templateUrl: '/modules/core/client/views/403.client.view.html',
|
||||
data: {
|
||||
ignoreState: true,
|
||||
pageTitle: 'Forbidden'
|
||||
ignoreState: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,13 +19,17 @@
|
||||
|
||||
function listener(event, toState) {
|
||||
var applicationCoreTitle = 'CHD.im',
|
||||
separeteBy = ' - ';
|
||||
separator = ' - ',
|
||||
stateTitle = applicationCoreTitle + separator;
|
||||
|
||||
toState.name.split('.').forEach(function (value, index) {
|
||||
stateTitle = stateTitle + value.charAt(0).toUpperCase() + value.slice(1) + separator;
|
||||
});
|
||||
if (toState.data && toState.data.pageTitle) {
|
||||
var stateTitle = $interpolate(toState.data.pageTitle)($state.$current.locals.globals);
|
||||
element.html(applicationCoreTitle + separeteBy + $translate.instant(stateTitle));
|
||||
} else {
|
||||
element.html(applicationCoreTitle);
|
||||
stateTitle = $interpolate(stateTitle + $translate.instant(toState.data.pageTitle) + separator)(($state.$current.locals.globals));
|
||||
}
|
||||
stateTitle = stateTitle.slice(0, 0 - separator.length);
|
||||
element.text(stateTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@
|
||||
|
||||
// Add menu item object
|
||||
function addMenuItem(menuId, options) {
|
||||
options = options || {};
|
||||
|
||||
// Validate that the menu exists
|
||||
service.validateMenuExistence(menuId);
|
||||
|
||||
options = options || {};
|
||||
|
||||
// Push new menu item
|
||||
service.menus[menuId].items.push({
|
||||
title: options.title || '',
|
||||
@@ -64,11 +64,9 @@
|
||||
|
||||
// Add submenu items
|
||||
if (options.items) {
|
||||
for (var i in options.items) {
|
||||
if (options.items.hasOwnProperty(i)) {
|
||||
service.addSubMenuItem(menuId, options.state, options.items[i]);
|
||||
}
|
||||
}
|
||||
options.items.forEach(function (subMenuItem) {
|
||||
service.addSubMenuItem(menuId, options.state, subMenuItem);
|
||||
});
|
||||
}
|
||||
|
||||
// Return the menu object
|
||||
@@ -83,21 +81,20 @@
|
||||
service.validateMenuExistence(menuId);
|
||||
|
||||
// Search for menu item
|
||||
for (var itemIndex in service.menus[menuId].items) {
|
||||
if (service.menus[menuId].items[itemIndex].state === parentItemState) {
|
||||
// Push new submenu item
|
||||
service.menus[menuId].items[itemIndex].items.push({
|
||||
title: options.title || '',
|
||||
state: options.state || '',
|
||||
params: options.params || {},
|
||||
roles: ((options.roles === null || typeof options.roles === 'undefined') ? service.menus[menuId].items[itemIndex].roles : options.roles),
|
||||
position: options.position || 0,
|
||||
shouldRender: shouldRender,
|
||||
target: options.target || undefined,
|
||||
divider: options.divider || false
|
||||
});
|
||||
}
|
||||
}
|
||||
service.menus[menuId].items.filter(function (item) {
|
||||
return item.state === parentItemState;
|
||||
}).forEach(function (item) {
|
||||
item.items.push({
|
||||
title: options.title || '',
|
||||
state: options.state || '',
|
||||
params: options.params || {},
|
||||
roles: ((options.roles === null || typeof options.roles === 'undefined') ? item.roles : options.roles),
|
||||
position: options.position || 0,
|
||||
shouldRender: shouldRender,
|
||||
target: options.target || undefined,
|
||||
divider: options.divider || false
|
||||
});
|
||||
});
|
||||
|
||||
// Return the menu object
|
||||
return service.menus[menuId];
|
||||
@@ -117,23 +114,17 @@
|
||||
shouldRender = function (user) {
|
||||
if (this.roles.indexOf('*') !== -1) {
|
||||
return true;
|
||||
} else {
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var userRoleIndex in user.roles) {
|
||||
if (user.roles.hasOwnProperty(userRoleIndex)) {
|
||||
for (var roleIndex in this.roles) {
|
||||
if (this.roles.hasOwnProperty(roleIndex) && this.roles[roleIndex] === user.roles[userRoleIndex]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var matchingRoles = user.roles.filter(function (userRole) {
|
||||
return this.roles.indexOf(userRole) !== -1;
|
||||
}, this);
|
||||
|
||||
return matchingRoles.length > 0;
|
||||
};
|
||||
|
||||
// Adding the topbar menu
|
||||
@@ -155,48 +146,40 @@
|
||||
// Validate that the menu exists
|
||||
service.validateMenuExistence(menuId);
|
||||
|
||||
// Search for menu item to remove
|
||||
for (var itemIndex in service.menus[menuId].items) {
|
||||
if (service.menus[menuId].items.hasOwnProperty(itemIndex) && service.menus[menuId].items[itemIndex].state === menuItemState) {
|
||||
service.menus[menuId].items.splice(itemIndex, 1);
|
||||
}
|
||||
}
|
||||
// Filter out menu items that do not match the current menu item state.
|
||||
service.menus[menuId].items = service.menus[menuId].items.filter(function (item) {
|
||||
return item.state !== menuItemState;
|
||||
});
|
||||
|
||||
// Return the menu object
|
||||
return service.menus[menuId];
|
||||
}
|
||||
|
||||
// Remove existing menu object by menu id
|
||||
function removeSubMenuItem(menuId, submenuItemState) {
|
||||
function removeSubMenuItem(menuId, subMenuItemState) {
|
||||
// Validate that the menu exists
|
||||
service.validateMenuExistence(menuId);
|
||||
|
||||
// Search for menu item to remove
|
||||
for (var itemIndex in service.menus[menuId].items) {
|
||||
if (this.menus[menuId].items.hasOwnProperty(itemIndex)) {
|
||||
for (var subitemIndex in service.menus[menuId].items[itemIndex].items) {
|
||||
if (this.menus[menuId].items[itemIndex].items.hasOwnProperty(subitemIndex) && service.menus[menuId].items[itemIndex].items[subitemIndex].state === submenuItemState) {
|
||||
service.menus[menuId].items[itemIndex].items.splice(subitemIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Filter out sub-menu items that do not match the current subMenuItemState
|
||||
service.menus[menuId].items.forEach(function (parentMenuItem) {
|
||||
parentMenuItem.items = parentMenuItem.items.filter(function (subMenuItem) {
|
||||
return subMenuItem.state !== subMenuItemState;
|
||||
});
|
||||
});
|
||||
|
||||
// Return the menu object
|
||||
return service.menus[menuId];
|
||||
}
|
||||
|
||||
// Validate menu existance
|
||||
// Validate menu existence
|
||||
function validateMenuExistence(menuId) {
|
||||
if (menuId && menuId.length) {
|
||||
if (service.menus[menuId]) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error('Menu does not exist');
|
||||
}
|
||||
} else {
|
||||
if (!(menuId && menuId.length)) {
|
||||
throw new Error('MenuId was not provided');
|
||||
}
|
||||
if (!service.menus[menuId]) {
|
||||
throw new Error('Menu does not exist');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
describe('authInterceptor', function() {
|
||||
(function () {
|
||||
describe('authInterceptor', function () {
|
||||
// Initialize global variables
|
||||
var authInterceptor,
|
||||
$q,
|
||||
@@ -13,11 +13,11 @@
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
// Load httpProvider
|
||||
beforeEach(module(function($httpProvider) {
|
||||
beforeEach(module(function ($httpProvider) {
|
||||
httpProvider = $httpProvider;
|
||||
}));
|
||||
|
||||
beforeEach(inject(function(_authInterceptor_, _$q_, _$state_, _Authentication_) {
|
||||
beforeEach(inject(function (_authInterceptor_, _$q_, _$state_, _Authentication_) {
|
||||
authInterceptor = _authInterceptor_;
|
||||
$q = _$q_;
|
||||
$state = _$state_;
|
||||
@@ -26,19 +26,19 @@
|
||||
spyOn($state, 'transitionTo');
|
||||
}));
|
||||
|
||||
it('Auth Interceptor should be object', function() {
|
||||
it('Auth Interceptor should be object', function () {
|
||||
expect(typeof authInterceptor).toEqual('object');
|
||||
});
|
||||
|
||||
it('Auth Interceptor should contain responseError function', function() {
|
||||
it('Auth Interceptor should contain responseError function', function () {
|
||||
expect(typeof authInterceptor.responseError).toEqual('function');
|
||||
});
|
||||
|
||||
it('httpProvider Interceptor should have authInterceptor', function() {
|
||||
it('httpProvider Interceptor should have authInterceptor', function () {
|
||||
expect(httpProvider.interceptors).toContain('authInterceptor');
|
||||
});
|
||||
|
||||
describe('Forbidden Interceptor', function() {
|
||||
describe('Forbidden Interceptor', function () {
|
||||
it('should redirect to forbidden route', function () {
|
||||
var response = {
|
||||
status: 403,
|
||||
@@ -50,7 +50,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
describe('Authorization Interceptor', function() {
|
||||
describe('Authorization Interceptor', function () {
|
||||
it('should redirect to signIn page for unauthorized access', function () {
|
||||
var response = {
|
||||
status: 401,
|
||||
@@ -63,9 +63,9 @@
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unresponsive Interceptor', function() {
|
||||
describe('Unresponsive Interceptor', function () {
|
||||
var Notification;
|
||||
beforeEach(inject(function(_Notification_) {
|
||||
beforeEach(inject(function (_Notification_) {
|
||||
Notification = _Notification_;
|
||||
spyOn(Notification, 'error');
|
||||
}));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
describe('Menus', function() {
|
||||
(function () {
|
||||
describe('Menus', function () {
|
||||
// Initialize global variables
|
||||
var scope,
|
||||
menuService;
|
||||
@@ -9,78 +9,78 @@
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
beforeEach(inject(function(_menuService_) {
|
||||
beforeEach(inject(function (_menuService_) {
|
||||
menuService = _menuService_;
|
||||
}));
|
||||
|
||||
it('should have topbar added', function() {
|
||||
it('should have topbar added', function () {
|
||||
expect(menuService.menus.topbar).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have default roles to user and admin', function() {
|
||||
it('should have default roles to user and admin', function () {
|
||||
expect(menuService.defaultRoles).toEqual(['user', 'admin']);
|
||||
});
|
||||
|
||||
describe('addMenu', function() {
|
||||
describe('with no options', function() {
|
||||
describe('addMenu', function () {
|
||||
describe('with no options', function () {
|
||||
var menuId = 'menu1',
|
||||
menu;
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menu = menuService.addMenu(menuId);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
it('should return menu object', function () {
|
||||
expect(menu).toBeDefined();
|
||||
});
|
||||
|
||||
it('should default roles', function() {
|
||||
it('should default roles', function () {
|
||||
expect(menu.roles).toEqual(menuService.defaultRoles);
|
||||
});
|
||||
|
||||
it('should have empty items', function() {
|
||||
it('should have empty items', function () {
|
||||
expect(menu.items).toEqual([]);
|
||||
});
|
||||
|
||||
it('should set shouldRender to shouldRender function handle', function() {
|
||||
it('should set shouldRender to shouldRender function handle', function () {
|
||||
expect(menu.shouldRender()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with options', function() {
|
||||
describe('with options', function () {
|
||||
var menu,
|
||||
options = {
|
||||
roles: ['a', 'b', 'c'],
|
||||
items: ['d', 'e', 'f']
|
||||
};
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menu = menuService.addMenu('menu1', options);
|
||||
});
|
||||
|
||||
it('should set items to options.items list', function() {
|
||||
it('should set items to options.items list', function () {
|
||||
expect(menu.items).toBe(options.items);
|
||||
});
|
||||
|
||||
it('should set roles to options.roles list', function() {
|
||||
it('should set roles to options.roles list', function () {
|
||||
expect(menu.roles).toBe(options.roles);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRender', function() {
|
||||
describe('shouldRender', function () {
|
||||
var menuOptions = {
|
||||
roles: ['*', 'menurole']
|
||||
},
|
||||
menu;
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menu = menuService.addMenu('menu1', menuOptions);
|
||||
});
|
||||
|
||||
describe('when logged out', function() {
|
||||
it('should render if menu is public', function() {
|
||||
describe('when logged out', function () {
|
||||
it('should render if menu is public', function () {
|
||||
expect(menu.shouldRender()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render if menu is private', function() {
|
||||
it('should not render if menu is private', function () {
|
||||
menu = menuService.addMenu('menu1', {
|
||||
isPublic: false
|
||||
});
|
||||
@@ -88,28 +88,28 @@
|
||||
});
|
||||
});
|
||||
|
||||
describe('when logged in', function() {
|
||||
describe('when logged in', function () {
|
||||
var user = {
|
||||
roles: ['1', 'menurole', '2']
|
||||
};
|
||||
describe('menu with * role', function() {
|
||||
it('should render', function() {
|
||||
describe('menu with * role', function () {
|
||||
it('should render', function () {
|
||||
expect(menu.shouldRender(user)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('menu without * role', function() {
|
||||
beforeEach(function() {
|
||||
describe('menu without * role', function () {
|
||||
beforeEach(function () {
|
||||
menu = menuService.addMenu('menu1', {
|
||||
roles: ['b', 'menurole', 'c']
|
||||
});
|
||||
});
|
||||
|
||||
it('should render if user has same role as menu', function() {
|
||||
it('should render if user has same role as menu', function () {
|
||||
expect(menu.shouldRender(user)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render if user has different roles', function() {
|
||||
it('should not render if user has different roles', function () {
|
||||
user = {
|
||||
roles: ['1', '2', '3']
|
||||
};
|
||||
@@ -119,54 +119,54 @@
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateMenuExistence', function() {
|
||||
describe('when menuId not provided', function() {
|
||||
it('should throw menuId error', function() {
|
||||
describe('validateMenuExistence', function () {
|
||||
describe('when menuId not provided', function () {
|
||||
it('should throw menuId error', function () {
|
||||
expect(menuService.validateMenuExistence).toThrowError('MenuId was not provided');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when menu does not exist', function() {
|
||||
it('should throw no menu error', function() {
|
||||
var target = function() {
|
||||
describe('when menu does not exist', function () {
|
||||
it('should throw no menu error', function () {
|
||||
var target = function () {
|
||||
menuService.validateMenuExistence('noMenuId');
|
||||
};
|
||||
expect(target).toThrowError('Menu does not exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when menu exists', function() {
|
||||
describe('when menu exists', function () {
|
||||
var menuId = 'menuId';
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menuService.menus[menuId] = {};
|
||||
});
|
||||
|
||||
it('should return truthy', function() {
|
||||
it('should return truthy', function () {
|
||||
expect(menuService.validateMenuExistence(menuId)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeMenu', function() {
|
||||
describe('removeMenu', function () {
|
||||
var menu = {
|
||||
id: 'menuId'
|
||||
};
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menuService.menus[menu.id] = menu;
|
||||
menuService.validateMenuExistence = jasmine.createSpy();
|
||||
menuService.removeMenu(menu.id);
|
||||
});
|
||||
|
||||
it('should remove existing menu from menus', function() {
|
||||
it('should remove existing menu from menus', function () {
|
||||
expect(menuService.menus).not.toContain(menu.id);
|
||||
});
|
||||
|
||||
it('validates menu existance before removing', function() {
|
||||
it('validates menu existance before removing', function () {
|
||||
expect(menuService.validateMenuExistence).toHaveBeenCalledWith(menu.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addMenuItem', function() {
|
||||
describe('addMenuItem', function () {
|
||||
var menuId = 'menu1',
|
||||
subMenuItem1 = {
|
||||
title: 'sub1'
|
||||
@@ -187,7 +187,7 @@
|
||||
menu,
|
||||
menuItem;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menuService.validateMenuExistence = jasmine.createSpy();
|
||||
menuService.addSubMenuItem = jasmine.createSpy();
|
||||
menuService.addMenu(menuId, {
|
||||
@@ -197,84 +197,84 @@
|
||||
menuItem = menu.items[0];
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
it('should validate menu existance', function () {
|
||||
expect(menuService.validateMenuExistence).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should return the menu', function() {
|
||||
it('should return the menu', function () {
|
||||
expect(menu).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set menu item shouldRender function', function() {
|
||||
it('should set menu item shouldRender function', function () {
|
||||
expect(menuItem.shouldRender).toBeDefined();
|
||||
});
|
||||
|
||||
describe('with options set', function() {
|
||||
it('should add menu item to menu', function() {
|
||||
describe('with options set', function () {
|
||||
it('should add menu item to menu', function () {
|
||||
expect(menu.items.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should set menu item title to options title', function() {
|
||||
it('should set menu item title to options title', function () {
|
||||
expect(menuItem.title).toBe(menuItemOptions.title);
|
||||
});
|
||||
|
||||
it('should set menu item state to options state', function() {
|
||||
it('should set menu item state to options state', function () {
|
||||
expect(menuItem.state).toBe(menuItemOptions.state);
|
||||
});
|
||||
|
||||
it('should set menu item type to options type', function() {
|
||||
it('should set menu item type to options type', function () {
|
||||
expect(menuItem.type).toBe(menuItemOptions.type);
|
||||
});
|
||||
|
||||
it('should set menu item class to options class', function() {
|
||||
it('should set menu item class to options class', function () {
|
||||
expect(menuItem.class).toBe(menuItemOptions.class);
|
||||
});
|
||||
|
||||
it('should set menu item position to options position', function() {
|
||||
it('should set menu item position to options position', function () {
|
||||
expect(menuItem.position).toBe(menuItemOptions.position);
|
||||
});
|
||||
|
||||
it('should call addSubMenuItem for each item in options', function() {
|
||||
it('should call addSubMenuItem for each item in options', function () {
|
||||
expect(menuService.addSubMenuItem).toHaveBeenCalledWith(menuId, menuItemOptions.state, subMenuItem1);
|
||||
expect(menuService.addSubMenuItem).toHaveBeenCalledWith(menuId, menuItemOptions.state, subMenuItem2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without options set', function() {
|
||||
beforeEach(function() {
|
||||
describe('without options set', function () {
|
||||
beforeEach(function () {
|
||||
menu = menuService.addMenuItem(menuId);
|
||||
menuItem = menu.items[1];
|
||||
});
|
||||
|
||||
it('should set menu item type to item', function() {
|
||||
it('should set menu item type to item', function () {
|
||||
expect(menuItem.type).toBe('item');
|
||||
});
|
||||
|
||||
it('should set menu item title to empty', function() {
|
||||
it('should set menu item title to empty', function () {
|
||||
expect(menuItem.title).toBe('');
|
||||
});
|
||||
|
||||
it('should set menu item isPublic to false', function() {
|
||||
it('should set menu item isPublic to false', function () {
|
||||
expect(menuItem.isPublic).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should set menu item roles to default roles', function() {
|
||||
it('should set menu item roles to default roles', function () {
|
||||
expect(menuItem.roles).toEqual(menuService.defaultRoles);
|
||||
});
|
||||
|
||||
it('should set menu item position to 0', function() {
|
||||
it('should set menu item position to 0', function () {
|
||||
expect(menuItem.position).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeMenuItem', function() {
|
||||
describe('removeMenuItem', function () {
|
||||
var menuId = 'menuId',
|
||||
menuItemState = 'menu.state1',
|
||||
menuItemState2 = 'menu.state2',
|
||||
menu;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menuService.addMenu(menuId);
|
||||
menuService.addMenuItem(menuId, { state: menuItemState });
|
||||
menuService.addMenuItem(menuId, { state: menuItemState2 });
|
||||
@@ -282,21 +282,21 @@
|
||||
menu = menuService.removeMenuItem(menuId, menuItemState);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
it('should return menu object', function () {
|
||||
expect(menu).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
it('should validate menu existance', function () {
|
||||
expect(menuService.validateMenuExistence).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should remove sub menu items with same state', function() {
|
||||
it('should remove sub menu items with same state', function () {
|
||||
expect(menu.items.length).toBe(1);
|
||||
expect(menu.items[0].state).toBe(menuItemState2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addSubMenuItem', function() {
|
||||
describe('addSubMenuItem', function () {
|
||||
var subItemOptions = {
|
||||
title: 'title',
|
||||
state: 'sub.state',
|
||||
@@ -324,7 +324,7 @@
|
||||
subItem2,
|
||||
menu;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
menuService.validateMenuExistence = jasmine.createSpy();
|
||||
menuService.addMenu(menuId);
|
||||
menuService.addMenuItem(menuId, menuItem1Options);
|
||||
@@ -339,93 +339,93 @@
|
||||
subItem2 = menuItem1.items[1];
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
menuService.removeMenu(menuId);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
it('should return menu object', function () {
|
||||
expect(menu).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
it('should validate menu existance', function () {
|
||||
expect(menuService.validateMenuExistence).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should not add sub menu item to menu item of different state', function() {
|
||||
it('should not add sub menu item to menu item of different state', function () {
|
||||
expect(menuItem3.items.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should set shouldRender', function() {
|
||||
it('should set shouldRender', function () {
|
||||
expect(subItem1.shouldRender).toBeDefined();
|
||||
});
|
||||
|
||||
describe('with options set', function() {
|
||||
it('should add sub menu item to menu item', function() {
|
||||
describe('with options set', function () {
|
||||
it('should add sub menu item to menu item', function () {
|
||||
expect(subItem1).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set title to options title', function() {
|
||||
it('should set title to options title', function () {
|
||||
expect(subItem1.title).toBe(subItemOptions.title);
|
||||
});
|
||||
|
||||
it('should set state to options state', function() {
|
||||
it('should set state to options state', function () {
|
||||
expect(subItem1.state).toBe(subItemOptions.state);
|
||||
});
|
||||
|
||||
it('should set roles to options roles', function() {
|
||||
it('should set roles to options roles', function () {
|
||||
expect(subItem1.roles).toEqual(subItemOptions.roles);
|
||||
});
|
||||
|
||||
it('should set position to options position', function() {
|
||||
it('should set position to options position', function () {
|
||||
expect(subItem1.position).toEqual(subItemOptions.position);
|
||||
});
|
||||
|
||||
it('should set params to options params', function() {
|
||||
it('should set params to options params', function () {
|
||||
expect(subItem1.params).toEqual(subItemOptions.params);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without optoins set', function() {
|
||||
it('should add sub menu item to menu item', function() {
|
||||
describe('without optoins set', function () {
|
||||
it('should add sub menu item to menu item', function () {
|
||||
expect(subItem2).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set isPublic to parent isPublic', function() {
|
||||
it('should set isPublic to parent isPublic', function () {
|
||||
expect(subItem2.isPublic).toBe(menuItem1.isPublic);
|
||||
});
|
||||
|
||||
it('should set title to blank', function() {
|
||||
it('should set title to blank', function () {
|
||||
expect(subItem2.title).toBe('');
|
||||
});
|
||||
|
||||
it('should set state to blank', function() {
|
||||
it('should set state to blank', function () {
|
||||
expect(subItem2.state).toBe('');
|
||||
});
|
||||
|
||||
it('should set roles to parent roles', function() {
|
||||
it('should set roles to parent roles', function () {
|
||||
expect(subItem2.roles).toEqual(menuItem1.roles);
|
||||
});
|
||||
|
||||
it('should set position to 0', function() {
|
||||
it('should set position to 0', function () {
|
||||
expect(subItem2.position).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('then removeSubMenuItem', function() {
|
||||
beforeEach(function() {
|
||||
describe('then removeSubMenuItem', function () {
|
||||
beforeEach(function () {
|
||||
menuService.validateMenuExistence = jasmine.createSpy();
|
||||
menu = menuService.removeSubMenuItem(menuId, subItem1.state);
|
||||
});
|
||||
|
||||
it('should validate menu existance', function() {
|
||||
it('should validate menu existance', function () {
|
||||
expect(menuService.validateMenuExistence).toHaveBeenCalledWith(menuId);
|
||||
});
|
||||
|
||||
it('should return menu object', function() {
|
||||
it('should return menu object', function () {
|
||||
expect(menu).toBeDefined();
|
||||
});
|
||||
|
||||
it('should remove sub menu item', function() {
|
||||
it('should remove sub menu item', function () {
|
||||
expect(menuItem1.items.length).toBe(1);
|
||||
expect(menuItem1.items[0].state).toEqual(subItem2.state);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function() {
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* Creates a mock of socket.io for the browser.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,12 +6,12 @@
|
||||
autocomplete="off">
|
||||
<fieldset>
|
||||
<div class="form-group" show-errors>
|
||||
<input type="text" id="username" name="username" class="form-control" ng-model="vm.credentials.username"
|
||||
<input type="text" id="usernameOrEmail" name="usernameOrEmail" class="form-control" ng-model="vm.credentials.usernameOrEmail"
|
||||
placeholder="{{ 'SIGN.ENTER_USERNAME' | translate}}"
|
||||
lowercase required autofocus>
|
||||
|
||||
<div ng-messages="vm.forgotPasswordForm.username.$error" role="alert">
|
||||
<p class="help-block error-text" ng-message="required">Enter a username.</p>
|
||||
<div ng-messages="vm.forgotPasswordForm.usernameOrEmail.$error" role="alert">
|
||||
<p class="help-block error-text" ng-message="required">Enter a username or email.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center form-group">
|
||||
@@ -21,4 +21,3 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ var passport = require('passport'),
|
||||
/**
|
||||
* Module init function
|
||||
*/
|
||||
module.exports = function (app, db) {
|
||||
module.exports = function (app) {
|
||||
// Serialize sessions
|
||||
passport.serializeUser(function (user, done) {
|
||||
user.updateSignedTime();
|
||||
|
||||
@@ -31,17 +31,23 @@ exports.forgot = function (req, res, next) {
|
||||
},
|
||||
// Lookup user by username
|
||||
function (token, done) {
|
||||
if (req.body.username) {
|
||||
if (req.body.usernameOrEmail) {
|
||||
|
||||
var usernameOrEmail = String(req.body.usernameOrEmail).toLowerCase();
|
||||
|
||||
User.findOne({
|
||||
username: req.body.username.toLowerCase()
|
||||
$or: [
|
||||
{ username: usernameOrEmail },
|
||||
{ email: usernameOrEmail }
|
||||
]
|
||||
}, '-salt -password', function (err, user) {
|
||||
if (err || !user) {
|
||||
return res.status(400).send({
|
||||
message: 'No account with that username has been found'
|
||||
message: 'No account with that username or email has been found'
|
||||
});
|
||||
} else if (user.provider !== 'local') {
|
||||
return res.status(400).send({
|
||||
message: 'It seems like you signed up using your ' + user.provider + ' account'
|
||||
message: 'It seems like you signed up using your ' + user.provider + ' account, please sign in using that provider.'
|
||||
});
|
||||
} else {
|
||||
user.resetPasswordToken = token;
|
||||
@@ -54,7 +60,7 @@ exports.forgot = function (req, res, next) {
|
||||
});
|
||||
} else {
|
||||
return res.status(422).send({
|
||||
message: 'Username field must not be blank'
|
||||
message: 'Username/email field must not be blank'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -81,7 +81,7 @@ exports.changeProfilePicture = function (req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
function uploadImage () {
|
||||
function uploadImage() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
upload(req, res, function (uploadError) {
|
||||
if (uploadError) {
|
||||
@@ -93,7 +93,7 @@ exports.changeProfilePicture = function (req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser () {
|
||||
function updateUser() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
user.profileImageURL = config.uploads.profile.image.dest + req.file.filename;
|
||||
user.save(function (err, theuser) {
|
||||
@@ -106,12 +106,20 @@ exports.changeProfilePicture = function (req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
function deleteOldImage () {
|
||||
function deleteOldImage() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (existingImageUrl !== User.schema.path('profileImageURL').defaultValue) {
|
||||
fs.unlink(existingImageUrl, function (unlinkError) {
|
||||
if (unlinkError) {
|
||||
console.log(unlinkError);
|
||||
|
||||
// If file didn't exist, no need to reject promise
|
||||
if (unlinkError.code === 'ENOENT') {
|
||||
console.log('Removing profile image failed because file did not exist.');
|
||||
return resolve();
|
||||
}
|
||||
|
||||
console.error(unlinkError);
|
||||
|
||||
reject({
|
||||
message: 'Error occurred while deleting old profile picture'
|
||||
});
|
||||
@@ -125,7 +133,7 @@ exports.changeProfilePicture = function (req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
function login () {
|
||||
function login() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
req.login(user, function (err) {
|
||||
if (err) {
|
||||
|
||||
@@ -11,7 +11,8 @@ var mongoose = require('mongoose'),
|
||||
validator = require('validator'),
|
||||
generatePassword = require('generate-password'),
|
||||
owasp = require('owasp-password-strength-test'),
|
||||
moment = require('moment');
|
||||
moment = require('moment'),
|
||||
chalk = require('chalk');
|
||||
|
||||
owasp.config(config.shared.owasp);
|
||||
|
||||
@@ -424,4 +425,92 @@ UserSchema.statics.generateRandomPassphrase = function () {
|
||||
});
|
||||
};
|
||||
|
||||
UserSchema.statics.seed = seed;
|
||||
|
||||
mongoose.model('User', UserSchema);
|
||||
|
||||
/**
|
||||
* Seeds the User collection with document (User)
|
||||
* and provided options.
|
||||
*/
|
||||
function seed(doc, options) {
|
||||
var User = mongoose.model('User');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
skipDocument()
|
||||
.then(add)
|
||||
.then(function (response) {
|
||||
return resolve(response);
|
||||
})
|
||||
.catch(function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
|
||||
function skipDocument() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
User
|
||||
.findOne({
|
||||
username: doc.username
|
||||
})
|
||||
.exec(function (err, existing) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
if (!existing) {
|
||||
return resolve(false);
|
||||
}
|
||||
|
||||
if (existing && !options.overwrite) {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
// Remove User (overwrite)
|
||||
|
||||
existing.remove(function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function add(skip) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (skip) {
|
||||
return resolve({
|
||||
message: chalk.yellow('Database Seeding: User\t\t' + doc.username + ' skipped')
|
||||
});
|
||||
}
|
||||
|
||||
User.generateRandomPassphrase()
|
||||
.then(function (passphrase) {
|
||||
var user = new User(doc);
|
||||
|
||||
user.provider = 'local';
|
||||
user.displayName = user.firstName + ' ' + user.lastName;
|
||||
user.password = passphrase;
|
||||
|
||||
user.save(function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve({
|
||||
message: 'Database Seeding: User\t\t' + user.username + ' added with password set to ' + passphrase
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
return reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
(function () {
|
||||
// Password Validator Directive Spec
|
||||
describe('PasswordValidatorDirective', function() {
|
||||
describe('PasswordValidatorDirective', function () {
|
||||
// Initialize global variables
|
||||
var scope,
|
||||
element,
|
||||
@@ -12,7 +12,7 @@
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
beforeEach(inject(function(_$rootScope_, _$compile_) {
|
||||
beforeEach(inject(function (_$rootScope_, _$compile_) {
|
||||
// Set a new global scope
|
||||
scope = _$rootScope_.$new();
|
||||
$compile = _$compile_;
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
// inject allows you to use AngularJS dependency injection
|
||||
// to retrieve and use other services
|
||||
inject(function($compile) {
|
||||
inject(function ($compile) {
|
||||
var form = $compile(template)(scope);
|
||||
element = form.find('div');
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
describe('Initialize', function() {
|
||||
describe('Initialize', function () {
|
||||
beforeEach(function () {
|
||||
compileDirective();
|
||||
});
|
||||
@@ -65,7 +65,7 @@
|
||||
expect(scope.requirementsProgress).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should be valid when password meets requirements - "P@ssw0rd!!""', function() {
|
||||
it('should be valid when password meets requirements - "P@ssw0rd!!""', function () {
|
||||
scope.passwordMock.password = 'P@ssw0rd!!';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -76,7 +76,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('100');
|
||||
});
|
||||
|
||||
it('should be valid when password meets requirements with a passphrase', function() {
|
||||
it('should be valid when password meets requirements with a passphrase', function () {
|
||||
scope.passwordMock.password = 'Open-Source Full-Stack Solution for MEAN';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -87,7 +87,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('100');
|
||||
});
|
||||
|
||||
it('should not allow a less than 10 characters long - "P@$$w0rd!"', function() {
|
||||
it('should not allow a less than 10 characters long - "P@$$w0rd!"', function () {
|
||||
scope.passwordMock.password = 'P@$$w0rd!';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -99,7 +99,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should not allow a greater than 128 characters long', function() {
|
||||
it('should not allow a greater than 128 characters long', function () {
|
||||
scope.passwordMock.password = ')!/uLT="lh&:`6X!]|15o!$!TJf,.13l?vG].-j],lFPe/QhwN#{Z<[*1nX@n1^?WW-%_.*D)m$toB+N7z}kcN#B_d(f41h%w@0F!]igtSQ1gl~6sEV&r~}~1ub>If1c+';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -111,7 +111,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should not allow more than 3 or more repeating characters - "P@$$w0rd!!!"', function() {
|
||||
it('should not allow more than 3 or more repeating characters - "P@$$w0rd!!!"', function () {
|
||||
scope.passwordMock.password = 'P@$$w0rd!!!';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -123,7 +123,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should not allow a password with no uppercase letters - "p@$$w0rd!!"', function() {
|
||||
it('should not allow a password with no uppercase letters - "p@$$w0rd!!"', function () {
|
||||
scope.passwordMock.password = 'p@$$w0rd!!';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -135,7 +135,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should not allow a password with less than one number - "P@$$word!!"', function() {
|
||||
it('should not allow a password with less than one number - "P@$$word!!"', function () {
|
||||
scope.passwordMock.password = 'P@$$word!!';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -147,7 +147,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should not allow a password with less than one special character - "Passw0rdss"', function() {
|
||||
it('should not allow a password with less than one special character - "Passw0rdss"', function () {
|
||||
scope.passwordMock.password = 'Passw0rdss';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -159,7 +159,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should show 20% progress and "danger" color', function() {
|
||||
it('should show 20% progress and "danger" color', function () {
|
||||
scope.passwordMock.password = 'P';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -168,7 +168,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('20');
|
||||
});
|
||||
|
||||
it('should show 40% progress and "warning" color', function() {
|
||||
it('should show 40% progress and "warning" color', function () {
|
||||
scope.passwordMock.password = 'Pa';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -177,7 +177,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('40');
|
||||
});
|
||||
|
||||
it('should show 60% progress and "info" color', function() {
|
||||
it('should show 60% progress and "info" color', function () {
|
||||
scope.passwordMock.password = 'Pa$';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -186,7 +186,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('60');
|
||||
});
|
||||
|
||||
it('should show 80% progress and "primary" color', function() {
|
||||
it('should show 80% progress and "primary" color', function () {
|
||||
scope.passwordMock.password = 'Pa$$w0rd';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
@@ -195,7 +195,7 @@
|
||||
expect(scope.requirementsProgress).toEqual('80');
|
||||
});
|
||||
|
||||
it('should show 100% progress and "success" color', function() {
|
||||
it('should show 100% progress and "success" color', function () {
|
||||
scope.passwordMock.password = 'Pa$$w0rd!!';
|
||||
compileDirective();
|
||||
scope.$digest();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
(function () {
|
||||
// Password Verify Directive Spec
|
||||
describe('PasswordVerifyDirective', function() {
|
||||
describe('PasswordVerifyDirective', function () {
|
||||
// Initialize global variables
|
||||
var scope,
|
||||
element,
|
||||
@@ -12,7 +12,7 @@
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
beforeEach(inject(function(_$rootScope_, _$compile_) {
|
||||
beforeEach(inject(function (_$rootScope_, _$compile_) {
|
||||
// Set a new global scope
|
||||
scope = _$rootScope_.$new();
|
||||
$compile = _$compile_;
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
// inject allows you to use AngularJS dependency injection
|
||||
// to retrieve and use other services
|
||||
inject(function($compile) {
|
||||
inject(function ($compile) {
|
||||
var form = $compile(template)(scope);
|
||||
element = form.find('div');
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
describe('Initialize', function() {
|
||||
describe('Initialize', function () {
|
||||
beforeEach(function () {
|
||||
compileDirective();
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
(function () {
|
||||
// Password controller Spec
|
||||
describe('PasswordController', function() {
|
||||
describe('PasswordController', function () {
|
||||
// Initialize global variables
|
||||
var PasswordController,
|
||||
scope,
|
||||
@@ -12,11 +12,11 @@
|
||||
$window,
|
||||
Notification;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
jasmine.addMatchers({
|
||||
toEqualData: function(util, customEqualityTesters) {
|
||||
toEqualData: function (util, customEqualityTesters) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
compare: function (actual, expected) {
|
||||
return {
|
||||
pass: angular.equals(actual, expected)
|
||||
};
|
||||
@@ -29,8 +29,8 @@
|
||||
// Load the main application module
|
||||
beforeEach(module(ApplicationConfiguration.applicationModuleName));
|
||||
|
||||
describe('Logged in user', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _UsersService_, _Authentication_, _$stateParams_, _$httpBackend_, _$location_) {
|
||||
describe('Logged in user', function () {
|
||||
beforeEach(inject(function ($controller, $rootScope, _UsersService_, _Authentication_, _$stateParams_, _$httpBackend_, _$location_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
|
||||
@@ -55,13 +55,13 @@
|
||||
});
|
||||
}));
|
||||
|
||||
it('should redirect logged in user to home', function() {
|
||||
it('should redirect logged in user to home', function () {
|
||||
expect($location.path).toHaveBeenCalledWith('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Logged out user', function() {
|
||||
beforeEach(inject(function($controller, $rootScope, _$window_, _$stateParams_, _$httpBackend_, _$location_, _Notification_) {
|
||||
describe('Logged out user', function () {
|
||||
beforeEach(inject(function ($controller, $rootScope, _$window_, _$stateParams_, _$httpBackend_, _$location_, _Notification_) {
|
||||
// Set a new global scope
|
||||
scope = $rootScope.$new();
|
||||
|
||||
@@ -87,22 +87,22 @@
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not redirect to home', function() {
|
||||
it('should not redirect to home', function () {
|
||||
expect($location.path).not.toHaveBeenCalledWith('/');
|
||||
});
|
||||
|
||||
describe('askForPasswordReset', function() {
|
||||
describe('askForPasswordReset', function () {
|
||||
var credentials = {
|
||||
username: 'test',
|
||||
password: 'P@ssw0rd!!'
|
||||
};
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
scope.vm.credentials = credentials;
|
||||
});
|
||||
|
||||
describe('POST error', function() {
|
||||
describe('POST error', function () {
|
||||
var errorMessage = 'No account with that username has been found';
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
$httpBackend.when('POST', '/api/auth/forgot', credentials).respond(400, {
|
||||
'message': errorMessage
|
||||
});
|
||||
@@ -111,18 +111,18 @@
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should clear form', function() {
|
||||
it('should clear form', function () {
|
||||
expect(scope.vm.credentials).toBe(null);
|
||||
});
|
||||
|
||||
it('should call Notification.error with response message', function() {
|
||||
it('should call Notification.error with response message', function () {
|
||||
expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: '<i class="glyphicon glyphicon-remove"></i> Failed to send password reset email!', delay: 4000 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST success', function() {
|
||||
describe('POST success', function () {
|
||||
var successMessage = 'An email has been sent to the provided email with further instructions.';
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
$httpBackend.when('POST', '/api/auth/forgot', credentials).respond({
|
||||
'message': successMessage
|
||||
});
|
||||
@@ -131,27 +131,27 @@
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should clear form', function() {
|
||||
it('should clear form', function () {
|
||||
expect(scope.vm.credentials).toBe(null);
|
||||
});
|
||||
|
||||
it('should call Notification.success with response message', function() {
|
||||
it('should call Notification.success with response message', function () {
|
||||
expect(Notification.success).toHaveBeenCalledWith({ message: successMessage, title: '<i class="glyphicon glyphicon-ok"></i> Password reset email sent successfully!' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('resetUserPassword', function() {
|
||||
describe('resetUserPassword', function () {
|
||||
var token = 'testToken';
|
||||
var passwordDetails = {
|
||||
password: 'test'
|
||||
};
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
$stateParams.token = token;
|
||||
scope.vm.passwordDetails = passwordDetails;
|
||||
});
|
||||
|
||||
it('POST error should call Notification.error with response message', function() {
|
||||
it('POST error should call Notification.error with response message', function () {
|
||||
var errorMessage = 'Passwords do not match';
|
||||
$httpBackend.when('POST', '/api/auth/reset/' + token, passwordDetails).respond(400, {
|
||||
'message': errorMessage
|
||||
@@ -163,26 +163,26 @@
|
||||
expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: '<i class="glyphicon glyphicon-remove"></i> Password reset failed!', delay: 4000 });
|
||||
});
|
||||
|
||||
describe('POST success', function() {
|
||||
describe('POST success', function () {
|
||||
var user = {
|
||||
username: 'test'
|
||||
};
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
$httpBackend.when('POST', '/api/auth/reset/' + token, passwordDetails).respond(user);
|
||||
|
||||
scope.vm.resetUserPassword(true);
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('should clear password form', function() {
|
||||
it('should clear password form', function () {
|
||||
expect(scope.vm.passwordDetails).toBe(null);
|
||||
});
|
||||
|
||||
it('should attach user profile', function() {
|
||||
it('should attach user profile', function () {
|
||||
expect(scope.vm.authentication.user.username).toEqual(user.username);
|
||||
});
|
||||
|
||||
it('should redirect to password reset success view with Notification.success', function() {
|
||||
it('should redirect to password reset success view with Notification.success', function () {
|
||||
expect(Notification.success).toHaveBeenCalledWith({ message: '<i class="glyphicon glyphicon-ok"></i> Password reset successful!' });
|
||||
expect($location.path).toHaveBeenCalledWith('/password/reset/success');
|
||||
});
|
||||
|
||||
@@ -421,7 +421,7 @@ describe('Users E2E Tests:', function () {
|
||||
expect(element.all(by.css('.error-text')).get(1).getText()).toBe('Password is required.');
|
||||
});
|
||||
|
||||
it('Verify that the user is logged in', function() {
|
||||
it('Verify that the user is logged in', function () {
|
||||
// Make sure user is signed out first
|
||||
signout();
|
||||
// Sign in
|
||||
|
||||
@@ -186,7 +186,7 @@ describe('User Model Unit Tests:', function () {
|
||||
_user3.email = _user1.email;
|
||||
_user3.save(function (err) {
|
||||
should.exist(err);
|
||||
_user1.remove(function(err) {
|
||||
_user1.remove(function (err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
@@ -224,7 +224,7 @@ describe('User Model Unit Tests:', function () {
|
||||
_user1.save(function (err) {
|
||||
should.not.exist(err);
|
||||
_user1.password.should.not.equal(passwordBeforeSave);
|
||||
_user1.remove(function(err) {
|
||||
_user1.remove(function (err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
@@ -238,7 +238,7 @@ describe('User Model Unit Tests:', function () {
|
||||
_user1.save(function (err) {
|
||||
should.not.exist(err);
|
||||
_user1.password.should.not.equal(passwordBeforeSave);
|
||||
_user1.remove(function(err) {
|
||||
_user1.remove(function (err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
@@ -246,7 +246,7 @@ describe('User Model Unit Tests:', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('User Password Validation Tests', function() {
|
||||
describe('User Password Validation Tests', function () {
|
||||
it('should validate when the password strength passes - "P@$$w0rd!!"', function () {
|
||||
var _user1 = new User(user1);
|
||||
_user1.password = 'P@$$w0rd!!';
|
||||
@@ -351,7 +351,7 @@ describe('User Model Unit Tests:', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('User E-mail Validation Tests', function() {
|
||||
describe('User E-mail Validation Tests', function () {
|
||||
it('should not allow invalid email address - "123"', function (done) {
|
||||
var _user1 = new User(user1);
|
||||
|
||||
@@ -645,12 +645,12 @@ describe('User Model Unit Tests:', function () {
|
||||
|
||||
});
|
||||
|
||||
describe('Username Validation', function() {
|
||||
it('should show error to save username beginning with .', function(done) {
|
||||
describe('Username Validation', function () {
|
||||
it('should show error to save username beginning with .', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = '.login';
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
@@ -660,67 +660,67 @@ describe('User Model Unit Tests:', function () {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = config.illegalUsernames[Math.floor(Math.random() * config.illegalUsernames.length)];
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error to save username end with .', function(done) {
|
||||
it('should show error to save username end with .', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = 'login.';
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error to save username with ..', function(done) {
|
||||
it('should show error to save username with ..', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = 'log..in';
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error to save username shorter than 3 character', function(done) {
|
||||
it('should show error to save username shorter than 3 character', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = 'lo';
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error saving a username without at least one alphanumeric character', function(done) {
|
||||
it('should show error saving a username without at least one alphanumeric character', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = '-_-';
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error saving a username longer than 34 characters', function(done) {
|
||||
it('should show error saving a username longer than 34 characters', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = 'l'.repeat(35);
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should save username with dot', function(done) {
|
||||
it('should save username with dot', function (done) {
|
||||
var _user = new User(user1);
|
||||
|
||||
_user.username = 'log.in';
|
||||
_user.save(function(err) {
|
||||
_user.save(function (err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ var semver = require('semver'),
|
||||
path = require('path'),
|
||||
mongoose = require('mongoose'),
|
||||
User = mongoose.model('User'),
|
||||
config = require(path.resolve('./config/config')),
|
||||
express = require(path.resolve('./config/lib/express'));
|
||||
|
||||
/**
|
||||
@@ -26,7 +27,7 @@ describe('User CRUD tests', function () {
|
||||
|
||||
before(function (done) {
|
||||
// Get application
|
||||
app = express.init(mongoose);
|
||||
app = express.init(mongoose.connection.db);
|
||||
agent = request.agent(app);
|
||||
|
||||
done();
|
||||
@@ -325,7 +326,7 @@ describe('User CRUD tests', function () {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
username: 'some_username_that_doesnt_exist'
|
||||
usernameOrEmail: 'some_username_that_doesnt_exist'
|
||||
})
|
||||
.expect(400)
|
||||
.end(function (err, res) {
|
||||
@@ -334,13 +335,13 @@ describe('User CRUD tests', function () {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
res.body.message.should.equal('No account with that username has been found');
|
||||
res.body.message.should.equal('No account with that username or email has been found');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('forgot password should return 400 for no username provided', function (done) {
|
||||
it('forgot password should return 400 for empty username/email', function (done) {
|
||||
var provider = 'facebook';
|
||||
user.provider = provider;
|
||||
user.roles = ['user'];
|
||||
@@ -349,7 +350,7 @@ describe('User CRUD tests', function () {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
username: ''
|
||||
usernameOrEmail: ''
|
||||
})
|
||||
.expect(422)
|
||||
.end(function (err, res) {
|
||||
@@ -358,7 +359,29 @@ describe('User CRUD tests', function () {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
res.body.message.should.equal('Username field must not be blank');
|
||||
res.body.message.should.equal('Username/email field must not be blank');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('forgot password should return 400 for no username or email provided', function (done) {
|
||||
var provider = 'facebook';
|
||||
user.provider = provider;
|
||||
user.roles = ['user'];
|
||||
|
||||
user.save(function (err) {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({})
|
||||
.expect(422)
|
||||
.end(function (err, res) {
|
||||
// Handle error
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
res.body.message.should.equal('Username/email field must not be blank');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
@@ -373,7 +396,7 @@ describe('User CRUD tests', function () {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
username: user.username
|
||||
usernameOrEmail: user.username
|
||||
})
|
||||
.expect(400)
|
||||
.end(function (err, res) {
|
||||
@@ -382,20 +405,20 @@ describe('User CRUD tests', function () {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
res.body.message.should.equal('It seems like you signed up using your ' + user.provider + ' account');
|
||||
res.body.message.should.equal('It seems like you signed up using your ' + user.provider + ' account, please sign in using that provider.');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('forgot password should be able to reset password for user password reset request', function (done) {
|
||||
it('forgot password should be able to reset password for user password reset request using username', function (done) {
|
||||
user.roles = ['user'];
|
||||
|
||||
user.save(function (err) {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
username: user.username
|
||||
usernameOrEmail: user.username
|
||||
})
|
||||
.expect(400)
|
||||
.end(function (err, res) {
|
||||
@@ -404,7 +427,33 @@ describe('User CRUD tests', function () {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
User.findOne({ username: user.username.toLowerCase() }, function(err, userRes) {
|
||||
User.findOne({ username: user.username.toLowerCase() }, function (err, userRes) {
|
||||
userRes.resetPasswordToken.should.not.be.empty();
|
||||
should.exist(userRes.resetPasswordExpires);
|
||||
res.body.message.should.be.equal('Failure sending email');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('forgot password should be able to reset password for user password reset request using email', function (done) {
|
||||
user.roles = ['user'];
|
||||
|
||||
user.save(function (err) {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
usernameOrEmail: user.email
|
||||
})
|
||||
.expect(400)
|
||||
.end(function (err, res) {
|
||||
// Handle error
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
User.findOne({ username: user.username.toLowerCase() }, function (err, userRes) {
|
||||
userRes.resetPasswordToken.should.not.be.empty();
|
||||
should.exist(userRes.resetPasswordExpires);
|
||||
res.body.message.should.be.equal('Failure sending email');
|
||||
@@ -421,7 +470,7 @@ describe('User CRUD tests', function () {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
username: user.username
|
||||
usernameOrEmail: user.username
|
||||
})
|
||||
.expect(400)
|
||||
.end(function (err, res) {
|
||||
@@ -430,7 +479,7 @@ describe('User CRUD tests', function () {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
User.findOne({ username: user.username.toLowerCase() }, function(err, userRes) {
|
||||
User.findOne({ username: user.username.toLowerCase() }, function (err, userRes) {
|
||||
userRes.resetPasswordToken.should.not.be.empty();
|
||||
should.exist(userRes.resetPasswordExpires);
|
||||
|
||||
@@ -458,7 +507,7 @@ describe('User CRUD tests', function () {
|
||||
should.not.exist(err);
|
||||
agent.post('/api/auth/forgot')
|
||||
.send({
|
||||
username: user.username
|
||||
usernameOrEmail: user.username
|
||||
})
|
||||
.expect(400)
|
||||
.end(function (err, res) {
|
||||
@@ -1030,6 +1079,39 @@ describe('User CRUD tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to change profile picture and not fail if existing picture file does not exist', function (done) {
|
||||
|
||||
user.profileImageURL = config.uploads.profile.image.dest + 'non-existing.png';
|
||||
|
||||
user.save(function (saveErr) {
|
||||
// Handle error
|
||||
if (saveErr) {
|
||||
return done(saveErr);
|
||||
}
|
||||
|
||||
agent.post('/api/auth/signin')
|
||||
.send(credentials)
|
||||
.expect(200)
|
||||
.end(function (signinErr) {
|
||||
// Handle signin error
|
||||
if (signinErr) {
|
||||
return done(signinErr);
|
||||
}
|
||||
|
||||
agent.post('/api/users/picture')
|
||||
.attach('newProfilePicture', './modules/users/client/img/profile/default.png')
|
||||
.expect(200)
|
||||
.end(function (userInfoErr) {
|
||||
|
||||
should.not.exist(userInfoErr);
|
||||
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
User.remove().exec(done);
|
||||
});
|
||||
|
||||
41
package.json
41
package.json
@@ -32,35 +32,35 @@
|
||||
"test:coverage": "gulp test:coverage",
|
||||
"postinstall": "npm run bower",
|
||||
"generate-ssl-certs": "scripts/generate-ssl-certs.sh",
|
||||
"snyk-protect": "snyk protect",
|
||||
"prepublish": "npm run snyk-protect"
|
||||
"seed": "gulp seed",
|
||||
"seed:prod": "gulp seed:prod",
|
||||
"seed:test": "gulp seed:test"
|
||||
},
|
||||
"dependencies": {
|
||||
"acl": "~0.4.10",
|
||||
"async": "~2.3.0",
|
||||
"async": "~2.5.0",
|
||||
"bencoding": "0.0.1",
|
||||
"body-parser": "~1.17.1",
|
||||
"bower": "~1.8.0",
|
||||
"chalk": "~2.0.1",
|
||||
"chalk": "~2.1.0",
|
||||
"compression": "~1.7.0",
|
||||
"connect-flash": "~0.1.1",
|
||||
"connect-mongo": "~1.3.2",
|
||||
"cookie-parser": "~1.4.1",
|
||||
"crypto": "0.0.3",
|
||||
"express": "~4.15.2",
|
||||
"express-hbs": "^1.0.4",
|
||||
"express-session": "~1.15.2",
|
||||
"generate-password": "~1.3.0",
|
||||
"glob": "~7.1.1",
|
||||
"helmet": "~3.6.1",
|
||||
"helmet": "~3.8.1",
|
||||
"irc": "^0.5.2",
|
||||
"jasmine-core": "~2.5.2",
|
||||
"jasmine-core": "~2.7.0",
|
||||
"lodash": "~4.17.4",
|
||||
"lusca": "~1.4.1",
|
||||
"lusca": "~1.5.1",
|
||||
"method-override": "~2.3.8",
|
||||
"mocha": "~3.4.2",
|
||||
"moment": "^2.18.1",
|
||||
"mongoose": "~4.10.2",
|
||||
"mongoose": "~4.11.3",
|
||||
"morgan": "~1.8.1",
|
||||
"moviedb": "^0.2.8",
|
||||
"multer": "~1.3.0",
|
||||
@@ -87,16 +87,15 @@
|
||||
"devDependencies": {
|
||||
"coveralls": "~2.13.0",
|
||||
"del": "^3.0.0",
|
||||
"eslint": "~2.2.0",
|
||||
"eslint-config-airbnb": "~6.0.2",
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-angular-templatecache": "~2.0.0",
|
||||
"gulp-autoprefixer": "~3.1.0",
|
||||
"gulp-autoprefixer": "~4.0.0",
|
||||
"gulp-concat": "~2.6.0",
|
||||
"gulp-csslint": "~1.0.0",
|
||||
"gulp-csso": "~3.0.0",
|
||||
"gulp-eslint": "~3.0.1",
|
||||
"gulp-imagemin": "~3.2.0",
|
||||
"gulp-imagemin": "~3.3.0",
|
||||
"gulp-istanbul": "~1.1.1",
|
||||
"gulp-less": "~3.3.0",
|
||||
"gulp-load-plugins": "~1.5.0",
|
||||
@@ -106,23 +105,19 @@
|
||||
"gulp-protractor": "^4.0.0",
|
||||
"gulp-refresh": "~1.1.0",
|
||||
"gulp-rename": "~1.2.2",
|
||||
"gulp-rev": "^7.1.2",
|
||||
"gulp-rev": "~8.0.0",
|
||||
"gulp-sass": "~3.1.0",
|
||||
"gulp-uglify": "~2.1.2",
|
||||
"gulp-util": "~3.0.7",
|
||||
"gulp-uglify": "~3.0.0",
|
||||
"imagemin-pngquant": "~5.0.0",
|
||||
"istanbul": "~0.4.2",
|
||||
"karma": "~1.6.0",
|
||||
"karma-chrome-launcher": "~2.0.0",
|
||||
"karma": "~1.7.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage": "~1.1.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-mocha-reporter": "~2.2.3",
|
||||
"karma-ng-html2js-preprocessor": "~1.0.0",
|
||||
"lcov-result-merger": "~1.2.0",
|
||||
"run-sequence": "~2.0.0",
|
||||
"semver": "~5.3.0",
|
||||
"run-sequence": "~2.1.0",
|
||||
"semver": "~5.4.1",
|
||||
"should": "~11.2.1",
|
||||
"supertest": "~3.0.0"
|
||||
},
|
||||
"snyk": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user