Adds users admin section.

Project: http://git-wip-us.apache.org/repos/asf/rave/repo
Commit: http://git-wip-us.apache.org/repos/asf/rave/commit/22917b44
Tree: http://git-wip-us.apache.org/repos/asf/rave/tree/22917b44
Diff: http://git-wip-us.apache.org/repos/asf/rave/diff/22917b44

Branch: refs/heads/angular
Commit: 22917b440655a6820401231e233ec3e09604b5b5
Parents: 03bce44
Author: Jmeas <[email protected]>
Authored: Thu Aug 14 09:57:57 2014 -0400
Committer: Jmeas <[email protected]>
Committed: Thu Aug 14 13:07:05 2014 -0400

----------------------------------------------------------------------
 rave-portal-ng/mock-api/bootstrap-data.js       | 32 +++++++
 rave-portal-ng/mock-api/bootstrap.js            |  6 ++
 .../mock-api/database/import-data/users.js      | 68 +++++++++++++-
 .../authentication/create-account/post.js       |  6 +-
 .../modules/authentication/login/post.js        | 25 ++++--
 .../modules/authentication/verify/post.js       | 23 +++--
 rave-portal-ng/mock-api/modules/user/delete.js  | 50 +++++++++++
 rave-portal-ng/mock-api/modules/user/get.js     | 59 +++++++++++++
 rave-portal-ng/mock-api/modules/user/put.js     | 93 ++++++++++++++++++++
 rave-portal-ng/mock-api/modules/users/get.js    | 47 ++++++++++
 rave-portal-ng/src/index.html                   | 18 ----
 rave-portal-ng/src/index.js                     |  2 +
 rave-portal-ng/src/rave.js                      | 17 ++--
 .../preferences/templates/preferences.html      |  2 +-
 .../src/subapps/admin/users/controllers/user.js | 90 +++++++++++++++++++
 .../subapps/admin/users/controllers/users.js    |  8 +-
 .../src/subapps/admin/users/resources/user.js   | 34 +++++++
 .../src/subapps/admin/users/resources/users.js  | 35 ++++++++
 .../src/subapps/admin/users/routes.js           | 20 ++++-
 .../subapps/admin/users/templates/detail.html   | 61 -------------
 .../src/subapps/admin/users/templates/user.html | 76 ++++++++++++++++
 .../subapps/admin/users/templates/users.html    |  8 +-
 rave-portal-ng/src/subapps/admin/users/users.js |  9 ++
 .../subapps/auth/security/services/security.js  |  4 +-
 .../src/subapps/home/templates/home.html        |  2 +-
 25 files changed, 677 insertions(+), 118 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/bootstrap-data.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/bootstrap-data.js 
