workstations continued
authorBill Erickson <berick@esilibrary.com>
Wed, 30 Apr 2014 21:06:23 +0000 (17:06 -0400)
committerBill Erickson <berick@esilibrary.com>
Wed, 30 Apr 2014 21:06:23 +0000 (17:06 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/admin/workstation/t_splash.tt2
Open-ILS/src/templates/staff/t_login.tt2
Open-ILS/web/js/ui/default/staff/admin/workstation/app.js
Open-ILS/web/js/ui/default/staff/app.js
Open-ILS/web/js/ui/default/staff/navbar.js
Open-ILS/web/js/ui/default/staff/services/auth.js
Open-ILS/web/js/ui/default/staff/services/env.js
Open-ILS/web/js/ui/default/staff/services/org.js
Open-ILS/web/js/ui/default/staff/services/startup.js
Open-ILS/web/js/ui/default/staff/services/ui.js

index 0c26f02..40287c5 100644 (file)
@@ -6,7 +6,7 @@
   #admin-workstation-container .new-entry {
     margin-top: 10px;
     padding-top: 10px;
-    border-top: 1px solid #F5F5F5;
+    border-top: 2px solid #F5F5F5;
   }
 </style>
 
 
   <div class="row">
     <div class="col-md-6">
-      [% l('Registered Workstations') %]
+      <div class="checkbox">
+        <label>
+          <input type="checkbox" ng-class="{disabled : !userHasAdminPerm}"
+            ng-model="hatchRequired" ng-change="updateHatchRequired()">
+[% l('This workstation uses a remote print / storage service ("Hatch")?') %]
+        </label>
+      </div>
+    </div><!-- row -->
+  </div>
+  <div class="row">
+    <div class="col-md-6">
+      <input type='text' class='form-control'  
+        ng-disabled="!hatchRequired || !userHasRegPerm"
+        title="[% l('Hatch URL') %]"
+        placeholder="[% l('Hatch URL') %]"
+        ng-change='updateHatchURL()' ng-model='hatchURL'/>
+    </div>
+  </div>
+
+  <div class="row new-entry">
+    <div class="col-md-6">
+      [% l('Workstations Registered With This Computer') %]
     </div>
   </div>
   <div class="row">
     <div class="col-md-6">
-      <div class="input-group">
-        <select class="form-control" ng-model="selectedWS">
-          <option ng-repeat="ws in workstations" value="{{ws.id}}"
-            ng-selected="ws.id == defaultWS.id">
-            {{getWSLabel(ws)}}
-          </option>
-        </select>
-        <div class="input-group-btn">
-          <button class="btn btn-default">
-            [% l('Login') %]
-          </button>
-        </div>
-        <div class="input-group-btn">
-          <button class="btn btn-default" ng-click="setDefaultWS()">
-            [% l('Set as Default') %]
-          </button>
-        </div>
-        <div class="input-group-btn">
-          <button class="btn btn-default btn-warning">
-            [% l('Delete') %]
-          </button>
-        </div>
-      </div>
+      <select class="form-control" ng-model="selectedWS">
+        <option ng-repeat="ws in workstations" value="{{ws}}"
+          ng-selected="ws == selectedWS">
+          {{getWSLabel(ws)}}
+        </option>
+      </select>
+    </div>
+  </div>
+
+  <div class="row">
+    <div class="col-md-6">
+      <button class="btn btn-default" ng-click="useWS()">
+        [% l('Use Now') %]
+      </button>
+      <button class="btn btn-default" ng-click="setDefaultWS()">
+        [% l('Mark As Default') %]
+      </button>
+      <button class="btn btn-default btn-danger disabled">
+        [% l('Delete') %]
+      </button>
     </div>
   </div>
 
   <div class="row new-entry">
     <div class="col-md-6">
-      [% l('Register a New Workstation') %]
+      [% l('Register a New Workstation For This Computer') %]
     </div>
   </div>
   <div class="row">
@@ -56,7 +74,7 @@
         <div class="input-group-btn">
           <eg-org-selector 
             selected="contextOrg"
-            org-changed="wsOrgChanged">
+            hidden-test="wsOrgHidden">
           </eg-org-selector>
         </div>
         <input type='text' class='form-control'  
     </div>
   </div>
 
