Add local user manual unlock

Enables manual unlock from the GUI when a user is locked out
due to failed login attempts above allowed threshold.

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: I63e28a4d6feed9eb6d4d09c0431d31e7bd6924c2
diff --git a/app/users/controllers/user-accounts-controller.js b/app/users/controllers/user-accounts-controller.js
index 11ba13d..3d63d69 100644
--- a/app/users/controllers/user-accounts-controller.js
+++ b/app/users/controllers/user-accounts-controller.js
@@ -34,6 +34,18 @@
       }
 
       /**
+       * Returns lockout method based on the lockout duration property
+       * If the lockoutDuration is greater than 0 the lockout method
+       * is automatic otherwise the lockout method is manual
+       * @param {number} lockoutDuration
+       * @returns {number} : returns the account lockout method
+       *                     1(automatic) / 0(manual)
+       */
+      function mapLockoutMethod(lockoutDuration) {
+        return lockoutDuration > 0 ? 1 : 0;
+      }
+
+      /**
        * API call to get all user accounts
        */
       function getLocalUsers() {
@@ -103,9 +115,12 @@
       /**
        * API call to update existing user
        */
-      function updateUser(originalUsername, username, password, role, enabled) {
+      function updateUser(
+          originalUsername, username, password, role, enabled, locked) {
         $scope.loading = true;
-        APIUtils.updateUser(originalUsername, username, password, role, enabled)
+        APIUtils
+            .updateUser(
+                originalUsername, username, password, role, enabled, locked)
             .then(() => {
               getLocalUsers();
               toastService.success('User has been updated successfully.')
@@ -176,11 +191,9 @@
               ariaLabelledBy: 'dialog_label',
               controllerAs: 'modalCtrl',
               controller: function() {
-                // If AccountLockoutDuration is not 0 the lockout
-                // method is automatic. If AccountLockoutDuration is 0 the
-                // lockout method is manual
-                const lockoutMethod =
-                    $scope.accountSettings.AccountLockoutDuration ? 1 : 0;
+                const lockoutMethod = mapLockoutMethod(
+                    $scope.accountSettings.AccountLockoutDuration);
+
                 this.settings = {};
                 this.settings.maxLogin =
                     $scope.accountSettings.AccountLockoutThreshold;
@@ -252,7 +265,11 @@
                 this.user.accountStatus = status;
                 this.user.username = newUser ? '' : user.UserName;
                 this.user.privilege = newUser ? '' : user.RoleId;
+                this.user.locked = newUser ? null : user.Locked;
 
+                this.manualUnlockProperty = false;
+                this.automaticLockout = mapLockoutMethod(
+                    $scope.accountSettings.AccountLockoutDuration);
                 this.privilegeRoles = $scope.userRoles;
                 this.existingUsernames = existingUsernames;
                 this.minPasswordLength = $scope.accountSettings ?
@@ -281,10 +298,14 @@
                                  form.accountStatus1.$pristine) ?
                     null :
                     form.accountStatus.$modelValue;
+                const locked = (form.lock && form.lock.$dirty) ?
+                    form.lock.$modelValue :
+                    null;
 
                 if (!newUser) {
                   updateUser(
-                      originalUsername, username, password, role, enabled);
+                      originalUsername, username, password, role, enabled,
+                      locked);
                 } else {
                   createUser(
                       username, password, role, form.accountStatus.$modelValue);
diff --git a/app/users/controllers/user-accounts-modal-user.html b/app/users/controllers/user-accounts-modal-user.html
index 7b380be..4e646b1 100644
--- a/app/users/controllers/user-accounts-modal-user.html
+++ b/app/users/controllers/user-accounts-modal-user.html
@@ -9,6 +9,29 @@
   </div>
   <form name="form">
     <div class="modal-body">
+      <!-- Manual unlock -->
+      <div class="row" ng-if="modalCtrl.user.locked && !modalCtrl.automaticLockout">
+        <div class="column medium-9">
+          <div class="notification-banner"
+               aria-live="polite"
+               ng-class="{'notification-banner--warning': !form.lock.$dirty,
+                          'notification-banner--information': form.lock.$dirty}">
+            <p class="notification-banner__text" ng-if="!form.lock.$dirty">Account locked</p>
+            <p class="notification-banner__text" ng-if="form.lock.$dirty">Click "Save" to unlock account</p>
+          </div>
+        </div>
+        <div class="column medium-3">
+          <input
+            type="hidden"
+            name="lock"
+            ng-model="modalCtrl.manualUnlockProperty"
+            value="false">
+          <button class="btn btn-primary"
+                  type="button"
+                  ng-click="form.lock.$setDirty()"
+                  ng-disabled="form.lock.$dirty">Unlock</button>
+        </div>
+      </div>
       <div class="row">
         <div class="column medium-6">
             <!-- Account Status -->