Merge branch 'master' into feat/replacing-gulp-node-inspector

This commit is contained in:
Liran Tal
2016-10-13 22:59:34 +03:00
64 changed files with 424 additions and 304 deletions

View File

@@ -10,6 +10,7 @@
"angular-messages": "~1.5.0",
"angular-mocks": "~1.5.0",
"angular-resource": "~1.5.0",
"angular-ui-notification": "~0.2.0",
"angular-ui-router": "~0.2.18",
"bootstrap": "~3.3.6",
"ng-file-upload": "^12.1.0",

View File

@@ -9,7 +9,8 @@ module.exports = {
// bower:css
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
'public/lib/ng-img-crop/compile/unminified/ng-img-crop.css'
'public/lib/ng-img-crop/compile/unminified/ng-img-crop.css',
'public/lib/angular-ui-notification/dist/angular-ui-notification.css'
// endbower
],
js: [
@@ -22,6 +23,7 @@ module.exports = {
'public/lib/angular-messages/angular-messages.js',
'public/lib/angular-mocks/angular-mocks.js',
'public/lib/angular-resource/angular-resource.js',
'public/lib/angular-ui-notification/dist/angular-ui-notification.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/owasp-password-strength-test/owasp-password-strength-test.js',
// endbower

View File

@@ -10,6 +10,7 @@ module.exports = {
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
'public/lib/ng-img-crop/compile/minified/ng-img-crop.css',
'public/lib/angular-ui-notification/dist/angular-ui-notification.min.css'
// endbower
],
js: [
@@ -20,6 +21,7 @@ module.exports = {
'public/lib/angular-messages/angular-messages.min.js',
'public/lib/angular-mocks/angular-mocks.js',
'public/lib/angular-resource/angular-resource.min.js',
'public/lib/angular-ui-notification/dist/angular-ui-notification.min.js',
'public/lib/angular-ui-router/release/angular-ui-router.min.js',
'public/lib/ng-file-upload/ng-file-upload.min.js',
'public/lib/ng-img-crop/compile/minified/ng-img-crop.js',

View File

@@ -68,29 +68,29 @@ gulp.task('nodemon-nodebug', function () {
// Watch Files For Changes
gulp.task('watch', function () {
// Start livereload
plugins.livereload.listen();
plugins.refresh.listen();
// Add watch rules
gulp.watch(defaultAssets.server.views).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.server.allJS, ['eslint']).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.client.js, ['eslint']).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.client.css, ['csslint']).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.client.sass, ['sass', 'csslint']).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.client.less, ['less', 'csslint']).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.server.views).on('change', plugins.refresh.changed);
gulp.watch(defaultAssets.server.allJS, ['eslint']).on('change', plugins.refresh.changed);
gulp.watch(defaultAssets.client.js, ['eslint']).on('change', plugins.refresh.changed);
gulp.watch(defaultAssets.client.css, ['csslint']).on('change', plugins.refresh.changed);
gulp.watch(defaultAssets.client.sass, ['sass', 'csslint']).on('change', plugins.refresh.changed);
gulp.watch(defaultAssets.client.less, ['less', 'csslint']).on('change', plugins.refresh.changed);
if (process.env.NODE_ENV === 'production') {
gulp.watch(defaultAssets.server.gulpConfig, ['templatecache', 'eslint']);
gulp.watch(defaultAssets.client.views, ['templatecache']).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.client.views, ['templatecache']).on('change', plugins.refresh.changed);
} else {
gulp.watch(defaultAssets.server.gulpConfig, ['eslint']);
gulp.watch(defaultAssets.client.views).on('change', plugins.livereload.changed);
gulp.watch(defaultAssets.client.views).on('change', plugins.refresh.changed);
}
});
// Watch server test files
gulp.task('watch:server:run-tests', function () {
// Start livereload
plugins.livereload.listen();
plugins.refresh.listen();
// Add Server Test file rules
gulp.watch([testAssets.tests.server, defaultAssets.server.allJS], ['test:server']).on('change', function (file) {
@@ -108,7 +108,7 @@ gulp.task('watch:server:run-tests', function () {
});
});
plugins.livereload.changed();
plugins.refresh.changed();
});
});

View File