-
-  <div class="row new-entry">
-    <div class="col-md-6">
-      <div class="checkbox">
-        <label>
-          <input type="checkbox" ng-class="{disabled : !userHasAdminPerm}"
-            ng-model="hatchRequired" ng-change="updateHatchRequired()">
-[% l('This workstation uses a remote print / storage service ("Hatch")?') %]
-        </label>
-      </div>
-    </div><!-- row -->
-  </div>
-  <div class="row">
-    <div class="col-md-6">
-      <input type='text' class='form-control'  
-        ng-disabled="!hatchRequired || !userHasAdminPerm"
-        title="[% l('Hatch URL') %]"
-        placeholder="[% l('Hatch URL') %]"
-        ng-change='updateHatchURL()' ng-model='hatchURL'/>
-    </div>
-  </div>
-
   <div class="row new-entry">
     <div class="col-md-6">
       <span class="glyphicon glyphicon-print"></span>
index 0bddfab..bf49669 100644 (file)
@@ -11,8 +11,8 @@
             The input IDs are there to match the labels.  
             They are not referenced in the Login controller.
           -->
-          <form ng-submit="login(args)" name="login-form">
-            <div class="form-group row">
+          <form ng-submit="login(args)" name="login-form" class="form-horizontal" role="form">
+            <div class="form-group">
               <label class="col-md-4 control-label" for="login-username">[% l('Username') %]</label>
               <div class="col-md-8">
                 <input type="text" id="login-username" class="form-control" 
@@ -21,7 +21,7 @@
               </div>
             </div>
 
-            <div class="form-group row">
+            <div class="form-group">
               <label class="col-md-4 control-label" for="login-password">[% l('Password') %]</label>
               <div class="col-md-8">
                 <input type="password" id="login-password" class="form-control"
               </div>
             </div>
 
-            <div class="form-group row">
-              <label class="col-md-4 control-label" for="login-workstation">[% l('Workstation') %]</label>
+            <div class="form-group">
+              <label class="col-md-4 control-label" 
+                for="login-workstation">[% l('Workstation') %]</label>
               <div class="col-md-8">
-                <select ng-model="workstations" class="form-control">
+                <select class="form-control" ng-model="args.workstation"
+                  ng-options="ws for ws in workstations">
+                  <option>[% l('Select Workstation') %]</option>
                 </select>
-              <div>
+              </div>
             </div>
 
-            <div class="form-group row">
-              <div class="col-md-12">
-                <button type="submit" class="btn">[% l('Sign in') %]</button>
-                <span ng-show="loginFailed">[% l('Login Failed') %]</span>
+            <div class="form-group">
+              <div class="col-md-offset-4 col-md-4">
+                <button type="submit" class="btn btn-default">[% l('Sign in') %]</button>
+              </div>
+              <div class="col-md-4">
+                <span ng-show="loginFailed" class="label-warning">[% l('Login Failed') %]</span>
               </div>
             </div>
+
           </form>
         </fieldset>
       </div>