b/rave-portal-ng/mock-api/bootstrap-data.js
new file mode 100644
index 0000000..6eafd9f
--- /dev/null
+++ b/rave-portal-ng/mock-api/bootstrap-data.js
@@ -0,0 +1,32 @@
+/*
+ * bootstrap
+ * 
+ * Note: This file is to be included during development only
+ *
+ * This file fakes out our initial data.
+ * 
+ */
+
+define(function(require) {
+
+  var api = require('./core.js');
+  require('underscore/underscore');
+
+  function getPreferences() {
+    var results = api.db.query('preferences');
+
+    var preferences = {};
+
+    _.each(results, function(item) {
+      preferences[item.key] = item.value;
+    });
+
+    return preferences;
+  }
+
+  var initialData = {};
+
+  initialData.preferences = getPreferences();
+
+  window.initialData = initialData;
+});

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/bootstrap.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/bootstrap.js 
b/rave-portal-ng/mock-api/bootstrap.js
index 3a7cf5a..71e344b 100644
--- a/rave-portal-ng/mock-api/bootstrap.js
+++ b/rave-portal-ng/mock-api/bootstrap.js
@@ -40,6 +40,12 @@ define(function(require) {
        require('./modules/preferences/get.js');
        require('./modules/preferences/put.js');
 
+       // users
+       require('./modules/users/get.js');
+       require('./modules/user/get.js');
+       require('./modules/user/put.js');
+       require('./modules/user/delete.js');
+
        // pages
        require('./modules/pages/get.js');
 

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/database/import-data/users.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/database/import-data/users.js 
b/rave-portal-ng/mock-api/database/import-data/users.js
index 8ab5b49..8a5bbbb 100644
--- a/rave-portal-ng/mock-api/database/import-data/users.js
+++ b/rave-portal-ng/mock-api/database/import-data/users.js
@@ -13,6 +13,10 @@ define(function(require) {
                        'relationshipStatus': 'Single',
                        'description': 'I like JS.',
                        'sessionToken': '',
+                       'locked': false,
+                       'enabled': true,
+                       'expired': false,
+                       'authorities': ['ROLE_USER', 'ROLE_ADMIN']
                },
                {
                        'username': 'admin',
@@ -23,8 +27,44 @@ define(function(require) {
                        'lastName': 'Admin',
                        'nameSeenByOthers': 'Admin',
                        'relationshipStatus': 'Single',
-                       'description': 'I\'m a BOSS.',
+                       'description': 'Pizza is good.',
                        'sessionToken': '',
+                       'locked': false,
+                       'enabled': true,
+                       'expired': false,
+                       'authorities': ['ROLE_ADMIN']
+               },
+               {
+                       'username': 'disabled',
+                       'password': 'disabled',
+                       'email': '[email protected]',
+                       'openIdUrl': '',
+                       'firstName': 'Dis',
+                       'lastName': 'Abled',
+                       'nameSeenByOthers': 'Disabled',
+                       'relationshipStatus': 'Single',
+                       'description': 'I cannot login.',
+                       'sessionToken': '',
+                       'locked': false,
+                       'enabled': false,
+                       'expired': false,
+                       'authorities': ['ROLE_USER']
+               },
+               {
+                       'username': 'canonical',
+                       'password': 'canonical',
+                       'email': '[email protected]',
+                       'openIdUrl': '',
+                       'firstName': 'Canon',
+                       'lastName': 'Ical',
+                       'nameSeenByOthers': 'Canonical',
+                       'relationshipStatus': 'Single',
+                       'description': 'Remember me?',
+                       'sessionToken': '',
+                       'locked': false,
+                       'enabled': true,
+                       'expired': false,
+                       'authorities': ['ROLE_ADMIN']
                },
                {
                        'username': 'jmeas',
@@ -36,7 +76,27 @@ define(function(require) {
                        'nameSeenByOthers': 'James',
                        'relationshipStatus': 'Single',
                        'description': 'I like JS.',
-                       'sessionToken': ''
-               }
+                       'sessionToken': '',
+                       'locked': false,
+                       'enabled': true,
+                       'expired': false,
+                       'authorities': ['ROLE_ADMIN', 'ROLE_USER']
+               },
+               {
+                       'username': 'jane.doe',
+                       'password': 'jane.doe',
+                       'email': '[email protected]',
+                       'openIdUrl': '',
+                       'firstName': 'Jane',
+                       'lastName': 'Doe',
+                       'nameSeenByOthers': 'Jane',
+                       'relationshipStatus': 'Single',
+                       'description': 'Rave test user.',
+                       'sessionToken': '',
+                       'locked': false,
+                       'enabled': true,
+                       'expired': false,
+                       'authorities': ['ROLE_USER']
+               },
        ];
-});
\ No newline at end of file
+});

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/authentication/create-account/post.js
----------------------------------------------------------------------
diff --git 
a/rave-portal-ng/mock-api/modules/authentication/create-account/post.js 
b/rave-portal-ng/mock-api/modules/authentication/create-account/post.js
index 6bcfbe5..464e3a4 100644
--- a/rave-portal-ng/mock-api/modules/authentication/create-account/post.js
+++ b/rave-portal-ng/mock-api/modules/authentication/create-account/post.js
@@ -59,7 +59,11 @@ define(function(require) {
                        lastName: (data.hasOwnProperty('lastName') ? 
data.lastName : '' ),
                        nameSeenByOthers: 
(data.hasOwnProperty('nameSeenByOthers') ? data.nameSeenByOthers : ''),
                        relationshipStatus: 
(data.hasOwnProperty('relationshipStatus') ? data.relationshipStatus: ''),
-                       description: (data.hasOwnProperty('description') ? 
data.description: '')
+                       description: (data.hasOwnProperty('description') ? 
data.description: ''),
+                       locked: false,
+                       enabled: true,
+                       expired: false,
+                       authorities: ['ROLE_USER']
                };
 
                api.db.insert('users', newUserData);

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/authentication/login/post.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/modules/authentication/login/post.js 
b/rave-portal-ng/mock-api/modules/authentication/login/post.js
index 3003213..ddab953 100644
--- a/rave-portal-ng/mock-api/modules/authentication/login/post.js
+++ b/rave-portal-ng/mock-api/modules/authentication/login/post.js
@@ -3,6 +3,21 @@ define(function(require) {
 
        var api = require('../../../core.js');
 
+       // The keys we want to send back when we're verified
+       var userKeys = [
+    'ID',
+    'username',
+    'description',
+    'firstName',
+    'lastName',
+    'locked',
+    'enabled',
+    'expired',
+    'authorities',
+    'openIdUrl',
+    'email'
+  ];
+
        function retrieveUser(username, password) {
                var results = api.db.query('users', {
                        username: username,
@@ -52,6 +67,8 @@ define(function(require) {
                        return [401, 'Invalid login.'];
                }
 
+               user = _.pick(user, userKeys);
+
                // update the user's token in the database
                var token = generateSessionToken();
                updateUserSessionToken(user.username, token);
@@ -59,12 +76,8 @@ define(function(require) {
                // return a record for the user
                return [200, {
                        authorized: true,
-                       user: {
-                               id: user.ID,
-                               authLevel: 'admin',
-                               name: user.nameSeenByOthers,
-                               token: token
-                       }
+                       user: user,
+                       token: token
                }];
        }
 

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/authentication/verify/post.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/modules/authentication/verify/post.js 
b/rave-portal-ng/mock-api/modules/authentication/verify/post.js
index 4d8d427..6906445 100644
--- a/rave-portal-ng/mock-api/modules/authentication/verify/post.js
+++ b/rave-portal-ng/mock-api/modules/authentication/verify/post.js
@@ -4,6 +4,21 @@ define(function(require) {
        require('underscore/underscore');
        var api = require('../../../core.js');
 
+       // The keys we want to send back when we're verified
+       var userKeys = [
+    'ID',
+    'username',
+    'description',
+    'firstName',
+    'lastName',
+    'locked',
+    'enabled',
+    'expired',
+    'authorities',
+    'openIdUrl',
+    'email'
+  ];
+
        // All of these 'helper' methods should be abstracted into (a) separate 
module(s).
        function retrieveUserByToken(token) {
                var results = api.db.query('users', {
@@ -32,14 +47,12 @@ define(function(require) {
                        return [401, 'Invalid token'];
                }
 
+               user = _.pick(user, userKeys);
+
                // return the user object
                return [200, {
                        authorized: true,
-                       user: {
-                               id: user.ID,
-                               authLevel: 'admin',
-                               name: user.nameSeenByOthers
-                       }
+                       user: user
                }];
        }
 

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/user/delete.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/modules/user/delete.js 
b/rave-portal-ng/mock-api/modules/user/delete.js
new file mode 100644
index 0000000..c7bf92d
--- /dev/null
+++ b/rave-portal-ng/mock-api/modules/user/delete.js
@@ -0,0 +1,50 @@
+define(function(require) {
+  'use strict';
+
+  var api = require('../../core.js');
+  require('underscore/underscore');
+
+  function userExists(id) {
+    var results = api.db.query('users', {
+      ID: id
+    });
+
+    if (results.length === 1) {
+      return true;
+    }
+
+    return false;
+  }
+
+  function deleteUser(id) {
+    api.db.deleteRows('users', {
+      ID: id
+    });
+    api.db.commit();
+  }
+
+  function processRequest(method, url, data, headers) {
+    if (method !== 'DELETE') {
+      return [405, 'Unknown request'];
+    } else if (!this.requestHasToken) {
+      return [401, 'A valid token is required'];
+    } else if (!this.userIsAuthenticated) {
+      return [401, 'Invalid token'];
+    }
+
+    // attempt to parse the user ID
+    var userID = parseInt( url.replace( '/api/v1/user/', '' ), 10 );
+    if (!_.isNumber(userID) || _.isNaN(userID)) {
+      return [400, 'Invalid user ID'];
+    } else if (!userExists(userID)) {
+      return [404, 'User does not exist'];
+    }
+
+    deleteUser(userID);
+
+    return [200, null];
+  }
+
+  api.register('/user/:id', 'delete', processRequest);
+
+} );

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/user/get.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/modules/user/get.js 
b/rave-portal-ng/mock-api/modules/user/get.js
new file mode 100644
index 0000000..9c712a5
--- /dev/null
+++ b/rave-portal-ng/mock-api/modules/user/get.js
@@ -0,0 +1,59 @@
+define(function(require) {
+  'use strict';
+
+  var api = require('../../core.js');
+  require('underscore/underscore');
+
+  // The whitelisted keys that we send back with our request for the users
+  var userKeys = [
+    'ID',
+    'username',
+    'description',
+    'firstName',
+    'lastName',
+    'locked',
+    'enabled',
+    'expired',
+    'authorities',
+    'openIdUrl',
+    'email'
+  ];
+
+  function getUser(id) {
+    var results = api.db.query('users', {
+      ID: id
+    });
+
+    if (results.length === 1) {
+      return _.pick(results[0], userKeys);
+    }
+
+    return false;
+  }
+
+  function processRequest(method, url, data, headers) {
+    if (method !== 'GET') {
+      return [405, 'Unknown request'];
+    } else if (!this.requestHasToken) {
+      return [401, 'A valid token is required'];
+    } else if (!this.userIsAuthenticated) {
+      return [401, 'Invalid token'];
+    }
+
+    // attempt to parse the user ID
+    var userID = parseInt(url.replace('/api/v1/user/', ''), 10);
+    if (!_.isNumber(userID) || _.isNaN(userID)) {
+      return [400, 'Invalid user ID'];
+    }
+
+    var user = getUser(userID);
+    if (!user) {
+      return [404, 'User does not exist'];
+    }
+
+    return [200, user];
+  }
+
+  api.register('/user/:id', 'get', processRequest);
+
+} );

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/user/put.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/modules/user/put.js 
b/rave-portal-ng/mock-api/modules/user/put.js
new file mode 100644
index 0000000..dfd794a
--- /dev/null
+++ b/rave-portal-ng/mock-api/modules/user/put.js
@@ -0,0 +1,93 @@
+define(function(require) {
+  'use strict';
+
+  var api = require('../../core.js');
+  require('underscore/underscore');
+
+  // The keys that a user is allowed to update through the client
+  var updateKeys = [
+    'email',
+    'openIdUrl',
+    'enabled',
+    'expired',
+    'locked',
+    'authorities'
+  ];
+
+  // The whitelisted keys that we send back with our request for the users
+  var userKeys = [
+    'ID',
+    'username',
+    'description',
+    'firstName',
+    'lastName',
+    'locked',
+    'enabled',
+    'expired',
+    'authorities',
+    'openIdUrl',
+    'email'
+  ];
+
+  function userExists(id) {
+    var results = api.db.query('users', {
+      ID: id
+    });
+
+    if (results.length === 1) {
+      return results[0];
+    }
+
+    return false;
+  }
+
+  function updateUser(userID, data) {
+    var searchParams = {
+      ID: userID
+    };
+    api.db.update('users', searchParams, function(row) {
+      _.extend(row, _.pick(data, updateKeys));
+      return row;
+    });
+    api.db.commit();
+
+    var results = api.db.query('users', searchParams);
+    if (results.length === 1) {
+      return _.pick(results[0], userKeys);
+    }
+
+    return false;
+  }
+
+  function processRequest(method, url, data, headers) {
+    if (method !== 'PUT') {
+      return [405, 'Unknown request'];
+    } else if (!this.requestHasToken) {
+      return [401, 'A valid token is required'];
+    } else if (!this.userIsAuthenticated) {
+      return [401, 'Invalid token'];
+    }
+
+    // attempt to parse the user ID
+    var userID = parseInt( url.replace( '/api/v1/user/', '' ), 10 );
+    if (!_.isNumber(userID) || _.isNaN(userID)) {
+      return [400, 'Invalid user ID'];
+    }
+
+    data = angular.fromJson(data);
+
+    if (!userExists(userID)) {
+      return [404, 'User does not exist'];
+    }
+
+    var updatedUser = updateUser(userID, data);
+    if (!updatedUser) {
+      return [500, 'An internal database error has occurred'];
+    }
+
+    return [200, updatedUser];
+  }
+
+  api.register('/user/:id', 'put', processRequest);
+
+} );

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/mock-api/modules/users/get.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/mock-api/modules/users/get.js 
b/rave-portal-ng/mock-api/modules/users/get.js
new file mode 100644
index 0000000..4e52226
--- /dev/null
+++ b/rave-portal-ng/mock-api/modules/users/get.js
@@ -0,0 +1,47 @@
+define(function(require) {
+  'use strict';
+
+  var api = require('../../core.js');
+  require('underscore/underscore');
+
+  // The whitelisted keys that we send back with our request for the users
+  var userKeys = [
+    'ID',
+    'username',
+    'description',
+    'firstName',
+    'lastName',
+    'locked',
+    'enabled',
+    'expired',
+    'authorities',
+    'openIdUrl',
+    'email'
+  ];
+
+  function getUsers() {
+    var rawUsers = api.db.query('users');
+    var filteredUsers = [];
+
+    _.each(rawUsers, function(rawUser) {
+      filteredUsers.push(_.pick(rawUser, userKeys));
+    });
+
+    return filteredUsers;
+  }
+
+  function processRequest(method, url, data, headers) {
+    if (method !== 'GET') {
+      return [405, 'Unknown request'];
+    } else if (!this.requestHasToken) {
+      return [401, 'A valid token is required'];
+    } else if (!this.userIsAuthenticated) {
+      return [401, 'Invalid token'];
+    }
+
+    return [200, getUsers()];
+  }
+
+  api.register('/users', 'get', processRequest);
+
+} );

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/index.html
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/index.html b/rave-portal-ng/src/index.html
index 5c415c1..cf21a69 100644
--- a/rave-portal-ng/src/index.html
+++ b/rave-portal-ng/src/index.html
@@ -40,15 +40,6 @@
   <!-- The server will send this back with the initial page load -->
   <script>
     window._initialData = {
-      authorized: true,
-      user: {
-        name: "Jmeas",
-        id: 34,
-        authLevel: "admin"
-      },
-      preferences: {
-        pageSize: 10
-      },
       nav: [
         {
           state: 'portal.home',
@@ -90,13 +81,4 @@
 
   <!-- Use grunt-preprocess in the future for dev and prod builds -->
   <script data-main='config/startup', src='requirejs/require.js'></script>
-
-  <!-- API modules -->
-  <!-- 
-  <script src="core.js"></script>
-  <script src="pages/pages.js"></script>
-  <script src="login/login.js"></script>
-  <script src="status/status.js"></script>
-  <script src="bootstrap.js"></script>
-  -->
 </body>

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/index.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/index.js b/rave-portal-ng/src/index.js
index e6e2d44..7246017 100644
--- a/rave-portal-ng/src/index.js
+++ b/rave-portal-ng/src/index.js
@@ -16,6 +16,8 @@ define(function(require) {
 
   // Load the mock API (development only)
   require('./api/bootstrap');
+  // Load the mock bootstrap response (development only)
+  require('./api/bootstrap-data');
   
   // Our things
   require('./providers/filters/index');

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/rave.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/rave.js b/rave-portal-ng/src/rave.js
index f049a3d..e78d00c 100644
--- a/rave-portal-ng/src/rave.js
+++ b/rave-portal-ng/src/rave.js
@@ -42,15 +42,16 @@ define(function(require) {
   rave.controller('appData', [
     '$scope', '$state', '$stateParams',
     function($scope, $state, $stateParams) {
-    $scope.user = window._initialData.user;
-    $scope.nav = window._initialData.nav;
-    $scope.loginNav = window._initialData.loginNav;
+      $scope.nav = window._initialData.nav;
+      $scope.loginNav = window._initialData.loginNav;
 
-    // The ui-router doesn't do everything, unfortunately. So we need to
-    // store our state data so we can make new directives for it.
-    $scope.$state = $state;
-    $scope.$stateParams = $stateParams;
-  }]);
+      $scope.preferences = window.initialData.preferences;
+
+      // The ui-router doesn't do everything, unfortunately. So we need to
+      // store our state data so we can make new directives for it.
+      $scope.$state = $state;
+      $scope.$stateParams = $stateParams;
+    }]);
 
   // Routes
   var routes = require('./routes');

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/preferences/templates/preferences.html
----------------------------------------------------------------------
diff --git 
a/rave-portal-ng/src/subapps/admin/preferences/templates/preferences.html 
b/rave-portal-ng/src/subapps/admin/preferences/templates/preferences.html
index cf81711..749ad1d 100644
--- a/rave-portal-ng/src/subapps/admin/preferences/templates/preferences.html
+++ b/rave-portal-ng/src/subapps/admin/preferences/templates/preferences.html
@@ -61,7 +61,7 @@
       </div>
     </div>
     <fieldset>
-      <button class="btn btn-primary" ng-click="onSubmit()">Update 
preferences</button>
+      <button class="btn" ng-click="onSubmit()">Update preferences</button>
     </fieldset>
   </form>
 </article>

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/controllers/user.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/controllers/user.js 
b/rave-portal-ng/src/subapps/admin/users/controllers/user.js
new file mode 100644
index 0000000..1d5ba83
--- /dev/null
+++ b/rave-portal-ng/src/subapps/admin/users/controllers/user.js
@@ -0,0 +1,90 @@
+/*
+ * user
+ * Handles submission of our form
+ *
+ */
+
+var $ = require('jquery');
+
+define(function(require) {
+  return ['$scope', 'userResource', '$state', '$stateParams', 'user',
+  function($scope, userResource, $state, $stateParams, user) {
+
+    $scope.user = user;
+
+    // The values to merge onto this scope once the promise resolves
+    var keys = [
+      'email',
+      'openIdUrl',
+      'enabled',
+      'expired',
+      'locked',
+      'authorities'
+    ];
+
+    user.$promise.then(function(res) {
+      _.extend($scope, _.pick(res, keys));
+
+      $scope.roleUser = _.contains($scope.authorities, 'ROLE_USER');
+      $scope.roleAdmin = _.contains($scope.authorities, 'ROLE_ADMIN');
+
+      $scope.isCurrentUser = $scope.user.ID === $scope.currentUser.ID;
+    }).catch(function(err) {
+    });
+
+    // Remove the user from the list of user in the scope
+    this.removeFromList = function() {
+      var oldUser = _.findWhere($scope.user, {ID:+$stateParams.id});
+      var oldIndex = _.indexOf($scope.user, oldUser);
+      $scope.users.splice(oldIndex, 1);
+    };
+
+    // Replace the old item in the list with the new
+    this.updateList = function(newResource) {
+      var oldUser = _.findWhere($scope.users, {ID:+$stateParams.id});
+      var oldIndex = _.indexOf($scope.users, oldUser);
+      $scope.users[oldIndex] = newResource;
+      $scope.user = newResource;
+    };
+
+    var ctrl = this;
+
+    var getAuthorities = function() {
+      var authorities = [];
+      if ($scope.roleUser) {
+        authorities.push('ROLE_USER');
+      }
+      if ($scope.roleAdmin) {
+        authorities.push('ROLE_ADMIN');
+      }
+      return authorities;
+    };
+
+    $scope.onSave = function() {
+      var data = _.pick($scope, keys);
+      data.authorities = getAuthorities();
+      data.id = $stateParams.id;
+      var savedResource = userResource.update(data);
+      
+      savedResource.$promise
+        .then(ctrl.updateList)
+        .catch(function(err) {
+        });
+    };
+
+    $scope.onDelete = function() {
+      var deletedResource = userResource.delete({
+        id: $stateParams.id
+      });
+
+      deletedResource.$promise
+        .then(function() {
+          ctrl.removeFromList();
+          $('#confirm-modal').modal('hide');
+          $state.transitionTo('portal.admin.users', {page:1});
+        })
+        .catch(function() {
+        });
+    };
+  }];
+});

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/controllers/users.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/controllers/users.js 
b/rave-portal-ng/src/subapps/admin/users/controllers/users.js
index e035516..7e7b0aa 100644
--- a/rave-portal-ng/src/subapps/admin/users/controllers/users.js
+++ b/rave-portal-ng/src/subapps/admin/users/controllers/users.js
@@ -5,17 +5,15 @@
  */
 
 define(function(require) {
-  return ['$scope', '$stateParams', 'pagination',
-  function($scope, $stateParams, pagination) {
+  return ['$scope', '$stateParams', 'pagination', 'usersList',
+  function($scope, $stateParams, pagination, usersList) {
 
     $scope.currentPage = +$stateParams.page || 0;
 
     // How many items to show per page
     $scope.itemsPerPage = 10;
 
-    // Some fake users for us to display.
-    $scope.users = [];
-    $scope.users.push({},{},{},{},{},{},{},{},{},{},{});
+    $scope.users = usersList;
 
     // Our total number of users.
     $scope.totalUsers = 1000;

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/resources/user.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/resources/user.js 
b/rave-portal-ng/src/subapps/admin/users/resources/user.js
new file mode 100644
index 0000000..074b587
--- /dev/null
+++ b/rave-portal-ng/src/subapps/admin/users/resources/user.js
@@ -0,0 +1,34 @@
+/*
+ * userResource
+ * A resource for a single user
+ *
+ */
+
+define(function(require) {
+
+  // The API endpoint for categories
+  var URL = '/api/v1/user/:id';
+
+  // Return the categories resource
+  return ['$resource', 'authToken',
+  function($resource, authToken) {
+    var authHeader = {
+      Authorization: 'Basic ' + authToken.get()
+    };
+
+    return $resource(URL, {id: '@id'}, {
+      get: {
+        method: 'GET',
+        headers: authHeader
+      },
+      update: {
+        method: 'PUT',
+        headers: authHeader
+      },
+      delete: {
+        method: 'DELETE',
+        headers: authHeader
+      }
+    });
+  }];
+});

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/resources/users.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/resources/users.js 
b/rave-portal-ng/src/subapps/admin/users/resources/users.js
new file mode 100644
index 0000000..cafd29d
--- /dev/null
+++ b/rave-portal-ng/src/subapps/admin/users/resources/users.js
@@ -0,0 +1,35 @@
+/*
+ * usersResource
+ * The resource for the users list
+ *
+ */
+
+define(function(require) {
+
+  // The API endpoint for categories
+  var URL = '/api/v1/users';
+
+  // Return the categories resource
+  return ['$resource', 'authToken',
+  function($resource, authToken) {
+
+    var authHeader = {};
+
+    // We return a factory method from this due to logging in and out
+    // requiring a dynamic header
+    return function() {
+
+      // Dynamically set the authorization header, based on our current 
authToken
+      authHeader.Authorization = 'Basic ' + authToken.get();
+
+      // Return the resource.
+      return $resource(URL, {}, {
+        query: {
+          method: 'GET',
+          isArray: true,
+          headers: authHeader
+        }
+      });
+    };
+  }];
+});

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/routes.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/routes.js 
b/rave-portal-ng/src/subapps/admin/users/routes.js
index b0816a7..b658575 100644
--- a/rave-portal-ng/src/subapps/admin/users/routes.js
+++ b/rave-portal-ng/src/subapps/admin/users/routes.js
@@ -8,6 +8,7 @@
 
 define(function(require) {
   var usersCtrl = require('./controllers/users');
+  var userCtrl = require('./controllers/user');
 
   return ['$stateProvider', '$urlRouterProvider',
     function($stateProvider, $urlRouterProvider) {
@@ -18,14 +19,27 @@ define(function(require) {
           url: '/users?page',
           templateUrl: '/subapps/admin/users/templates/users.html',
           authenticate: true,
-          controller: usersCtrl
+          controller: usersCtrl,
+          resolve: {
+            usersList: ['usersResource',
+              function(usersResource) {
+                return usersResource().query();
+              }]
+          }
         })
 
         // Show a particular user's profile
         .state('portal.admin.users.detail', {
           url: '/users/detail-:id',
-          templateUrl: '/subapps/admin/users/templates/detail.html',
-          authenticate: true
+          templateUrl: '/subapps/admin/users/templates/user.html',
+          authenticate: true,
+          controller: userCtrl,
+          resolve: {
+            user: ['userResource', '$stateParams',
+              function(userResource, $stateParams) {
+                return userResource.get({id: $stateParams.id});
+              }]
+          }
         });
     }
   ];

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/templates/detail.html
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/templates/detail.html 
b/rave-portal-ng/src/subapps/admin/users/templates/detail.html
deleted file mode 100644
index 847d84e..0000000
--- a/rave-portal-ng/src/subapps/admin/users/templates/detail.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<a ui-sref="portal.admin.users">
-  « Back to users
-</a>
-<h2>canonical</h2>
-<div>
-  <section>
-    <form id="updateUserProfile" class="form-horizontal" action="update" 
method="POST">
-      <fieldset>
-        <legend>Edit user data</legend>
-        <br>
-        <input id="username" name="username" type="hidden" value="canonical">
-        <div class="control-group">
-          <label class="control-label" for="email">Email address:</label>
-          <div class="controls">
-            <input type="email" name="email" id="email" 
value="[email protected]" class="long">
-          </div>
-        </div>
-        <div class="control-group">
-          <label class="control-label" for="openIdField">OpenID URL:</label>
-          <div class="controls">
-            <input type="url" id="openIdField" name="openId" value="" 
class="long">
-          </div>
-        </div>
-        <div class="control-group">
-          <span class="control-label">Account status:</span>
-          <ul class="checkboxlist">
-            <li>
-              <input id="enabled1" name="enabled" disabled="disabled" 
type="checkbox" value="true" checked="checked">
-              <label for="enabled1">Account enabled</label>
-            </li>
-            <li>
-              <input id="expired1" name="expired" disabled="disabled" 
type="checkbox" value="true">
-              <label for="expired1">Account expired</label>
-            </li>
-            <li>
-              <input id="locked1" name="locked" disabled="disabled" 
type="checkbox" value="true">
-              <label for="locked1">Account locked</label>
-            </li>
-          </ul>
-        </div>
-      </fieldset>
-      <fieldset>
-        <span class="control-label">Authorities:</span>
-        <ul class="checkboxlist">
-          <li>
-            <input id="authorities1" name="authorities" type="checkbox" 
value="ROLE_USER">
-            <label for="authorities1">ROLE_USER</label>
-          </li>
-          <li>
-            <input id="authorities2" name="authorities" type="checkbox" 
value="ROLE_ADMIN" checked="checked">
-            <label for="authorities2">ROLE_ADMIN</label>
-          </li>
-        </ul>
-      </fieldset>
-      <fieldset>
-        <button class="btn btn-primary" type="submit" value="Update 
profile">Update profile</button>
-      </fieldset>
-    </form>
-  </section>
-</div>
-<div class="clear-float"></div>

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/templates/user.html
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/templates/user.html 
b/rave-portal-ng/src/subapps/admin/users/templates/user.html
new file mode 100644
index 0000000..e20adc5
--- /dev/null
+++ b/rave-portal-ng/src/subapps/admin/users/templates/user.html
@@ -0,0 +1,76 @@
+<a ui-sref="portal.admin.users">
+  « Back to users
+</a>
+<h2>{{ user.username }}</h2>
+<div class="alert alert-info" ng-show="isCurrentUser">
+  This user is you! Note that Administrators are unable to change their 
account status nor delete their account through the admin interface.
+</div>
+<div>
+  <section>
+    <form id="updateUserProfile" class="form-horizontal">
+      <fieldset>
+        <legend>Edit user data</legend>
+        <br>
+        <input id="username" name="username" type="hidden" value="canonical">
+        <div class="control-group">
+          <label class="control-label" for="email">Email address:</label>
+          <div class="controls">
+            <input type="email" name="email" id="email" class="long" 
ng-model="email">
+          </div>
+        </div>
+        <div class="control-group">
+          <label class="control-label" for="openIdField">OpenID URL:</label>
+          <div class="controls">
+            <input type="url" id="openIdField" name="openId" class="long" 
ng-model="openIdUrl">
+          </div>
+        </div>
+        <div class="control-group">
+          <span class="control-label">Account status:</span>
+          <ul class="checkboxlist">
+            <li>
+              <input id="enabled" name="enabled" type="checkbox" value="true" 
ng-model="enabled" ng-disabled="isCurrentUser">
+              <label for="enabled">Account enabled</label>
+            </li>
+            <li>
+              <input id="expired" name="expired" type="checkbox" value="true" 
ng-model="expired" ng-disabled="isCurrentUser">
+              <label for="expired">Account expired</label>
+            </li>
+            <li>
+              <input id="locked" name="locked" type="checkbox" value="true" 
ng-model="locked" ng-disabled="isCurrentUser">
+              <label for="locked">Account locked</label>
+            </li>
+          </ul>
+        </div>
+      </fieldset>
+      <fieldset>
+        <span class="control-label">Authorities:</span>
+        <ul class="checkboxlist">
+          <li>
+            <input id="role-user" name="role-user" type="checkbox" 
value="ROLE_USER" ng-model="roleUser">
+            <label for="role-user">ROLE_USER</label>
+          </li>
+          <li>
+            <input id="role-admin" name="role-admin" type="checkbox" 
value="ROLE_ADMIN" ng-model="roleAdmin">
+            <label for="role-admin">ROLE_ADMIN</label>
+          </li>
+        </ul>
+      </fieldset>
+      <fieldset>
+        <button class="btn" ng-click="onSave()">Update profile</button>
+        <button class="btn btn-danger" data-toggle="modal" 
data-target="#confirm-modal" ng-disabled="isCurrentUser">Delete User</button>
+      </fieldset>
+      <div id="confirm-modal" class="modal hide" tabindex="-1" role="dialog" 
aria-labelledby="myModalLabel" aria-hidden="true">
+        <div class="modal-body">
+          <div class="alert alert-danger">
+            Are you sure? This cannot be undone.
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="btn" data-dismiss="modal" 
aria-hidden="true">Cancel</button>
+          <button class="btn btn-danger" ng-click="onDelete()">Delete 
User</button>
+        </div>
+      </div>
+    </form>
+  </section>
+</div>
+<div class="clear-float"></div>

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/templates/users.html
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/templates/users.html 
b/rave-portal-ng/src/subapps/admin/users/templates/users.html
index 97c1898..9628338 100644
--- a/rave-portal-ng/src/subapps/admin/users/templates/users.html
+++ b/rave-portal-ng/src/subapps/admin/users/templates/users.html
@@ -36,12 +36,12 @@
     <tbody>
       <tr ng-repeat="user in users">
         <td>
-          <a ui-sref="portal.admin.users.detail">
-            Username
+          <a ui-sref="portal.admin.users.detail({id: user.ID, page: null})">
+            {{ user.username }}
           </a>
         </td>
-        <td>OpenSocial</td>
-        <td>published</td>
+        <td>{{ user.email }}</td>
+        <td>{{ user.enabled }}</td>
       </tr>
     </tbody>
   </table>

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/admin/users/users.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/admin/users/users.js 
b/rave-portal-ng/src/subapps/admin/users/users.js
index 779d6f1..47936fc 100644
--- a/rave-portal-ng/src/subapps/admin/users/users.js
+++ b/rave-portal-ng/src/subapps/admin/users/users.js
@@ -19,9 +19,18 @@ define(function(require) {
   var users = ng.module('admin.users', usersDependencies);
 
   // Register our providers for the users
+  var usersResource = require('./resources/users');
+  users.factory('usersResource', usersResource);
+
+  var userResource = require('./resources/user');
+  users.factory('userResource', userResource);
+  
   var usersCtrl = require('./controllers/users');
   users.controller('usersCtrl', usersCtrl);
 
+  var userCtrl = require('./controllers/user');
+  users.controller('userCtrl', userCtrl);
+
   // Register the routes
   var routes = require('./routes');
   users.config(routes);

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/auth/security/services/security.js
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/auth/security/services/security.js 
b/rave-portal-ng/src/subapps/auth/security/services/security.js
index 4ee0591..29ca642 100644
--- a/rave-portal-ng/src/subapps/auth/security/services/security.js
+++ b/rave-portal-ng/src/subapps/auth/security/services/security.js
@@ -42,6 +42,7 @@ define(function(require) {
           else {
             authApi.verify(myToken)
               .then(function(res) {
+                $rootScope.currentUser = res.data.user;
                 $rootScope.authenticated = true;
                 authCache.put('verified', true);
                 response.resolve(true);
@@ -67,8 +68,9 @@ define(function(require) {
             .then(function(res) {
               var user = res.data.user;
               $rootScope.authenticated = true;
+              $rootScope.currentUser = user;
               authCache.put('verified', true);
-              authToken.set(user.token, credentials.remember);
+              authToken.set(res.data.token, credentials.remember);
 
               var toState = locationCache.get('toState') || 'portal.home';
               var toParams = locationCache.get('toParams') || undefined;

http://git-wip-us.apache.org/repos/asf/rave/blob/22917b44/rave-portal-ng/src/subapps/home/templates/home.html
----------------------------------------------------------------------
diff --git a/rave-portal-ng/src/subapps/home/templates/home.html 
b/rave-portal-ng/src/subapps/home/templates/home.html
index 714e9f3..df5407d 100644
--- a/rave-portal-ng/src/subapps/home/templates/home.html
+++ b/rave-portal-ng/src/subapps/home/templates/home.html
@@ -1,2 +1,2 @@
-<h1 class="home">Welcome {{ user.name }}</h1>
+<h1 class="home">Welcome {{ currentUser.username }}</h1>
 <hr>

Reply via email to