@@ -16,7 +16,7 @@
})
.state('admin.articles.list', {
url: '',
templateUrl: 'modules/articles/client/views/admin/list-articles.client.view.html',
templateUrl: '/modules/articles/client/views/admin/list-articles.client.view.html',
controller: 'ArticlesAdminListController',
controllerAs: 'vm',
data: {
@@ -25,7 +25,7 @@
})
.state('admin.articles.create', {
url: '/create',
templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
templateUrl: '/modules/articles/client/views/admin/form-article.client.view.html',
controller: 'ArticlesAdminController',
controllerAs: 'vm',
data: {
@@ -37,7 +37,7 @@
})
.state('admin.articles.edit', {
url: '/:articleId/edit',
templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
templateUrl: '/modules/articles/client/views/admin/form-article.client.view.html',
controller: 'ArticlesAdminController',
controllerAs: 'vm',
data: {

View File

@@ -16,7 +16,7 @@
})
.state('articles.list', {
url: '',
templateUrl: 'modules/articles/client/views/list-articles.client.view.html',
templateUrl: '/modules/articles/client/views/list-articles.client.view.html',
controller: 'ArticlesListController',
controllerAs: 'vm',
data: {
@@ -25,7 +25,7 @@
})
.state('articles.view', {
url: '/:articleId',
templateUrl: 'modules/articles/client/views/view-article.client.view.html',
templateUrl: '/modules/articles/client/views/view-article.client.view.html',
controller: 'ArticlesController',
controllerAs: 'vm',
resolve: {

View File

@@ -5,14 +5,13 @@
.module('articles.admin')
.controller('ArticlesAdminController', ArticlesAdminController);
ArticlesAdminController.$inject = ['$scope', '$state', '$window', 'articleResolve', 'Authentication'];
ArticlesAdminController.$inject = ['$scope', '$state', '$window', 'articleResolve', 'Authentication', 'Notification'];
function ArticlesAdminController($scope, $state, $window, article, Authentication) {
function ArticlesAdminController($scope, $state, $window, article, Authentication, Notification) {
var vm = this;
vm.article = article;
vm.authentication = Authentication;
vm.error = null;
vm.form = {};
vm.remove = remove;
vm.save = save;
@@ -22,6 +21,7 @@
if ($window.confirm('Are you sure you want to delete?')) {
vm.article.$remove(function() {
$state.go('admin.articles.list');
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Article deleted successfully!' });
});
}
}
@@ -40,10 +40,11 @@
function successCallback(res) {
$state.go('admin.articles.list'); // should we send the User to the list or the updated Article's view?
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Article saved successfully!' });
}
function errorCallback(res) {
vm.error = res.data.message;
Notification.error({ message: res.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Article save error!' });
}
}
}

View File

@@ -12,7 +12,6 @@
vm.article = article;
vm.authentication = Authentication;
vm.error = null;
}
}());

View File

@@ -5,10 +5,10 @@
.module('articles.services')
.factory('ArticlesService', ArticlesService);
ArticlesService.$inject = ['$resource'];
ArticlesService.$inject = ['$resource', '$log'];
function ArticlesService($resource) {
var Article = $resource('api/articles/:articleId', {
function ArticlesService($resource, $log) {
var Article = $resource('/api/articles/:articleId', {
articleId: '@_id'
}, {
update: {
@@ -47,7 +47,7 @@
function handleError(error) {
// Log error
console.log(error);
$log.error(error);
}
}
}());

View File

@@ -24,9 +24,6 @@
<div class="form-group">
<button type="submit" class="btn btn-default">{{vm.article._id ? 'Update' : 'Create'}}</button>
</div>
<div ng-show="vm.error" class="text-danger">
<strong ng-bind="vm.error"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -17,7 +17,7 @@ exports.create = function (req, res) {
article.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -51,7 +51,7 @@ exports.update = function (req, res) {
article.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -68,7 +68,7 @@ exports.delete = function (req, res) {
article.remove(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -83,7 +83,7 @@ exports.delete = function (req, res) {
exports.list = function (req, res) {
Article.find().sort('-created').populate('user', 'displayName').exec(function (err, articles) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {

View File

@@ -9,7 +9,8 @@
$state,
Authentication,
ArticlesService,
mockArticle;
mockArticle,
Notification;
// The $resource service augments the response object with methods for updating and deleting the resource.
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
@@ -36,7 +37,7 @@
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function ($controller, $rootScope, _$state_, _$httpBackend_, _Authentication_, _ArticlesService_) {
beforeEach(inject(function ($controller, $rootScope, _$state_, _$httpBackend_, _Authentication_, _ArticlesService_, _Notification_) {
// Set a new global scope
$scope = $rootScope.$new();
@@ -45,6 +46,10 @@
$state = _$state_;
Authentication = _Authentication_;
ArticlesService = _ArticlesService_;
Notification = _Notification_;
// Ignore parent template get on state transitions
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
// create mock article
mockArticle = new ArticlesService({
@@ -66,6 +71,8 @@
// Spy on state go
spyOn($state, 'go');
spyOn(Notification, 'error');
spyOn(Notification, 'success');
}));
describe('vm.save() as create', function () {
@@ -83,26 +90,28 @@
it('should send a POST request with the form input values and then locate to new object URL', inject(function (ArticlesService) {
// Set POST response
$httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(mockArticle);
$httpBackend.expectPOST('/api/articles', sampleArticlePostData).respond(mockArticle);
// Run controller functionality
$scope.vm.save(true);
$httpBackend.flush();
// Test Notification success was called
expect(Notification.success).toHaveBeenCalledWith({ message: '<i class="glyphicon glyphicon-ok"></i> Article saved successfully!' });
// Test URL redirection after the article was created
expect($state.go).toHaveBeenCalledWith('admin.articles.list');
}));
it('should set $scope.vm.error if error', function () {
it('should call Notification.error if error', function () {
var errorMessage = 'this is an error message';
$httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(400, {
$httpBackend.expectPOST('/api/articles', sampleArticlePostData).respond(400, {
message: errorMessage
});
$scope.vm.save(true);
$httpBackend.flush();
expect($scope.vm.error).toBe(errorMessage);
expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: '<i class="glyphicon glyphicon-remove"></i> Article save error!' });
});
});
@@ -120,11 +129,13 @@
$scope.vm.save(true);
$httpBackend.flush();
// Test Notification success was called
expect(Notification.success).toHaveBeenCalledWith({ message: '<i class="glyphicon glyphicon-ok"></i> Article saved successfully!' });
// Test URL location to new object
expect($state.go).toHaveBeenCalledWith('admin.articles.list');
}));
it('should set $scope.vm.error if error', inject(function (ArticlesService) {
it('should call Notification.error if error', inject(function (ArticlesService) {
var errorMessage = 'error';
$httpBackend.expectPUT(/api\/articles\/([0-9a-fA-F]{24})$/).respond(400, {
message: errorMessage
@@ -133,7 +144,7 @@
$scope.vm.save(true);
$httpBackend.flush();
expect($scope.vm.error).toBe(errorMessage);
expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: '<i class="glyphicon glyphicon-remove"></i> Article save error!' });
}));
});
@@ -152,6 +163,7 @@
$scope.vm.remove();
$httpBackend.flush();
expect(Notification.success).toHaveBeenCalledWith({ message: '<i class="glyphicon glyphicon-ok"></i> Article deleted successfully!' });
expect($state.go).toHaveBeenCalledWith('admin.articles.list');
});

View File

@@ -53,7 +53,7 @@
});
it('Should have templateUrl', function () {
expect(liststate.templateUrl).toBe('modules/articles/client/views/admin/list-articles.client.view.html');
expect(liststate.templateUrl).toBe('/modules/articles/client/views/admin/list-articles.client.view.html');
});
});
@@ -64,7 +64,7 @@
beforeEach(inject(function ($controller, $state, $templateCache) {
createstate = $state.get('admin.articles.create');
$templateCache.put('modules/articles/client/views/admin/form-article.client.view.html', '');
$templateCache.put('/modules/articles/client/views/admin/form-article.client.view.html', '');
// Create mock article
mockArticle = new ArticlesService();
@@ -99,7 +99,7 @@
});
it('Should have templateUrl', function () {
expect(createstate.templateUrl).toBe('modules/articles/client/views/admin/form-article.client.view.html');
expect(createstate.templateUrl).toBe('/modules/articles/client/views/admin/form-article.client.view.html');
});
});
@@ -110,7 +110,7 @@
beforeEach(inject(function ($controller, $state, $templateCache) {
editstate = $state.get('admin.articles.edit');
$templateCache.put('modules/articles/client/views/admin/form-article.client.view.html', '');
$templateCache.put('/modules/articles/client/views/admin/form-article.client.view.html', '');
// Create mock article
mockArticle = new ArticlesService({
@@ -150,7 +150,7 @@
});
it('Should have templateUrl', function () {
expect(editstate.templateUrl).toBe('modules/articles/client/views/admin/form-article.client.view.html');
expect(editstate.templateUrl).toBe('/modules/articles/client/views/admin/form-article.client.view.html');
});
xit('Should go to unauthorized route', function () {

View File

@@ -46,6 +46,10 @@
Authentication = _Authentication_;
ArticlesService = _ArticlesService_;
// Ignore parent template get on state transitions
$httpBackend.whenGET('/modules/articles/client/views/list-articles.client.view.html').respond(200, '');
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
// create mock article
mockArticle = new ArticlesService({
_id: '525a8422f6d0f87f0e407a33',
@@ -76,7 +80,7 @@
it('should send a GET request and return all articles', inject(function (ArticlesService) {
// Set POST response
$httpBackend.expectGET('api/articles').respond(mockArticleList);
$httpBackend.expectGET('/api/articles').respond(mockArticleList);
$httpBackend.flush();

View File

@@ -53,7 +53,7 @@
});
it('Should have templateUrl', function () {
expect(liststate.templateUrl).toBe('modules/articles/client/views/list-articles.client.view.html');
expect(liststate.templateUrl).toBe('/modules/articles/client/views/list-articles.client.view.html');
});
});
@@ -64,7 +64,7 @@
beforeEach(inject(function ($controller, $state, $templateCache) {
viewstate = $state.get('articles.view');
$templateCache.put('modules/articles/client/views/view-article.client.view.html', '');
$templateCache.put('/modules/articles/client/views/view-article.client.view.html', '');
// create mock article
mockArticle = new ArticlesService({
@@ -104,12 +104,14 @@
});
it('Should have templateUrl', function () {
expect(viewstate.templateUrl).toBe('modules/articles/client/views/view-article.client.view.html');
expect(viewstate.templateUrl).toBe('/modules/articles/client/views/view-article.client.view.html');
});
});
describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope) {
beforeEach(inject(function ($state, $rootScope, $templateCache) {
$templateCache.put('/modules/articles/client/views/list-articles.client.view.html', '');
$state.go('articles.list');
$rootScope.$digest();
}));
@@ -119,7 +121,7 @@
$rootScope.$digest();
expect($location.path()).toBe('/articles');
expect($state.current.templateUrl).toBe('modules/articles/client/views/list-articles.client.view.html');
expect($state.current.templateUrl).toBe('/modules/articles/client/views/list-articles.client.view.html');
}));
});
});

View File

@@ -76,8 +76,10 @@
it('should send a GET request and return all articles', inject(function (ArticlesService) {
// Set POST response
$httpBackend.expectGET('api/articles').respond(mockArticleList);
$httpBackend.expectGET('/api/articles').respond(mockArticleList);
// Ignore parent template get on state transition
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
$httpBackend.flush();

View File

@@ -170,7 +170,7 @@ describe('Article Admin CRUD tests', function () {
// Save a new article
agent.post('/api/articles')
.send(article)
.expect(400)
.expect(422)
.end(function (articleSaveErr, articleSaveRes) {
// Set message assertion
(articleSaveRes.body.message).should.match('Title cannot be blank');

View File

@@ -11,7 +11,7 @@
$stateProvider
.state('chat', {
url: '/chat',
templateUrl: 'modules/chat/client/views/chat.client.view.html',
templateUrl: '/modules/chat/client/views/chat.client.view.html',
controller: 'ChatController',
controllerAs: 'vm',
data: {

View File

@@ -18,7 +18,7 @@
<!-- List all messages -->
<li class="col-xs-12 col-md-offset-4 col-md-4 chat-message" ng-repeat="message in vm.messages">
<small class="pull-right text-muted" ng-bind="message.created | date:'mediumTime'"></small>
<img ng-src="{{message.profileImageURL}}" alt="{{message.username}}" class="pull-left chat-profile-image" />
<img ng-src="/{{message.profileImageURL}}" alt="{{message.username}}" class="pull-left chat-profile-image" />
<div class="pull-left chat-message-details">
<strong ng-bind="message.username"></strong>
<br>

View File

@@ -11,7 +11,8 @@
ChatController,
$timeout,
$state,
Authentication;
Authentication,
$httpBackend;
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
@@ -39,12 +40,17 @@
});
describe('when user logged in', function () {
beforeEach(inject(function ($controller, $rootScope, _Socket_, _Authentication_, _$timeout_, _$state_) {
beforeEach(inject(function ($controller, $rootScope, _$httpBackend_, _Socket_, _Authentication_, _$timeout_, _$state_) {
Authentication.user = {
name: 'user',
roles: ['user']
};
$httpBackend = _$httpBackend_;
// Ignore parent template get on state transitions
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
ChatController = $controller('ChatController as vm', {
$scope: $scope
});

View File

@@ -4,7 +4,8 @@
describe('Chat Route Tests', function () {
// Initialize global variables
var $scope,
Authentication;
Authentication,
$httpBackend;
// We can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
@@ -34,27 +35,35 @@
});
it('Should have templateUrl', function () {
expect(mainstate.templateUrl).toBe('modules/chat/client/views/chat.client.view.html');
expect(mainstate.templateUrl).toBe('/modules/chat/client/views/chat.client.view.html');
});
});
describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope, _Authentication_) {
beforeEach(inject(function ($state, $rootScope, _$httpBackend_, _Authentication_) {
Authentication.user = {
name: 'user',
roles: ['user']
};
$httpBackend = _$httpBackend_;
// Ignore parent template get on state transition
$httpBackend.whenGET('/modules/chat/client/views/chat.client.view.html').respond(200);
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
$state.go('chat');
$rootScope.$digest();
}));
it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
it('Should remove trailing slash', inject(function ($state, $location, $rootScope, $templateCache) {
$templateCache.put('/modules/chat/client/views/chat.client.view.html', '');
$location.path('chat/');
$rootScope.$digest();
expect($location.path()).toBe('/chat');
expect($state.current.templateUrl).toBe('modules/chat/client/views/chat.client.view.html');
expect($state.current.templateUrl).toBe('/modules/chat/client/views/chat.client.view.html');
}));
});

View File

@@ -6,7 +6,7 @@
var service = {
applicationEnvironment: window.env,
applicationModuleName: applicationModuleName,
applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'ngFileUpload', 'ngImgCrop'],
applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'ngFileUpload', 'ngImgCrop', 'ui-notification'],
registerModule: registerModule
};
@@ -20,4 +20,17 @@
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
}
// Angular-ui-notification configuration
angular.module('ui-notification').config(function(NotificationProvider) {
NotificationProvider.setOptions({
delay: 2000,
startTop: 20,
startRight: 10,
verticalSpacing: 20,
horizontalSpacing: 20,
positionX: 'right',
positionY: 'bottom'
});
});
}(window));

View File

@@ -10,17 +10,22 @@
.module(app.applicationModuleName)
.config(bootstrapConfig);
function bootstrapConfig($compileProvider, $locationProvider, $httpProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
bootstrapConfig.$inject = ['$compileProvider', '$locationProvider', '$httpProvider', '$logProvider'];
function bootstrapConfig($compileProvider, $locationProvider, $httpProvider, $logProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
}).hashPrefix('!');
$httpProvider.interceptors.push('authInterceptor');
// Disable debug data for production environment
// @link https://docs.angularjs.org/guide/production
$compileProvider.debugInfoEnabled(app.applicationEnvironment !== 'production');
$logProvider.debugEnabled(app.applicationEnvironment !== 'production');
}
bootstrapConfig.$inject = ['$compileProvider', '$locationProvider', '$httpProvider'];
// Then define the init function for starting up the application
angular.element(document).ready(init);

View File

@@ -29,29 +29,43 @@
$stateProvider
.state('home', {
url: '/',
templateUrl: 'modules/core/client/views/home.client.view.html',
templateUrl: '/modules/core/client/views/home.client.view.html',
controller: 'HomeController',
controllerAs: 'vm'
})
.state('not-found', {
url: '/not-found',
templateUrl: 'modules/core/client/views/404.client.view.html',
templateUrl: '/modules/core/client/views/404.client.view.html',
controller: 'ErrorController',
controllerAs: 'vm',
params: {
message: function($stateParams) {
return $stateParams.message;
}
},
data: {
ignoreState: true,
pageTitle: 'Not-Found'
pageTitle: 'Not Found'
}
})
.state('bad-request', {
url: '/bad-request',
templateUrl: 'modules/core/client/views/400.client.view.html',
templateUrl: '/modules/core/client/views/400.client.view.html',
controller: 'ErrorController',
controllerAs: 'vm',
params: {
message: function($stateParams) {
return $stateParams.message;
}
},
data: {
ignoreState: true,
pageTitle: 'Bad-Request'
pageTitle: 'Bad Request'
}
})
.state('forbidden', {
url: '/forbidden',
templateUrl: 'modules/core/client/views/403.client.view.html',
templateUrl: '/modules/core/client/views/403.client.view.html',
data: {
ignoreState: true,
pageTitle: 'Forbidden'

View File

@@ -0,0 +1,18 @@
(function () {
'use strict';
angular
.module('core')
.controller('ErrorController', ErrorController);
ErrorController.$inject = ['$stateParams'];
function ErrorController($stateParams) {
var vm = this;
vm.errorMessage = null;
// Display custom message if it was set
if ($stateParams.message) vm.errorMessage = $stateParams.message;
}
}());

View File

@@ -17,6 +17,9 @@
function responseError(rejection) {
if (!rejection.config.ignoreAuthModule) {
switch (rejection.status) {
case 400:
$injector.get('$state').go('bad-request', { message: rejection.data.message });
break;
case 401:
// Deauthenticate the global user
Authentication.user = null;
@@ -25,6 +28,13 @@
case 403:
$injector.get('$state').transitionTo('forbidden');
break;
case 404:
$injector.get('$state').go('not-found', { message: rejection.data.message });
break;
case -1: // Handle error if no response from server(Network Lost or Server not responding)
var Notification = $injector.get('Notification');
Notification.error({ message: 'No response received from server. Please try again later.', title: 'Error processing request!', delay: 5000 });
break;
}
}
// otherwise, default behaviour

View File

@@ -1,6 +1,9 @@
<h1>Bad Request</h1>
<div class="page-header">
<h1>Bad Request</h1>
</div>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
You made a bad request
<span ng-if="vm.errorMessage" ng-bind="vm.errorMessage"></span>
<span ng-if="!vm.errorMessage">You made a bad request</span>
</div>

View File

@@ -1,4 +1,6 @@
<h1>Forbidden</h1>
<div class="page-header">
<h1>Forbidden</h1>
</div>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>

View File

@@ -1,5 +1,8 @@
<h1>Page Not Found</h1>
<div class="page-header">
<h1>Page Not Found</h1>
</div>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span> Page Not Found
<span ng-if="vm.errorMessage" ng-bind="vm.errorMessage"></span>
<span ng-if="!vm.errorMessage">Page Not Found</span>
</div>

View File

@@ -32,7 +32,7 @@
<ul class="nav navbar-nav navbar-right" ng-show="vm.authentication.user">
<li class="dropdown" uib-dropdown>
<a class="dropdown-toggle user-header-dropdown-toggle" uib-dropdown-toggle role="button">
<img ng-src="{{vm.authentication.user.profileImageURL}}" alt="{{vm.authentication.user.displayName}}" class="header-profile-image" />
<img ng-src="/{{vm.authentication.user.profileImageURL}}" alt="{{vm.authentication.user.displayName}}" class="header-profile-image" />
<span ng-bind="vm.authentication.user.displayName"></span> <b class="caret"></b>
</a>
<ul class="dropdown-menu" role="menu">

View File

@@ -2,7 +2,7 @@
<div class="jumbotron text-center">
<div class="row">
<div class="col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3 col-xs-12">
<img alt="MEAN.JS" class="img-responsive text-center" src="modules/core/client/img/brand/logo.png" />
<img alt="MEAN.JS" class="img-responsive text-center" src="/modules/core/client/img/brand/logo.png" />
</div>
</div>
<br>

View File

@@ -4,7 +4,6 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<base href="/">
<title page-title></title>
<meta name="description" content="{{description}}">
<meta name="fragment" content="!">
@@ -29,10 +28,10 @@
<meta name="twitter:image" content="{{logo}}">
<!-- Fav Icon -->
<link href="{{favicon}}" rel="shortcut icon" type="image/x-icon">
<link href="/{{favicon}}" rel="shortcut icon" type="image/x-icon">
<!-- Application CSS Files -->
{{#each cssFiles}}<link rel="stylesheet" href="{{this}}">{{/each}}
{{#each cssFiles}}<link rel="stylesheet" href="/{{this}}">{{/each}}
</head>
<body class="ng-cloak">
@@ -64,7 +63,7 @@
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<!--Application JavaScript Files-->
{{#each jsFiles}}<script type="text/javascript" src="{{this}}"></script>{{/each}}
{{#each jsFiles}}<script type="text/javascript" src="/{{this}}"></script>{{/each}}
<!--owasp config sync-->
<script type="text/javascript">

View File

@@ -62,5 +62,22 @@
expect($state.transitionTo).toHaveBeenCalledWith('authentication.signin');
});
});
describe('Unresponsive Interceptor', function() {
var Notification;
beforeEach(inject(function(_Notification_) {
Notification = _Notification_;
spyOn(Notification, 'error');
}));
it('should show error Notification', function () {
var response = {
status: -1,
config: {}
};
var promise = authInterceptor.responseError(response);
expect($q.reject).toHaveBeenCalled();
expect(Notification.error).toHaveBeenCalledWith({ message: 'No response received from server. Please try again later.', title: 'Error processing request!', delay: 5000 });
});
});
});
}());

View File

@@ -12,7 +12,7 @@
$stateProvider
.state('admin.users', {
url: '/users',
templateUrl: 'modules/users/client/views/admin/list-users.client.view.html',
templateUrl: '/modules/users/client/views/admin/list-users.client.view.html',
controller: 'UserListController',
controllerAs: 'vm',
data: {
@@ -21,7 +21,7 @@
})
.state('admin.user', {
url: '/users/:userId',
templateUrl: 'modules/users/client/views/admin/view-user.client.view.html',
templateUrl: '/modules/users/client/views/admin/view-user.client.view.html',
controller: 'UserController',
controllerAs: 'vm',
resolve: {
@@ -33,7 +33,7 @@
})
.state('admin.user-edit', {
url: '/users/:userId/edit',
templateUrl: 'modules/users/client/views/admin/edit-user.client.view.html',
templateUrl: '/modules/users/client/views/admin/edit-user.client.view.html',
controller: 'UserController',
controllerAs: 'vm',
resolve: {

View File

@@ -14,7 +14,7 @@
.state('settings', {
abstract: true,
url: '/settings',
templateUrl: 'modules/users/client/views/settings/settings.client.view.html',
templateUrl: '/modules/users/client/views/settings/settings.client.view.html',
controller: 'SettingsController',
controllerAs: 'vm',
data: {
@@ -23,7 +23,7 @@
})
.state('settings.profile', {
url: '/profile',
templateUrl: 'modules/users/client/views/settings/edit-profile.client.view.html',
templateUrl: '/modules/users/client/views/settings/edit-profile.client.view.html',
controller: 'EditProfileController',
controllerAs: 'vm',
data: {
@@ -32,7 +32,7 @@
})
.state('settings.password', {
url: '/password',
templateUrl: 'modules/users/client/views/settings/change-password.client.view.html',
templateUrl: '/modules/users/client/views/settings/change-password.client.view.html',
controller: 'ChangePasswordController',
controllerAs: 'vm',
data: {
@@ -41,7 +41,7 @@
})
.state('settings.accounts', {
url: '/accounts',
templateUrl: 'modules/users/client/views/settings/manage-social-accounts.client.view.html',
templateUrl: '/modules/users/client/views/settings/manage-social-accounts.client.view.html',
controller: 'SocialAccountsController',
controllerAs: 'vm',
data: {
@@ -50,7 +50,7 @@
})
.state('settings.picture', {
url: '/picture',
templateUrl: 'modules/users/client/views/settings/change-profile-picture.client.view.html',
templateUrl: '/modules/users/client/views/settings/change-profile-picture.client.view.html',
controller: 'ChangeProfilePictureController',
controllerAs: 'vm',
data: {
@@ -60,13 +60,13 @@
.state('authentication', {
abstract: true,
url: '/authentication',
templateUrl: 'modules/users/client/views/authentication/authentication.client.view.html',
templateUrl: '/modules/users/client/views/authentication/authentication.client.view.html',
controller: 'AuthenticationController',
controllerAs: 'vm'
})
.state('authentication.signup', {
url: '/signup',
templateUrl: 'modules/users/client/views/authentication/signup.client.view.html',
templateUrl: '/modules/users/client/views/authentication/signup.client.view.html',
controller: 'AuthenticationController',
controllerAs: 'vm',
data: {
@@ -75,7 +75,7 @@
})
.state('authentication.signin', {
url: '/signin?err',
templateUrl: 'modules/users/client/views/authentication/signin.client.view.html',
templateUrl: '/modules/users/client/views/authentication/signin.client.view.html',
controller: 'AuthenticationController',
controllerAs: 'vm',
data: {
@@ -89,7 +89,7 @@
})
.state('password.forgot', {
url: '/forgot',
templateUrl: 'modules/users/client/views/password/forgot-password.client.view.html',
templateUrl: '/modules/users/client/views/password/forgot-password.client.view.html',
controller: 'PasswordController',
controllerAs: 'vm',
data: {
@@ -103,21 +103,21 @@
})
.state('password.reset.invalid', {
url: '/invalid',
templateUrl: 'modules/users/client/views/password/reset-password-invalid.client.view.html',
templateUrl: '/modules/users/client/views/password/reset-password-invalid.client.view.html',
data: {
pageTitle: 'Password reset invalid'
}
})
.state('password.reset.success', {
url: '/success',
templateUrl: 'modules/users/client/views/password/reset-password-success.client.view.html',
templateUrl: '/modules/users/client/views/password/reset-password-success.client.view.html',
data: {
pageTitle: 'Password reset success'
}
})
.state('password.reset.form', {
url: '/:token',
templateUrl: 'modules/users/client/views/password/reset-password.client.view.html',
templateUrl: '/modules/users/client/views/password/reset-password.client.view.html',
controller: 'PasswordController',
controllerAs: 'vm',
data: {

View File

@@ -5,9 +5,9 @@
.module('users.admin')
.controller('UserController', UserController);
UserController.$inject = ['$scope', '$state', '$window', 'Authentication', 'userResolve'];
UserController.$inject = ['$scope', '$state', '$window', 'Authentication', 'userResolve', 'Notification'];
function UserController($scope, $state, $window, Authentication, user) {
function UserController($scope, $state, $window, Authentication, user, Notification) {
var vm = this;
vm.authentication = Authentication;
@@ -22,9 +22,11 @@
user.$remove();
vm.users.splice(vm.users.indexOf(user), 1);
Notification.success('User deleted successfully!');
} else {
vm.user.$remove(function () {
$state.go('admin.users');
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> User deleted successfully!' });
});
}
}
@@ -43,8 +45,9 @@
$state.go('admin.user', {
userId: user._id
});
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> User saved successfully!' });
}, function (errorResponse) {
vm.error = errorResponse.data.message;
Notification.error({ message: errorResponse.data.message, title: '<i class="glyphicon glyphicon-remove"></i> User update error!' });
});
}

View File

@@ -5,9 +5,9 @@
.module('users')
.controller('AuthenticationController', AuthenticationController);
AuthenticationController.$inject = ['$scope', '$state', 'UsersService', '$location', '$window', 'Authentication', 'PasswordValidator'];
AuthenticationController.$inject = ['$scope', '$state', 'UsersService', '$location', '$window', 'Authentication', 'PasswordValidator', 'Notification'];
function AuthenticationController($scope, $state, UsersService, $location, $window, Authentication, PasswordValidator) {
function AuthenticationController($scope, $state, UsersService, $location, $window, Authentication, PasswordValidator, Notification) {
var vm = this;
vm.authentication = Authentication;
@@ -17,7 +17,9 @@
vm.callOauthProvider = callOauthProvider;
// Get an eventual error defined in the URL query string:
vm.error = $location.search().err;
if ($location.search().err) {
Notification.error({ message: $location.search().err });
}
// If user is signed in then redirect back home
if (vm.authentication.user) {
@@ -25,7 +27,6 @@
}
function signup(isValid) {
vm.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.userForm');
@@ -39,7 +40,6 @@
}
function signin(isValid) {
vm.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.userForm');
@@ -67,25 +67,25 @@
function onUserSignupSuccess(response) {
// If successful we assign the response to the global user model
vm.authentication.user = response;
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Signup successful!' });
// And redirect to the previous or home page
$state.go($state.previous.state.name || 'home', $state.previous.params);
}
function onUserSignupError(response) {
vm.error = response.data.message;
Notification.error({ message: response.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Signup Error!', delay: 6000 });
}
function onUserSigninSuccess(response) {
// If successful we assign the response to the global user model
vm.authentication.user = response;
Notification.info({ message: 'Welcome ' + response.firstName });
// And redirect to the previous or home page
$state.go($state.previous.state.name || 'home', $state.previous.params);
}
function onUserSigninError(response) {
vm.error = response.data.message;
Notification.error({ message: response.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Signin Error!', delay: 6000 });
}
}
}());

View File

@@ -5,9 +5,9 @@
.module('users')
.controller('PasswordController', PasswordController);
PasswordController.$inject = ['$scope', '$stateParams', 'UsersService', '$location', 'Authentication', 'PasswordValidator'];
PasswordController.$inject = ['$scope', '$stateParams', 'UsersService', '$location', 'Authentication', 'PasswordValidator', 'Notification'];
function PasswordController($scope, $stateParams, UsersService, $location, Authentication, PasswordValidator) {
function PasswordController($scope, $stateParams, UsersService, $location, Authentication, PasswordValidator, Notification) {
var vm = this;
vm.resetUserPassword = resetUserPassword;
@@ -22,7 +22,6 @@
// Submit forgotten password account id
function askForPasswordReset(isValid) {
vm.success = vm.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.forgotPasswordForm');
@@ -37,7 +36,6 @@
// Change user password
function resetUserPassword(isValid) {
vm.success = vm.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.resetPasswordForm');
@@ -55,13 +53,13 @@
function onRequestPasswordResetSuccess(response) {
// Show user success message and clear form
vm.credentials = null;
vm.success = response.message;
Notification.success({ message: response.message, title: '<i class="glyphicon glyphicon-ok"></i> Password reset email sent successfully!' });
}
function onRequestPasswordResetError(response) {
// Show user error message and clear form
vm.credentials = null;
vm.error = response.data.message;
Notification.error({ message: response.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Failed to send password reset email!', delay: 4000 });
}
function onResetPasswordSuccess(response) {
@@ -70,12 +68,13 @@
// Attach user profile
Authentication.user = response;
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Password reset successful!' });
// And redirect to the index page
$location.path('/password/reset/success');
}
function onResetPasswordError(response) {
vm.error = response.data.message;
Notification.error({ message: response.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Password reset failed!', delay: 4000 });
}
}
}());

View File

@@ -5,9 +5,9 @@
.module('users')
.controller('ChangePasswordController', ChangePasswordController);
ChangePasswordController.$inject = ['$scope', '$http', 'Authentication', 'UsersService', 'PasswordValidator'];
ChangePasswordController.$inject = ['$scope', '$http', 'Authentication', 'UsersService', 'PasswordValidator', 'Notification'];
function ChangePasswordController($scope, $http, Authentication, UsersService, PasswordValidator) {
function ChangePasswordController($scope, $http, Authentication, UsersService, PasswordValidator, Notification) {
var vm = this;
vm.user = Authentication.user;
@@ -16,7 +16,6 @@
// Change user password
function changeUserPassword(isValid) {
vm.success = vm.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.passwordForm');
@@ -31,13 +30,12 @@
function onChangePasswordSuccess(response) {
// If successful show success message and clear form
$scope.$broadcast('show-errors-reset', 'vm.passwordForm');
vm.success = true;
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Password Changed Successfully' });
vm.passwordDetails = null;
}
function onChangePasswordError(response) {
vm.error = response.data.message;
Notification.error({ message: response.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Password change failed!' });
}
}
}());

View File

@@ -5,19 +5,18 @@
.module('users')
.controller('ChangeProfilePictureController', ChangeProfilePictureController);
ChangeProfilePictureController.$inject = ['$timeout', 'Authentication', 'Upload'];
ChangeProfilePictureController.$inject = ['$timeout', 'Authentication', 'Upload', 'Notification'];
function ChangeProfilePictureController($timeout, Authentication, Upload) {
function ChangeProfilePictureController($timeout, Authentication, Upload, Notification) {
var vm = this;
vm.user = Authentication.user;
vm.fileSelected = false;
vm.upload = function (dataUrl, name) {
vm.success = vm.error = null;
Upload.upload({
url: 'api/users/picture',
url: '/api/users/picture',
data: {
newProfilePicture: Upload.dataUrltoBlob(dataUrl, name)
}
@@ -35,7 +34,7 @@
// Called after the user has successfully uploaded a new picture
function onSuccessItem(response) {
// Show success message
vm.success = true;
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Change profile picture successful!' });
// Populate user object
vm.user = Authentication.user = response;
@@ -50,7 +49,7 @@
vm.fileSelected = false;
// Show error message
vm.error = response.message;
Notification.error({ message: response.message, title: '<i class="glyphicon glyphicon-remove"></i> Change profile picture failed!' });
}
}
}());

View File

@@ -5,9 +5,9 @@
.module('users')
.controller('EditProfileController', EditProfileController);
EditProfileController.$inject = ['$scope', '$http', '$location', 'UsersService', 'Authentication'];
EditProfileController.$inject = ['$scope', '$http', '$location', 'UsersService', 'Authentication', 'Notification'];
function EditProfileController($scope, $http, $location, UsersService, Authentication) {
function EditProfileController($scope, $http, $location, UsersService, Authentication, Notification) {
var vm = this;
vm.user = Authentication.user;
@@ -15,7 +15,6 @@
// Update a user profile
function updateUserProfile(isValid) {
vm.success = vm.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.userForm');
@@ -28,10 +27,10 @@
user.$update(function (response) {
$scope.$broadcast('show-errors-reset', 'vm.userForm');
vm.success = true;
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Edit profile successful!' });
Authentication.user = response;
}, function (response) {
vm.error = response.data.message;
Notification.error({ message: response.data.message, title: '<i class="glyphicon glyphicon-remove"></i> Edit profile failed!' });
});
}
}

View File

@@ -5,9 +5,9 @@
.module('users')
.controller('SocialAccountsController', SocialAccountsController);
SocialAccountsController.$inject = ['$scope', 'UsersService', 'Authentication'];
SocialAccountsController.$inject = ['$scope', 'UsersService', 'Authentication', 'Notification'];
function SocialAccountsController($scope, UsersService, Authentication) {
function SocialAccountsController($scope, UsersService, Authentication, Notification) {
var vm = this;
vm.user = Authentication.user;
@@ -27,7 +27,6 @@
// Remove a user social account
function removeUserSocialAccount(provider) {
vm.success = vm.error = null;
UsersService.removeSocialAccount(provider)
.then(onRemoveSocialAccountSuccess)
@@ -36,12 +35,12 @@
function onRemoveSocialAccountSuccess(response) {
// If successful show success message and clear form
vm.success = true;
Notification.success({ message: '<i class="glyphicon glyphicon-ok"></i> Removed successfully!' });
vm.user = Authentication.user = response;
}
function onRemoveSocialAccountError(response) {
vm.error = response.message;
Notification.error({ message: response.message, title: '<i class="glyphicon glyphicon-remove"></i> Remove failed!' });
}
}
}());

View File

@@ -9,36 +9,36 @@
UsersService.$inject = ['$resource'];
function UsersService($resource) {
var Users = $resource('api/users', {}, {
var Users = $resource('/api/users', {}, {
update: {
method: 'PUT'
},
updatePassword: {
method: 'POST',
url: 'api/users/password'
url: '/api/users/password'
},
deleteProvider: {
method: 'DELETE',
url: 'api/users/accounts',
url: '/api/users/accounts',
params: {
provider: '@provider'
}
},
sendPasswordResetToken: {
method: 'POST',
url: 'api/auth/forgot'
url: '/api/auth/forgot'
},
resetPasswordWithToken: {
method: 'POST',
url: 'api/auth/reset/:token'
url: '/api/auth/reset/:token'
},
signup: {
method: 'POST',
url: 'api/auth/signup'
url: '/api/auth/signup'
},
signin: {
method: 'POST',
url: 'api/auth/signin'
url: '/api/auth/signin'
}
});
@@ -78,7 +78,7 @@
AdminService.$inject = ['$resource'];
function AdminService($resource) {
return $resource('api/users/:userId', {
return $resource('/api/users/:userId', {
userId: '@_id'
}, {
update: {

View File

@@ -31,9 +31,6 @@
<div class="form-group">
<input type="submit" value="Update" class="btn btn-default">
</div>
<div ng-show="vm.error" class="text-danger">
<strong ng-bind="vm.error"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -51,9 +51,6 @@
&nbsp; or&nbsp;
<a ui-sref="authentication.signin" class="show-signup">Sign in</a>
</div>
<div ng-show="vm.error" class="text-center text-danger">
<strong ng-bind="vm.error"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -13,12 +13,6 @@
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
<div ng-show="vm.error" class="text-center text-danger">
<strong ng-bind="vm.error"></strong>
</div>
<div ng-show="vm.success" class="text-center text-success">
<strong ng-bind="vm.success"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -28,12 +28,6 @@
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">Update Password</button>
</div>
<div ng-show="error" class="text-center text-danger">
<strong ng-bind="vm.error"></strong>
</div>
<div ng-show="success" class="text-center text-success">
<strong ng-bind="vm.success"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -34,12 +34,6 @@
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">Save Password</button>
</div>
<div ng-show="vm.success" class="text-center text-success">
<strong>Password Changed Successfully</strong>
</div>
<div ng-show="vm.error" class="text-center text-danger">
<strong ng-bind="vm.error"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -9,10 +9,10 @@
</div>
</div>
<div class="form-group text-center">
<img ng-src="{{vm.fileSelected ? croppedDataUrl : vm.user.profileImageURL}}" alt="{{vm.user.displayName}}" class="img-thumbnail user-profile-picture" ngf-drop>
<img ng-src="{{vm.fileSelected ? croppedDataUrl : '/' + vm.user.profileImageURL}}" alt="{{vm.user.displayName}}" class="img-thumbnail user-profile-picture" ngf-drop>
</div>
<div ng-show="!vm.fileSelected" class="text-center form-group">
<button class="btn btn-default btn-file" ngf-select="vm.fileSelected = true; vm.success = null" ng-model="picFile" accept="image/*">Select Picture</button>
<button class="btn btn-default btn-file" ngf-select="vm.fileSelected = true" ng-model="picFile" accept="image/*">Select Picture</button>
</div>
<div ng-show="vm.fileSelected" class="text-center form-group">
<button class="btn btn-primary" ng-click="vm.upload(croppedDataUrl, picFile.name)">Upload</button>
@@ -23,12 +23,6 @@
<span class="sr-only">{{vm.progress}}% Complete</span>
</div>
</div>
<div ng-show="vm.success" class="text-center text-success">
<strong>Profile Picture Changed Successfully</strong>
</div>
<div ng-show="vm.error" class="text-center text-danger">
<strong ng-bind="vm.error"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -34,12 +34,6 @@
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">Save Profile</button>
</div>
<div ng-show="vm.success" class="text-center text-success">
<strong>Profile Saved Successfully</strong>
</div>
<div ng-show="vm.error" class="text-center text-danger">
<strong ng-bind="vm.error"></strong>
</div>
</fieldset>
</form>
</div>

View File

@@ -29,7 +29,7 @@ exports.update = function (req, res) {
user.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
}
@@ -46,7 +46,7 @@ exports.delete = function (req, res) {
user.remove(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
}
@@ -61,7 +61,7 @@ exports.delete = function (req, res) {
exports.list = function (req, res) {
User.find({}, '-salt -password -providerData').sort('-created').populate('user', 'displayName').exec(function (err, users) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
}

View File

@@ -30,7 +30,7 @@ exports.signup = function (req, res) {
// Then save the user
user.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -55,7 +55,7 @@ exports.signup = function (req, res) {
exports.signin = function (req, res, next) {
passport.authenticate('local', function (err, user, info) {
if (err || !user) {
res.status(400).send(info);
res.status(422).send(info);
} else {
// Remove sensitive data before login
user.password = undefined;
@@ -231,7 +231,7 @@ exports.removeOAuthProvider = function (req, res, next) {
user.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {

View File

@@ -50,7 +50,7 @@ exports.forgot = function (req, res, next) {
}
});
} else {
return res.status(400).send({
return res.status(422).send({
message: 'Username field must not be blank'
});
}
@@ -62,13 +62,11 @@ exports.forgot = function (req, res, next) {
httpTransport = 'https://';
}
var baseUrl = req.app.get('domain') || httpTransport + req.headers.host;
console.log(baseUrl);
res.render(path.resolve('modules/users/server/templates/reset-password-email'), {
name: user.displayName,
appName: config.app.title,
url: baseUrl + '/api/auth/reset/' + token
}, function (err, emailHTML) {
console.log(emailHTML);
done(err, emailHTML, user);
});
},
@@ -143,7 +141,7 @@ exports.reset = function (req, res, next) {
user.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -163,7 +161,7 @@ exports.reset = function (req, res, next) {
}
});
} else {
return res.status(400).send({
return res.status(422).send({
message: 'Passwords do not match'
});
}
@@ -219,7 +217,7 @@ exports.changePassword = function (req, res, next) {
user.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -235,12 +233,12 @@ exports.changePassword = function (req, res, next) {
}
});
} else {
res.status(400).send({
res.status(422).send({
message: 'Passwords do not match'
});
}
} else {
res.status(400).send({
res.status(422).send({
message: 'Current password is incorrect'
});
}
@@ -251,12 +249,12 @@ exports.changePassword = function (req, res, next) {
}
});
} else {
res.status(400).send({
res.status(422).send({
message: 'Please provide a new password'
});
}
} else {
res.status(400).send({
res.status(401).send({
message: 'User is not signed in'
});
}

View File

@@ -31,7 +31,7 @@ exports.update = function (req, res) {
user.save(function (err) {
if (err) {
return res.status(400).send({
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -45,7 +45,7 @@ exports.update = function (req, res) {
}
});
} else {
res.status(400).send({
res.status(401).send({
message: 'User is not signed in'
});
}
@@ -73,10 +73,10 @@ exports.changeProfilePicture = function (req, res) {
res.json(user);
})
.catch(function (err) {
res.status(400).send(err);
res.status(422).send(err);
});
} else {
res.status(400).send({
res.status(401).send({
message: 'User is not signed in'
});
}
@@ -129,7 +129,7 @@ exports.changeProfilePicture = function (req, res) {
return new Promise(function (resolve, reject) {
req.login(user, function (err) {
if (err) {
reject(err);
res.status(400).send(err);
} else {
resolve();
}

View File

@@ -9,7 +9,8 @@
$httpBackend,
$stateParams,
$state,
$location;
$location,
Notification;
beforeEach(function () {
jasmine.addMatchers({
@@ -32,7 +33,7 @@
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function ($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
beforeEach(inject(function ($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_, _Notification_) {
// Set a new global scope
scope = $rootScope.$new();
@@ -40,6 +41,15 @@
$stateParams = _$stateParams_;
$httpBackend = _$httpBackend_;
$location = _$location_;
Notification = _Notification_;
// Spy on Notification
spyOn(Notification, 'error');
spyOn(Notification, 'success');
// Ignore parent template get on state transitions
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200);
$httpBackend.whenGET('/modules/core/client/views/400.client.view.html').respond(200);
// Initialize the Authentication controller
AuthenticationController = $controller('AuthenticationController as vm', {
@@ -48,9 +58,11 @@
}));
describe('$scope.signin()', function () {
it('should login with a correct username and password', function () {
it('should login with a correct user and password', inject(function ($templateCache) {
$templateCache.put('/modules/core/client/views/home.client.view.html', '');
// Test expected GET request
$httpBackend.when('POST', 'api/auth/signin').respond(200, { username: 'Fred' });
$httpBackend.when('POST', '/api/auth/signin').respond(200, { username: 'Fred' });
scope.vm.signin(true);
$httpBackend.flush();
@@ -58,11 +70,12 @@
// Test scope value
expect(scope.vm.authentication.user.username).toEqual('Fred');
expect($location.url()).toEqual('/');
});
}));
it('should login with a correct email and password', function () {
it('should login with a correct email and password', inject(function ($templateCache) {
$templateCache.put('/modules/core/client/views/home.client.view.html', '');
// Test expected GET request
$httpBackend.when('POST', 'api/auth/signin').respond(200, { email: 'Fred@email.com' });
$httpBackend.when('POST', '/api/auth/signin').respond(200, { email: 'Fred@email.com' });
scope.vm.signin(true);
$httpBackend.flush();
@@ -70,7 +83,7 @@
// Test scope value
expect(scope.vm.authentication.user.email).toEqual('Fred@email.com');
expect($location.url()).toEqual('/');
});
}));
it('should be redirected to previous state after successful login',
inject(function (_$state_) {
@@ -87,7 +100,7 @@
spyOn($state, 'go');
// Test expected GET request
$httpBackend.when('POST', 'api/auth/signin').respond(200, 'Fred');
$httpBackend.when('POST', '/api/auth/signin').respond(200, 'Fred');
scope.vm.signin(true);
$httpBackend.flush();
@@ -100,15 +113,15 @@
it('should fail to log in with nothing', function () {
// Test expected POST request
$httpBackend.expectPOST('api/auth/signin').respond(400, {
$httpBackend.expectPOST('/api/auth/signin').respond(400, {
'message': 'Missing credentials'
});
scope.vm.signin(true);
$httpBackend.flush();
// Test scope value
expect(scope.vm.error).toEqual('Missing credentials');
// Test Notification.error is called
expect(Notification.error).toHaveBeenCalledWith({ message: 'Missing credentials', title: '<i class="glyphicon glyphicon-remove"></i> Signin Error!', delay: 6000 });
});
it('should fail to log in with wrong credentials', function () {
@@ -117,44 +130,46 @@
scope.vm.credentials = 'Bar';
// Test expected POST request
$httpBackend.expectPOST('api/auth/signin').respond(400, {
$httpBackend.expectPOST('/api/auth/signin').respond(400, {
'message': 'Unknown user'
});
scope.vm.signin(true);
$httpBackend.flush();
// Test scope value
expect(scope.vm.error).toEqual('Unknown user');
// Test Notification.error is called
expect(Notification.error).toHaveBeenCalledWith({ message: 'Unknown user', title: '<i class="glyphicon glyphicon-remove"></i> Signin Error!', delay: 6000 });
});
});
describe('$scope.signup()', function () {
it('should register with correct data', function () {
it('should register with correct data', inject(function ($templateCache) {
$templateCache.put('/modules/core/client/views/home.client.view.html', '');
// Test expected GET request
scope.vm.authentication.user = 'Fred';
$httpBackend.when('POST', 'api/auth/signup').respond(200, { username: 'Fred' });
$httpBackend.when('POST', '/api/auth/signup').respond(200, { username: 'Fred' });
scope.vm.signup(true);
$httpBackend.flush();
// test scope value
expect(scope.vm.authentication.user.username).toBe('Fred');
expect(scope.vm.error).toEqual(null);
expect(Notification.success).toHaveBeenCalledWith({ message: '<i class="glyphicon glyphicon-ok"></i> Signup successful!' });
expect($location.url()).toBe('/');
});
}));
it('should fail to register with duplicate Username', function () {
// Test expected POST request
$httpBackend.when('POST', 'api/auth/signup').respond(400, {
$httpBackend.when('POST', '/api/auth/signup').respond(400, {
'message': 'Username already exists'
});
scope.vm.signup(true);
$httpBackend.flush();
// Test scope value
expect(scope.vm.error).toBe('Username already exists');
// Test Notification.error is called
expect(Notification.error).toHaveBeenCalledWith({ message: 'Username already exists', title: '<i class="glyphicon glyphicon-remove"></i> Signup Error!', delay: 6000 });
});
});
});

View File

@@ -8,7 +8,8 @@
$httpBackend,
$location,
Authentication,
UsersService;
UsersService,
Notification;
// The $resource service augments the response object with methods for updating and deleting the resource.
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
@@ -35,7 +36,7 @@
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function ($controller, $rootScope, _$location_, _$httpBackend_, _Authentication_, _UsersService_) {
beforeEach(inject(function ($controller, $rootScope, _$location_, _$httpBackend_, _Authentication_, _UsersService_, _Notification_) {
// Set a new global scope
$scope = $rootScope.$new();
@@ -44,6 +45,15 @@
$location = _$location_;
Authentication = _Authentication_;
UsersService = _UsersService_;
Notification = _Notification_;
// Spy on Notification
spyOn(Notification, 'error');
spyOn(Notification, 'success');
// Ignore parent template gets on state transition
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200);
$httpBackend.whenGET('/modules/core/client/views/400.client.view.html').respond(200);
// Mock logged in user
Authentication.user = {
@@ -72,10 +82,10 @@
$scope.vm.updateUserProfile(true);
$httpBackend.flush();
expect($scope.vm.success).toBe(true);
expect(Notification.success).toHaveBeenCalledWith({ message: '<i class="glyphicon glyphicon-ok"></i> Edit profile successful!' });
}));
it('should set vm.error if error', inject(function (UsersService) {
it('should call Notification.error if error', inject(function (UsersService) {
var errorMessage = 'error';
$httpBackend.expectPUT(/api\/users/).respond(400, {
message: errorMessage
@@ -84,7 +94,7 @@
$scope.vm.updateUserProfile(true);
$httpBackend.flush();
expect($scope.vm.error).toBe(errorMessage);
expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: '<i class="glyphicon glyphicon-remove"></i> Edit profile failed!' });
}));
});

View File

@@ -9,7 +9,8 @@
$httpBackend,
$stateParams,
$location,
$window;
$window,
Notification;
beforeEach(function() {
jasmine.addMatchers({
@@ -39,6 +40,9 @@
$location = _$location_;
$location.path = jasmine.createSpy().and.returnValue(true);
// Ignore parent template gets on state transition
$httpBackend.whenGET('/modules/core/client/views/404.client.view.html').respond(200);
// Mock logged in user
_Authentication_.user = {
username: 'test',
@@ -57,7 +61,7 @@
});
describe('Logged out user', function() {
beforeEach(inject(function($controller, $rootScope, _$window_, _$stateParams_, _$httpBackend_, _$location_) {
beforeEach(inject(function($controller, $rootScope, _$window_, _$stateParams_, _$httpBackend_, _$location_, _Notification_) {
// Set a new global scope
scope = $rootScope.$new();
@@ -68,6 +72,14 @@
$location.path = jasmine.createSpy().and.returnValue(true);
$window = _$window_;
$window.user = null;
Notification = _Notification_;
spyOn(Notification, 'error');
spyOn(Notification, 'success');
// Ignore parent template gets on state transition
$httpBackend.whenGET('/modules/core/client/views/404.client.view.html').respond(200);
$httpBackend.whenGET('/modules/core/client/views/400.client.view.html').respond(200);
// Initialize the Authentication controller
PasswordController = $controller('PasswordController as vm', {
@@ -88,19 +100,10 @@
scope.vm.credentials = credentials;
});
it('should clear scope.success and scope.error', function() {
scope.vm.success = 'test';
scope.vm.error = 'test';
scope.vm.askForPasswordReset(true);
expect(scope.vm.success).toBeNull();
expect(scope.vm.error).toBeNull();
});
describe('POST error', function() {
var errorMessage = 'No account with that username has been found';
beforeEach(function() {
$httpBackend.when('POST', 'api/auth/forgot', credentials).respond(400, {
$httpBackend.when('POST', '/api/auth/forgot', credentials).respond(400, {
'message': errorMessage
});
@@ -112,15 +115,15 @@
expect(scope.vm.credentials).toBe(null);
});
it('should set error to response message', function() {
expect(scope.vm.error).toBe(errorMessage);
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() {
var successMessage = 'An email has been sent to the provided email with further instructions.';
beforeEach(function() {
$httpBackend.when('POST', 'api/auth/forgot', credentials).respond({
$httpBackend.when('POST', '/api/auth/forgot', credentials).respond({
'message': successMessage
});
@@ -132,8 +135,8 @@
expect(scope.vm.credentials).toBe(null);
});
it('should set success to response message', function() {
expect(scope.vm.success).toBe(successMessage);
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!' });
});
});
});
@@ -148,25 +151,16 @@
scope.vm.passwordDetails = passwordDetails;
});
it('should clear scope.success and scope.vm.error', function() {
scope.vm.success = 'test';
scope.vm.error = 'test';
scope.vm.resetUserPassword(true);
expect(scope.vm.success).toBeNull();
expect(scope.vm.error).toBeNull();
});
it('POST error should set scope.error to 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, {
$httpBackend.when('POST', '/api/auth/reset/' + token, passwordDetails).respond(400, {
'message': errorMessage
});
scope.vm.resetUserPassword(true);
$httpBackend.flush();
expect(scope.vm.error).toBe(errorMessage);
expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: '<i class="glyphicon glyphicon-remove"></i> Password reset failed!', delay: 4000 });
});
describe('POST success', function() {
@@ -174,7 +168,7 @@
username: 'test'
};
beforeEach(function() {
$httpBackend.when('POST', 'api/auth/reset/' + token, passwordDetails).respond(user);
$httpBackend.when('POST', '/api/auth/reset/' + token, passwordDetails).respond(user);
scope.vm.resetUserPassword(true);
$httpBackend.flush();
@@ -188,7 +182,8 @@
expect(scope.vm.authentication.user.username).toEqual(user.username);
});
it('should redirect to password reset success view', 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');
});
});

View File

@@ -4,7 +4,8 @@
describe('Users Admin Route Tests', function () {
// Initialize global variables
var $scope,
Authentication;
Authentication,
$httpBackend;
// We can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
@@ -34,7 +35,7 @@
});
it('Should have templateUrl', function () {
expect(mainstate.templateUrl).toBe('modules/users/client/views/admin/list-users.client.view.html');
expect(mainstate.templateUrl).toBe('/modules/users/client/views/admin/list-users.client.view.html');
});
});
@@ -53,7 +54,7 @@
});
it('Should have templateUrl', function () {
expect(viewstate.templateUrl).toBe('modules/users/client/views/admin/view-user.client.view.html');
expect(viewstate.templateUrl).toBe('/modules/users/client/views/admin/view-user.client.view.html');
});
});
@@ -72,27 +73,36 @@
});
it('Should have templateUrl', function () {
expect(editstate.templateUrl).toBe('modules/users/client/views/admin/edit-user.client.view.html');
expect(editstate.templateUrl).toBe('/modules/users/client/views/admin/edit-user.client.view.html');
});
});
describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope, _Authentication_) {
beforeEach(inject(function ($state, $rootScope, _Authentication_, _$httpBackend_) {
Authentication.user = {
name: 'user',
roles: ['admin']
};
$httpBackend = _$httpBackend_;
// Ignore parent template gets on state transition
$httpBackend.whenGET('/modules/users/client/views/admin/list-users.client.view.html').respond(200);
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200);
$state.go('admin.users');
$rootScope.$digest();
}));
it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
it('Should remove trailing slash', inject(function ($state, $location, $rootScope, $templateCache) {
$templateCache.put('/modules/users/client/views/admin/list-users.client.view.html', '');
$templateCache.put('/modules/core/client/views/home.client.view.html', '');
$location.path('admin/users/');
$rootScope.$digest();
expect($location.path()).toBe('/admin/users');
expect($state.current.templateUrl).toBe('modules/users/client/views/admin/list-users.client.view.html');
expect($state.current.templateUrl).toBe('/modules/users/client/views/admin/list-users.client.view.html');
}));
});

View File

@@ -4,7 +4,8 @@
describe('Users Route Tests', function () {
// Initialize global variables
var $scope,
Authentication;
Authentication,
$httpBackend;
// We can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
@@ -34,7 +35,7 @@
});
it('Should have templateUrl', function () {
expect(mainstate.templateUrl).toBe('modules/users/client/views/settings/settings.client.view.html');
expect(mainstate.templateUrl).toBe('/modules/users/client/views/settings/settings.client.view.html');
});
});
@@ -53,7 +54,7 @@
});
it('Should have templateUrl', function () {
expect(profilestate.templateUrl).toBe('modules/users/client/views/settings/edit-profile.client.view.html');
expect(profilestate.templateUrl).toBe('/modules/users/client/views/settings/edit-profile.client.view.html');
});
});
@@ -72,7 +73,7 @@
});
it('Should have templateUrl', function () {
expect(passwordstate.templateUrl).toBe('modules/users/client/views/settings/change-password.client.view.html');
expect(passwordstate.templateUrl).toBe('/modules/users/client/views/settings/change-password.client.view.html');
});
});
@@ -91,7 +92,7 @@
});
it('Should have templateUrl', function () {
expect(accountsstate.templateUrl).toBe('modules/users/client/views/settings/manage-social-accounts.client.view.html');
expect(accountsstate.templateUrl).toBe('/modules/users/client/views/settings/manage-social-accounts.client.view.html');
});
});
@@ -110,27 +111,37 @@
});
it('Should have templateUrl', function () {
expect(picturestate.templateUrl).toBe('modules/users/client/views/settings/change-profile-picture.client.view.html');
expect(picturestate.templateUrl).toBe('/modules/users/client/views/settings/change-profile-picture.client.view.html');
});
});
describe('Handle Trailing Slash', function () {
beforeEach(inject(function ($state, $rootScope, _Authentication_) {
beforeEach(inject(function ($state, $rootScope, _Authentication_, _$httpBackend_) {
Authentication.user = {
name: 'user',
roles: ['user']
};
$httpBackend = _$httpBackend_;
// Ignore parent template gets on state transitions
$httpBackend.whenGET('/modules/users/client/views/settings/settings.client.view.html').respond(200);
$httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200);
$httpBackend.whenGET('/modules/users/client/views/settings/edit-profile.client.view.html').respond(200);
$state.go('settings.profile');
$rootScope.$digest();
}));
it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
it('Should remove trailing slash', inject(function ($state, $location, $rootScope, $templateCache) {
$templateCache.put('/modules/users/client/views/settings/settings.client.view.html', '');
$templateCache.put('/modules/users/client/views/settings/edit-profile.client.view.html', '');
$location.path('settings/profile/');
$rootScope.$digest();
expect($location.path()).toBe('/settings/profile');
expect($state.current.templateUrl).toBe('modules/users/client/views/settings/edit-profile.client.view.html');
expect($state.current.templateUrl).toBe('/modules/users/client/views/settings/edit-profile.client.view.html');
}));
});
@@ -152,7 +163,7 @@
});
it('Should have templateUrl', function () {
expect(mainstate.templateUrl).toBe('modules/users/client/views/authentication/authentication.client.view.html');
expect(mainstate.templateUrl).toBe('/modules/users/client/views/authentication/authentication.client.view.html');
});
});
@@ -171,7 +182,7 @@
});
it('Should have templateUrl', function () {
expect(signupstate.templateUrl).toBe('modules/users/client/views/authentication/signup.client.view.html');
expect(signupstate.templateUrl).toBe('/modules/users/client/views/authentication/signup.client.view.html');
});
});
@@ -190,7 +201,7 @@
});
it('Should have templateUrl', function () {
expect(signinstate.templateUrl).toBe('modules/users/client/views/authentication/signin.client.view.html');
expect(signinstate.templateUrl).toBe('/modules/users/client/views/authentication/signin.client.view.html');
});
});
@@ -231,7 +242,7 @@
});
it('Should have templateUrl', function () {
expect(forgotstate.templateUrl).toBe('modules/users/client/views/password/forgot-password.client.view.html');
expect(forgotstate.templateUrl).toBe('/modules/users/client/views/password/forgot-password.client.view.html');
});
});
@@ -272,7 +283,7 @@
});
it('Should have templateUrl', function () {
expect(invalidstate.templateUrl).toBe('modules/users/client/views/password/reset-password-invalid.client.view.html');
expect(invalidstate.templateUrl).toBe('/modules/users/client/views/password/reset-password-invalid.client.view.html');
});
});
@@ -291,7 +302,7 @@
});
it('Should have templateUrl', function () {
expect(successstate.templateUrl).toBe('modules/users/client/views/password/reset-password-success.client.view.html');
expect(successstate.templateUrl).toBe('/modules/users/client/views/password/reset-password-success.client.view.html');
});
});
@@ -310,7 +321,7 @@
});
it('Should have templateUrl', function () {
expect(formstate.templateUrl).toBe('modules/users/client/views/password/reset-password.client.view.html');
expect(formstate.templateUrl).toBe('/modules/users/client/views/password/reset-password.client.view.html');
});
});

View File

@@ -272,7 +272,7 @@ describe('Users E2E Tests:', function () {
// Click Submit button
element(by.css('button[type=submit]')).click();
// Password Error
expect(element.all(by.css('strong')).get(0).getText()).toBe('Email already exists');
expect(element.all(by.css('.message')).get(0).getText()).toBe('Email already exists');
});
it('Should report Username already exists', function () {
@@ -291,7 +291,7 @@ describe('Users E2E Tests:', function () {
// Click Submit button
element(by.css('button[type=submit]')).click();
// Password Error
expect(element.all(by.css('strong')).get(0).getText()).toBe('Username already exists');
expect(element.all(by.css('.message')).get(0).getText()).toBe('Username already exists');
});
});
@@ -436,7 +436,7 @@ describe('Users E2E Tests:', function () {
// Click Submit button
element(by.css('button[type=submit]')).click();
// Password Changed
expect(element.all(by.css('.text-success')).get(0).getText()).toBe('Password Changed Successfully');
expect(element.all(by.css('.ui-notification')).get(0).getText()).toBe('Password Changed Successfully');
});
});
});

View File

@@ -328,7 +328,7 @@ describe('User CRUD tests', function () {
.send({
username: ''
})
.expect(400)
.expect(422)
.end(function (err, res) {
// Handle error
if (err) {
@@ -507,7 +507,7 @@ describe('User CRUD tests', function () {
verifyPassword: '1234567890-ABC-123-Aa$',
currentPassword: credentials.password
})
.expect(400)
.expect(422)
.end(function (err, res) {
if (err) {
return done(err);
@@ -536,7 +536,7 @@ describe('User CRUD tests', function () {
verifyPassword: '1234567890Aa$',
currentPassword: 'some_wrong_passwordAa$'
})
.expect(400)
.expect(422)
.end(function (err, res) {
if (err) {
return done(err);
@@ -565,7 +565,7 @@ describe('User CRUD tests', function () {
verifyPassword: '',
currentPassword: credentials.password
})
.expect(400)
.expect(422)
.end(function (err, res) {
if (err) {
return done(err);
@@ -577,7 +577,7 @@ describe('User CRUD tests', function () {
});
});
it('should not be able to change user own password if no new password is at all given', function (done) {
it('should not be able to change user own password if not signed in', function (done) {
// Change password
agent.post('/api/users/password')
@@ -586,7 +586,7 @@ describe('User CRUD tests', function () {
verifyPassword: '1234567890Aa$',
currentPassword: credentials.password
})
.expect(400)
.expect(401)
.end(function (err, res) {
if (err) {
return done(err);
@@ -759,7 +759,7 @@ describe('User CRUD tests', function () {
agent.put('/api/users')
.send(userUpdate)
.expect(400)
.expect(422)
.end(function (userInfoErr, userInfoRes) {
if (userInfoErr) {
return done(userInfoErr);
@@ -811,7 +811,7 @@ describe('User CRUD tests', function () {
agent.put('/api/users')
.send(userUpdate)
.expect(400)
.expect(422)
.end(function (userInfoErr, userInfoRes) {
if (userInfoErr) {
return done(userInfoErr);
@@ -888,7 +888,7 @@ describe('User CRUD tests', function () {
agent.put('/api/users')
.send(userUpdate)
.expect(400)
.expect(401)
.end(function (userInfoErr, userInfoRes) {
if (userInfoErr) {
return done(userInfoErr);
@@ -906,7 +906,7 @@ describe('User CRUD tests', function () {
agent.post('/api/users/picture')
.send({})
.expect(400)
.expect(401)
.end(function (userInfoErr, userInfoRes) {
if (userInfoErr) {
return done(userInfoErr);
@@ -931,7 +931,6 @@ describe('User CRUD tests', function () {
agent.post('/api/users/picture')
.attach('newProfilePicture', './modules/users/client/img/profile/default.png')
.send(credentials)
.expect(200)
.end(function (userInfoErr, userInfoRes) {
// Handle change profile picture error
@@ -961,7 +960,7 @@ describe('User CRUD tests', function () {
agent.post('/api/users/picture')
.attach('fieldThatDoesntWork', './modules/users/client/img/profile/default.png')
.send(credentials)
.expect(400)
.expect(422)
.end(function (userInfoErr, userInfoRes) {
done(userInfoErr);
});

View File

@@ -88,12 +88,12 @@
"gulp-imagemin": "~3.0.3",
"gulp-istanbul": "~1.1.1",
"gulp-less": "~3.1.0",
"gulp-livereload": "~3.8.1",
"gulp-load-plugins": "~1.3.0",
"gulp-mocha": "~3.0.1",
"gulp-ng-annotate": "~2.0.0",
"gulp-nodemon": "~2.2.1",
"gulp-protractor": "~3.0.0",
"gulp-refresh": "~1.1.0",
"gulp-rename": "~1.2.2",
"gulp-rev": "^7.1.2",
"gulp-sass": "~2.3.0",