index 2793706..dd67797 100644 (file)
@@ -36,9 +36,10 @@ angular.module('egWorkstationAdmin',
 }])
 
 .controller('SplashCtrl',
-       ['$scope','egPrintStore','egAuth','egOrg','egPerm','egEvent','egNet','egAppStrings',
-function($scope , egPrintStore , egAuth , egOrg , egPerm , egEvent , egNet , egAppStrings) {
+       ['$scope','$window','$location','egPrintStore','egAuth','egOrg','egPerm','egEvent','egNet','egAppStrings',
+function($scope , $window , $location , egPrintStore , egAuth , egOrg , egPerm , egEvent , egNet , egAppStrings) {
 
+    var allWorkstations = [];
     var permMap = {};
     var wsPerms = [
         'ADMIN_WORKSTATION', //FIXME: create
@@ -47,41 +48,51 @@ function($scope , egPrintStore , egAuth , egOrg , egPerm , egEvent , egNet , egA
         'DELETE_WORKSTATION'
     ]
 
+    $scope.contextOrg = egOrg.get(egAuth.user().ws_ou());
+
     $scope.userHasAdminPerm = false;
-    egPerm.hasPermAt(wsPerms)
-    .then(function(permMap) { 
-        //$scope.userHasAdminPerm = bool 
+    egPerm.hasPermAt('REGISTER_WORKSTATION', true)
+    .then(function(orgList) { 
+
+        // hide orgs in the context org selector where this login
+        // does not have the reg_ws perm
+        $scope.wsOrgHidden = function(id) {
+            return orgList.indexOf(id) == -1;
+        }
+        $scope.userHasRegPerm = 
+            orgList.indexOf($scope.contextOrg.id()) > -1;
     });
 
     // fetch the stored WS info
     egPrintStore.getItem('eg.conf.workstation.all')
     .then(function(all) {
-        $scope.workstations = all || [];
+        allWorkstations = all || [];
+        $scope.workstations = 
+            allWorkstations.map(function(w) { return w.name });
         return egPrintStore.getItem('eg.conf.workstation.default');
     })
     .then(function(def) { 
-        console.log('loaded default WS ' + ws);
-        $scope.defaultWS = def 
+        $scope.defaultWS = def;
+        $scope.activeWS = $scope.selectedWS = egAuth.workstation() || def;
     });
 
-    if (ws = egAuth.workstation()) {
-        $scope.activeWS = ws;
-        $scope.contextOrg = egOrg.get(ws.owning_lib);
-    }
-
     $scope.getWSLabel = function(ws) {
-        return ws.name; // FIXME: appstrings
+        return ws; // FIXME: appstrings
     }
 
     $scope.setDefaultWS = function() {
-        console.log('selected ' + $scope.selectedWS);
-        var ws = $scope.workstations.filter(
-            function(w) { return w.id == $scope.selectedWS })[0];
         egPrintStore.setItem(
-            'eg.conf.workstation.default', 
-            // avoid storing angular $$hashkey
-            {id : ws.id, name : ws.name, owning_lib : ws.owning_lib})
-        .then(function() { $scope.defaultWS = ws });
+            'eg.conf.workstation.default', $scope.selectedWS)
+        .then(function() { $scope.defaultWS = $scope.selectedWS });
+    }
+
+    // redirect the user to the login page using the current
+    // workstation as the workstation URL param
+    $scope.useWS = function() {
+        $window.location.href = $location
+            .path('/login')
+            .search({ws : $scope.selectedWS})
+            .absUrl();
     }
 
     $scope.registerWS = function() {
@@ -94,20 +105,29 @@ function($scope , egPrintStore , egAuth , egOrg , egPerm , egEvent , egNet , egA
             var evt = egEvent.parse(resp);
             if (evt) {
                 if (evt.textcode == 'WORKSTATION_NAME_EXISTS') {
+                    console.log(evt);
                     // TODO: override call
                 } else {
                     // TODO: improvide permission error display
                     alert(evt);
                 }
             } else if (resp) {
-                $scope.workstations.push(
-                    {   id : resp,
-                        name : newName, 
-                        owning_lib : $scope.contextOrg.id()
+                $scope.workstations.push(newName);
+                allWorkstations.push({   
+                    id : resp,
+                    name : newName, 
+                    owning_lib : $scope.contextOrg.id()
+                });
+
+                egPrintStore.setItem(
+                    'eg.conf.workstation.all', allWorkstations)
+                .then(function() {
+                    if (allWorkstations.length == 1) {
+                        // first one registerd, also mark it as the default
+                        $scope.selectedWS = newName;
+                        $scope.setDefaultWS();
                     }
-                );
-                return egPrintStore.setItem(
-                    'eg.conf.workstation.all', $scope.workstations);
+                });
             }
         });
     }
index 0e50104..8a1aef1 100644 (file)
@@ -51,7 +51,6 @@ angular.module('egHome', ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod'])
 
         egPrintStore.getItem('eg.conf.workstation.all')
         .then(function(all) {
-                $scope.workstations = ['abc', 'dev', 'foo']; // TODO
             if (all && all.length) {
                 $scope.workstations = all.map(function(a) { return a.name });
 
@@ -69,9 +68,9 @@ angular.module('egHome', ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod'])
                     }
                 } else {
                     // no workstation requested; use the default
-                    egPrintStore.get('eg.conf.workstation.all.default')
+                    egPrintStore.getItem('eg.conf.workstation.default')
                     .then(function(ws) {
-                        $scope.args = {workstation : ws.name}
+                        $scope.args = {workstation : ws}
                     });
                 }
             } 
index f58cc47..12f63d2 100644 (file)
@@ -30,20 +30,16 @@ function NavCtrl($scope, $window, $location, egStartup, egAuth, egEnv) {
      * done inside a promise resolver, another $digest() loop will
      * run and pick up our changes.  No $scope.$apply() needed.
      */
-    egStartup.go().then(
-        function() {
-
-
-            // login page will not have a cached user
-            if (!egAuth.user()) return;
-
-            $scope.username = egAuth.user().usrname();
-
-            // TODO: move workstation into egAuth
-            if (ws = egAuth.workstation())
-                $scope.workstation = ws.name();
-        }
-    );
+    if ($location.path() != '/login') {
+        // avoiding rending user info on the login page
+
+        egStartup.go().then(
+            function() {
+                $scope.username = egAuth.user().usrname();
+                $scope.workstation = egAuth.workstation();
+            }
+        );
+    }
 }
 
 // minify-safe dependency injection
index 0cc6c1f..5b7b7cb 100644 (file)
@@ -12,11 +12,11 @@ angular.module('egCoreMod')
 .constant('EG_AUTH_COOKIE', 'ses')
 
 .factory('egAuth', 
-       ['$q','$cookies','egNet','EG_AUTH_COOKIE',
-function($q , $cookies , egNet , EG_AUTH_COOKIE) {
+       ['$q','$cookies','egNet','EG_AUTH_COOKIE','egPrintStore',
+function($q , $cookies , egNet , EG_AUTH_COOKIE , egPrintStore) {
 
     var service = {
-        // the currently active user object
+        // the currently active user (au) object
         user : function() {
             return this._user;
         },
@@ -26,10 +26,10 @@ function($q , $cookies , egNet , EG_AUTH_COOKIE) {
             return $cookies[EG_AUTH_COOKIE];
         },
 
-        // the currently active workstation
-        workstation : function(ws) {
-            if (ws) this._workstation = ws;
-            return this._workstation;
+        // the currently active workstation name
+        // For ws_ou or wsid(), see egAuth.user().ws_ou(), etc.
+        workstation : function() {
+            return this.ws;
         }
     };
 
@@ -40,21 +40,41 @@ function($q , $cookies , egNet , EG_AUTH_COOKIE) {
         var token = service.token();
 
         if (token) {
+
             egNet.request(
                 'open-ils.auth',
-                'open-ils.auth.session.retrieve', token).then(
-                function(user) {
-                    if (user && user.classname) {
-                        service._user = user;
-                        deferred.resolve();
+                'open-ils.auth.session.retrieve', token)
+
+            .then(function(user) {
+                if (user && user.classname) {
+                    // authtoken test succeeded
+                    service._user = user;
+                   
+                    if (user.wsid()) {
+                        // user previously logged in with a workstation. 
+                        // Find the workstation name from the list 
+                        // of configured workstations
+                        egPrintStore.getItem('eg.conf.workstation.all')
+                        .then(function(all) { 
+                            if (all) {
+                                var ws = all.filter(
+                                    function(w) {return w.id == user.wsid()})[0];
+                                if (ws) service.ws = ws.name;
+                            }
+                            deferred.resolve(); // found WS
+                        });
                     } else {
-                        delete $cookies[EG_AUTH_COOKIE]; 
-                        deferred.reject();
+                        deferred.resolve(); // no WS
                     }
+                } else {
+                    // authtoken test failed
+                    delete $cookies[EG_AUTH_COOKIE]; 
+                    deferred.reject(); 
                 }
-            );
+            });
 
         } else {
+            // no authtoken to test
             deferred.reject();
         }
 
@@ -77,6 +97,7 @@ function($q , $cookies , egNet , EG_AUTH_COOKIE) {
                     'open-ils.auth.authenticate.complete', args).then(
                     function(evt) {
                         if (evt.textcode == 'SUCCESS') {
+                            service.ws = args.workstation; 
                             $cookies[EG_AUTH_COOKIE] = evt.payload.authtoken;
                             deferred.resolve();
                         } else {
@@ -126,7 +147,7 @@ function($q , $cookies , egNet , egAuth , egOrg) {
      * hash of perm => orgList maps.  If a string, the response is the
      * org list for the requested perm.
      */
-    service.hasPermAt = function(permList) {
+    service.hasPermAt = function(permList, asId) {
         var deferred = $q.defer();
         var isArray = true;
         if (!angular.isArray(permList)) {
@@ -145,7 +166,7 @@ function($q , $cookies , egNet , egAuth , egOrg) {
             angular.forEach(permList, function(perm) {
                 var all = [];
                 angular.forEach(resp[perm], function(oneOrg) {
-                    all = all.concat(egOrg.descendants(oneOrg));
+                    all = all.concat(egOrg.descendants(oneOrg, asId));
                 });
                 answer[perm] = all;
             });
@@ -185,18 +206,13 @@ function($q , $cookies , egNet , egAuth , egOrg) {
 
         ws_ou = egAuth.user().ws_ou();
 
-        return service.hasPermAt(permList)
+        return service.hasPermAt(permList, true)
         .then(function(orgMap) {
-            angular.forEach(orgMap, function(orgs, perm) {
-                // each permission is mapped to a flat list of org units,
+            angular.forEach(orgMap, function(orgIds, perm) {
+                // each permission is mapped to a flat list of org unit ids,
                 // including descendants.  See if our workstation org unit
                 // is in the list.
-                angular.forEach(orgs, function(org) {
-                    if ((''+org.id()) == (''+ws_ou)) 
-                        response[perm] = true;
-                });
-                if (response[perm] !== true) 
-                    response[perm] = false;
+                response[perm] = orgIds.indexOf(ws_ou) > -1;
             });
             if (!isArray) response = response[permList[0]];
             return response;
index e24a6f1..9860477 100644 (file)
@@ -88,7 +88,7 @@ function($q,  egAuth,  egPCRUD,  egIDL) {
      * list of classes to load on every page, regardless of whether
      * a page-specific list is provided.
      */
-    service.loadClasses = ['aou', 'aws'];
+    service.loadClasses = ['aou'];
 
     /*
      * Default class loaders.  Only add classes directly to this file
@@ -103,19 +103,6 @@ function($q,  egAuth,  egPCRUD,  egIDL) {
                 function(tree) {service.absorbTree(tree, 'aou')}
             );
         },
-        aws : function() {
-            // FIXME: this will come from local storage, not the server
-            // load thee workstation for the authenticated user and
-            // insert the value into egAuth.workstation().
-            // TODO: auth.session.retrieve should be capable of returning
-            // the session with the workstation fleshed.
-            if (!egAuth.user().wsid()) { 
-                // nothing to fetch.  
-                return $q.when();
-            }
-            return egPCRUD.retrieve('aws', egAuth.user().wsid())
-            .then(function(ws) {egAuth.workstation(ws)});
-        }
     };
 
     return service;
index 438d112..b07c41b 100644 (file)
@@ -83,7 +83,6 @@ function($q,  egEnv,  egAuth,  egNet) {
         return deferred.promise;
     }
 
-
     return service;
 }]);
  
index 644598c..670248c 100644 (file)
@@ -46,14 +46,14 @@ function($q,  $rootScope,  $location,  $window,  egIDL,  egAuth,  egEnv) {
     $rootScope.$on('egAuthExpired', function() {service.expiredAuthHandler()});
 
     service.go = function () {
-        if (this.promise) {
+        if (service.promise) {
             // startup already started, return our existing promise
-            return this.promise;
+            return service.promise;
         } 
 
         // create a new promise and fire off startup
         var deferred = $q.defer();
-        this.promise = deferred.promise;
+        service.promise = deferred.promise;
 
         // IDL parsing is sync.  No promises required
         egIDL.parseIDL();
@@ -76,7 +76,7 @@ function($q,  $rootScope,  $location,  $window,  egIDL,  egAuth,  egEnv) {
             }
         );
 
-        return this.promise;
+        return service.promise;
     }
     
     return service;
index 44a466e..0e7e3c4 100644 (file)
@@ -143,7 +143,11 @@ function($timeout, $parse) {
         transclude : true,
         scope : {
             selected : '=', // defaults to workstation or root org
-            orgChanged : '=' // called when selected org changes
+            
+            // Each org unit is passed into this function and, for
+            // any org units where the response value is true, the
+            // org unit will not be added to the selector.
+            hiddenTest : '=',
         },
 
         // any reason to move this into a TT2 template?
@@ -154,7 +158,7 @@ function($timeout, $parse) {
             + '<span class="caret"></span>'
           + '</button>'
           + '<ul class="dropdown-menu">'
-            + '<li ng-repeat="org in orgList">'
+            + '<li ng-repeat="org in orgList" ng-hide="hiddenTest(org.id)">'
               + '<a href="" ng-click="orgChanged(org)"'
                 + 'style="padding-left: {{org.depth * 10 + 5}}px">'
                 + '{{org.shortname}}'