diff --git a/modules/articles/client/config/articles.client.routes.js b/modules/articles/client/config/articles.client.routes.js
index ab0337a695..2505bec742 100644
--- a/modules/articles/client/config/articles.client.routes.js
+++ b/modules/articles/client/config/articles.client.routes.js
@@ -10,7 +10,7 @@ angular.module('articles').config(['$stateProvider',
url: '/articles',
template: '',
data: {
- roles: ['user']
+ roles: ['user', 'admin']
}
}).
state('articles.list', {
diff --git a/modules/chat/client/config/chat.client.routes.js b/modules/chat/client/config/chat.client.routes.js
index 490a11da88..becabe53e0 100644
--- a/modules/chat/client/config/chat.client.routes.js
+++ b/modules/chat/client/config/chat.client.routes.js
@@ -8,7 +8,7 @@ angular.module('chat').config(['$stateProvider',
url: '/chat',
templateUrl: 'modules/chat/views/chat.client.view.html',
data: {
- roles: ['user']
+ roles: ['user', 'admin']
}
});
}
diff --git a/modules/core/client/config/core-admin.client.menus.js b/modules/core/client/config/core-admin.client.menus.js
new file mode 100644
index 0000000000..a2afa83668
--- /dev/null
+++ b/modules/core/client/config/core-admin.client.menus.js
@@ -0,0 +1,12 @@
+'use strict';
+
+angular.module('core.admin').run(['Menus',
+ function (Menus) {
+ Menus.addMenuItem('topbar', {
+ title: 'Admin',
+ state: 'admin',
+ type: 'dropdown',
+ roles: ['admin']
+ });
+ }
+]);
diff --git a/modules/core/client/config/core-admin.client.routes.js b/modules/core/client/config/core-admin.client.routes.js
new file mode 100644
index 0000000000..1697246fa7
--- /dev/null
+++ b/modules/core/client/config/core-admin.client.routes.js
@@ -0,0 +1,16 @@
+'use strict';
+
+// Setting up route
+angular.module('core.admin.routes').config(['$stateProvider',
+ function ($stateProvider) {
+ $stateProvider
+ .state('admin', {
+ abstract: true,
+ url: '/admin',
+ template: '',
+ data: {
+ roles: ['admin']
+ }
+ });
+ }
+]);
diff --git a/modules/core/client/core.client.module.js b/modules/core/client/core.client.module.js
index b2658634cb..5850d6aec7 100644
--- a/modules/core/client/core.client.module.js
+++ b/modules/core/client/core.client.module.js
@@ -2,3 +2,5 @@
// Use Applicaion configuration module to register a new module
ApplicationConfiguration.registerModule('core');
+ApplicationConfiguration.registerModule('core.admin', ['core']);
+ApplicationConfiguration.registerModule('core.admin.routes', ['ui.router']);
diff --git a/modules/users/client/config/users-admin.client.menus.js b/modules/users/client/config/users-admin.client.menus.js
new file mode 100644
index 0000000000..33f998ae8f
--- /dev/null
+++ b/modules/users/client/config/users-admin.client.menus.js
@@ -0,0 +1,11 @@
+'use strict';
+
+// Configuring the Articles module
+angular.module('users.admin').run(['Menus',
+ function (Menus) {
+ Menus.addSubMenuItem('topbar', 'admin', {
+ title: 'Manage Users',
+ state: 'admin.users'
+ });
+ }
+]);
diff --git a/modules/users/client/config/users-admin.client.routes.js b/modules/users/client/config/users-admin.client.routes.js
new file mode 100644
index 0000000000..8cf34221d0
--- /dev/null
+++ b/modules/users/client/config/users-admin.client.routes.js
@@ -0,0 +1,37 @@
+'use strict';
+
+// Setting up route
+angular.module('users.admin.routes').config(['$stateProvider',
+ function ($stateProvider) {
+ $stateProvider
+ .state('admin.users', {
+ url: '/users',
+ templateUrl: 'modules/users/views/admin/user-list.client.view.html',
+ controller: 'UserListController'
+ })
+ .state('admin.user', {
+ url: '/users/:userId',
+ templateUrl: 'modules/users/views/admin/user.client.view.html',
+ controller: 'UserController',
+ resolve: {
+ userResolve: ['$stateParams', 'Admin', function ($stateParams, Admin) {
+ return Admin.get({
+ userId: $stateParams.userId
+ });
+ }]
+ }
+ })
+ .state('admin.user-edit', {
+ url: '/users/:userId/edit',
+ templateUrl: 'modules/users/views/admin/user-edit.client.view.html',
+ controller: 'UserController',
+ resolve: {
+ userResolve: ['$stateParams', 'Admin', function ($stateParams, Admin) {
+ return Admin.get({
+ userId: $stateParams.userId
+ });
+ }]
+ }
+ });
+ }
+]);
diff --git a/modules/users/client/config/users.client.routes.js b/modules/users/client/config/users.client.routes.js
index 1646d50717..c38632650a 100644
--- a/modules/users/client/config/users.client.routes.js
+++ b/modules/users/client/config/users.client.routes.js
@@ -10,7 +10,7 @@ angular.module('users').config(['$stateProvider',
url: '/settings',
templateUrl: 'modules/users/views/settings/settings.client.view.html',
data: {
- roles: ['user']
+ roles: ['user', 'admin']
}
}).
state('settings.profile', {
diff --git a/modules/users/client/controllers/admin/user-list.client.controller.js b/modules/users/client/controllers/admin/user-list.client.controller.js
new file mode 100644
index 0000000000..a552dd0e47
--- /dev/null
+++ b/modules/users/client/controllers/admin/user-list.client.controller.js
@@ -0,0 +1,31 @@
+'use strict';
+
+angular.module('users.admin').controller('UserListController', ['$scope', '$filter', 'Admin',
+ function ($scope, $filter, Admin) {
+ Admin.query(function (data) {
+ $scope.users = data;
+ $scope.buildPager();
+ });
+
+ $scope.buildPager = function () {
+ $scope.pagedItems = [];
+ $scope.itemsPerPage = 15;
+ $scope.currentPage = 1;
+ $scope.figureOutItemsToDisplay();
+ };
+
+ $scope.figureOutItemsToDisplay = function () {
+ $scope.filteredItems = $filter('filter')($scope.users, {
+ $: $scope.search
+ });
+ $scope.filterLength = $scope.filteredItems.length;
+ var begin = (($scope.currentPage - 1) * $scope.itemsPerPage);
+ var end = begin + $scope.itemsPerPage;
+ $scope.pagedItems = $scope.filteredItems.slice(begin, end);
+ };
+
+ $scope.pageChanged = function () {
+ $scope.figureOutItemsToDisplay();
+ };
+ }
+]);
diff --git a/modules/users/client/controllers/admin/user.client.controller.js b/modules/users/client/controllers/admin/user.client.controller.js
new file mode 100644
index 0000000000..754316ec20
--- /dev/null
+++ b/modules/users/client/controllers/admin/user.client.controller.js
@@ -0,0 +1,34 @@
+'use strict';
+
+angular.module('users.admin').controller('UserController', ['$scope', '$state', 'Authentication', 'userResolve',
+ function ($scope, $state, Authentication, userResolve) {
+ $scope.authentication = Authentication;
+ $scope.user = userResolve;
+
+ $scope.remove = function (user) {
+ if (confirm('Are you sure you want to delete this user?')) {
+ if (user) {
+ user.$remove();
+
+ $scope.users.splice($scope.users.indexOf(user), 1);
+ } else {
+ $scope.user.$remove(function () {
+ $state.go('admin.users');
+ });
+ }
+ }
+ };
+
+ $scope.update = function () {
+ var user = $scope.user;
+
+ user.$update(function () {
+ $state.go('admin.user', {
+ userId: user._id
+ });
+ }, function (errorResponse) {
+ $scope.error = errorResponse.data.message;
+ });
+ };
+ }
+]);
diff --git a/modules/users/client/services/users.client.service.js b/modules/users/client/services/users.client.service.js
index f8a68eeac2..eb3abfeee3 100644
--- a/modules/users/client/services/users.client.service.js
+++ b/modules/users/client/services/users.client.service.js
@@ -2,7 +2,7 @@
// Users service used for communicating with the users REST endpoint
angular.module('users').factory('Users', ['$resource',
- function($resource) {
+ function ($resource) {
return $resource('api/users', {}, {
update: {
method: 'PUT'
@@ -10,3 +10,17 @@ angular.module('users').factory('Users', ['$resource',
});
}
]);
+
+
+//TODO this should be Users service
+angular.module('users.admin').factory('Admin', ['$resource',
+ function ($resource) {
+ return $resource('api/users/:userId', {
+ userId: '@_id'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+ }
+]);
diff --git a/modules/users/client/users.client.module.js b/modules/users/client/users.client.module.js
index 569aba8c16..8a95d388ca 100644
--- a/modules/users/client/users.client.module.js
+++ b/modules/users/client/users.client.module.js
@@ -1,4 +1,6 @@
'use strict';
// Use Applicaion configuration module to register a new module
-ApplicationConfiguration.registerModule('users');
+ApplicationConfiguration.registerModule('users', ['core']);
+ApplicationConfiguration.registerModule('users.admin', ['core.admin']);
+ApplicationConfiguration.registerModule('users.admin.routes', ['core.admin.routes']);
diff --git a/modules/users/client/views/admin/user-edit.client.view.html b/modules/users/client/views/admin/user-edit.client.view.html
new file mode 100644
index 0000000000..26e274b96a
--- /dev/null
+++ b/modules/users/client/views/admin/user-edit.client.view.html
@@ -0,0 +1,35 @@
+
diff --git a/modules/users/client/views/admin/user-list.client.view.html b/modules/users/client/views/admin/user-list.client.view.html
new file mode 100644
index 0000000000..dd933302b5
--- /dev/null
+++ b/modules/users/client/views/admin/user-list.client.view.html
@@ -0,0 +1,20 @@
+
diff --git a/modules/users/client/views/admin/user.client.view.html b/modules/users/client/views/admin/user.client.view.html
new file mode 100644
index 0000000000..eef7cf4703
--- /dev/null
+++ b/modules/users/client/views/admin/user.client.view.html
@@ -0,0 +1,51 @@
+
diff --git a/modules/users/server/controllers/admin.server.controller.js b/modules/users/server/controllers/admin.server.controller.js
new file mode 100644
index 0000000000..c2998f9e9a
--- /dev/null
+++ b/modules/users/server/controllers/admin.server.controller.js
@@ -0,0 +1,83 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var path = require('path'),
+ mongoose = require('mongoose'),
+ User = mongoose.model('User'),
+ errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));
+
+/**
+ * Show the current user
+ */
+exports.read = function (req, res) {
+ res.json(req.model);
+};
+
+/**
+ * Update a User
+ */
+exports.update = function (req, res) {
+ var user = req.model;
+
+ //For security purposes only merge these parameters
+ user.firstName = req.body.firstName;
+ user.lastName = req.body.lastName;
+ user.displayName = user.firstName + ' ' + user.lastName;
+ user.roles = req.body.roles;
+
+ user.save(function (err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ }
+
+ res.json(user);
+ });
+};
+
+/**
+ * Delete a user
+ */
+exports.delete = function (req, res) {
+ var user = req.model;
+
+ user.remove(function (err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ }
+
+ res.json(user);
+ });
+};
+
+/**
+ * List of Users
+ */
+exports.list = function (req, res) {
+ User.find({}, '-salt -password').sort('-created').populate('user', 'displayName').exec(function (err, users) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ }
+
+ res.json(users);
+ });
+};
+
+/**
+ * User middleware
+ */
+exports.userByID = function (req, res, next, id) {
+ User.findById(id, '-salt -password').exec(function (err, user) {
+ if (err) return next(err);
+ if (!user) return next(new Error('Failed to load user ' + id));
+ req.model = user;
+ next();
+ });
+};
diff --git a/modules/users/server/policies/admin.server.policies.js b/modules/users/server/policies/admin.server.policies.js
new file mode 100644
index 0000000000..b0860ec82b
--- /dev/null
+++ b/modules/users/server/policies/admin.server.policies.js
@@ -0,0 +1,49 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var acl = require('acl');
+
+// Using the memory backend
+acl = new acl(new acl.memoryBackend());
+
+/**
+ * Invoke Articles Permissions
+ */
+exports.invokeRolesPolicies = function () {
+ acl.allow([{
+ roles: ['admin'],
+ allows: [{
+ resources: '/api/users',
+ permissions: '*'
+ }, {
+ resources: '/api/users/:userId',
+ permissions: '*'
+ }]
+ }]);
+};
+
+/**
+ * Check If Admin Policy Allows
+ */
+exports.isAllowed = function (req, res, next) {
+ var roles = (req.user) ? req.user.roles : ['guest'];
+
+ // Check for user roles
+ acl.areAnyRolesAllowed(roles, req.route.path, req.method.toLowerCase(), function (err, isAllowed) {
+ if (err) {
+ // An authorization error occurred.
+ return res.status(500).send('Unexpected authorization error');
+ } else {
+ if (isAllowed) {
+ // Access granted! Invoke next middleware
+ return next();
+ } else {
+ return res.status(403).json({
+ message: 'User is not authorized'
+ });
+ }
+ }
+ });
+};
diff --git a/modules/users/server/routes/admin.server.routes.js b/modules/users/server/routes/admin.server.routes.js
new file mode 100644
index 0000000000..d2fd4f4630
--- /dev/null
+++ b/modules/users/server/routes/admin.server.routes.js
@@ -0,0 +1,22 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var adminPolicy = require('../policies/admin.server.policies'),
+ admin = require('../controllers/admin.server.controller');
+
+module.exports = function (app) {
+ // Users collection routes
+ app.route('/api/users').all(adminPolicy.isAllowed)
+ .get(admin.list);
+
+ // Single user routes
+ app.route('/api/users/:userId').all(adminPolicy.isAllowed)
+ .get(admin.read)
+ .put(admin.update)
+ .delete(admin.delete);
+
+ // Finish by binding the user middleware
+ app.param('userId', admin.userByID);
+};