Add password requirements to local user page

- Make api call to get user account settings
- Update add/edit user form to include dynamic password
  requirement values
- Fix edit username bug by adding input listener to field
  that sets form control to $dirty state and adds
  property to PATCH request

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: I3535f4214ee12c95d5e502134bf3e36597d2421a
diff --git a/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue b/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
index 8797da7..97b00e4 100644
--- a/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
+++ b/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
@@ -75,8 +75,12 @@
       </b-col>
     </b-row>
     <!-- Modals -->
-    <modal-settings :settings="settings"></modal-settings>
-    <modal-user :user="activeUser" @ok="saveUser"></modal-user>
+    <modal-settings :settings="settings" />
+    <modal-user
+      :user="activeUser"
+      :password-requirements="passwordRequirements"
+      @ok="saveUser"
+    />
   </b-container>
 </template>
 
@@ -116,7 +120,6 @@
   data() {
     return {
       activeUser: null,
-      settings: null,
       fields: [
         {
           key: 'checkbox',
@@ -174,15 +177,25 @@
           ...user
         };
       });
+    },
+    settings() {
+      return this.$store.getters['localUsers/accountSettings'];
+    },
+    passwordRequirements() {
+      return this.$store.getters['localUsers/accountPasswordRequirements'];
     }
   },
   created() {
     this.getUsers();
+    this.getAccountSettings();
   },
   methods: {
     getUsers() {
       this.$store.dispatch('localUsers/getUsers');
     },
+    getAccountSettings() {
+      this.$store.dispatch('localUsers/getAccountSettings');
+    },
     initModalUser(user) {
       this.activeUser = user;
       this.$bvModal.show('modal-user');
diff --git a/src/views/AccessControl/LocalUserManagement/ModalSettings.vue b/src/views/AccessControl/LocalUserManagement/ModalSettings.vue
index a0d6294..afe2d95 100644
--- a/src/views/AccessControl/LocalUserManagement/ModalSettings.vue
+++ b/src/views/AccessControl/LocalUserManagement/ModalSettings.vue
@@ -6,8 +6,8 @@
 export default {
   props: {
     settings: {
-      type: String,
-      default: ''
+      type: Object,
+      required: true
     }
   }
 };
diff --git a/src/views/AccessControl/LocalUserManagement/ModalUser.vue b/src/views/AccessControl/LocalUserManagement/ModalUser.vue
index 448276b..4a6a0bc 100644
--- a/src/views/AccessControl/LocalUserManagement/ModalUser.vue
+++ b/src/views/AccessControl/LocalUserManagement/ModalUser.vue
@@ -43,6 +43,7 @@
                 aria-describedby="username-help-block"
                 :state="getValidationState($v.form.username)"
                 :disabled="!newUser && originalUsername === 'root'"
+                @input="$v.form.username.$touch()"
               />
               <b-form-invalid-feedback role="alert">
                 <template v-if="!$v.form.username.required">
@@ -73,9 +74,13 @@
           </b-col>
           <b-col>
             <b-form-group label="User password" label-for="password">
-              <b-form-text id="password-help-block" text-variant="black">
-                <!-- TODO: Should be dynamic values -->
-                Password must between 8 – 20 characters
+              <b-form-text id="password-help-block">
+                Password must between
+                <span class="text-nowrap">
+                  {{ passwordRequirements.minLength }}
+                  – {{ passwordRequirements.maxLength }}
+                </span>
+                characters
               </b-form-text>
               <input-password-toggle>
                 <b-form-input
@@ -95,7 +100,12 @@
                       !$v.form.password.minLength || !$v.form.password.maxLength
                     "
                   >
-                    Length must be between 8 – 20 characters
+                    Length must be between
+                    <span class="text-nowrap">
+                      {{ passwordRequirements.minLength }}
+                      – {{ passwordRequirements.maxLength }}
+                    </span>
+                    characters
                   </template>
                 </b-form-invalid-feedback>
               </input-password-toggle>
@@ -158,6 +168,10 @@
     user: {
       type: Object,
       default: null
+    },
+    passwordRequirements: {
+      type: Object,
+      required: true
     }
   },
   data() {
@@ -187,33 +201,35 @@
       this.form.privilege = value.privilege;
     }
   },
-  validations: {
-    form: {
-      status: {
-        required
-      },
-      username: {
-        required,
-        maxLength: maxLength(16),
-        pattern: helpers.regex('pattern', /^([a-zA-Z_][a-zA-Z0-9_]*)/)
-      },
-      privilege: {
-        required
-      },
-      password: {
-        required: requiredIf(function() {
-          return this.requirePassword();
-        }),
-        minLength: minLength(8), //TODO: Update to dynamic backend values
-        maxLength: maxLength(20) //TODO: UPdate to dynamic backend values
-      },
-      passwordConfirmation: {
-        required: requiredIf(function() {
-          return this.requirePassword();
-        }),
-        sameAsPassword: sameAs('password')
+  validations() {
+    return {
+      form: {
+        status: {
+          required
+        },
+        username: {
+          required,
+          maxLength: maxLength(16),
+          pattern: helpers.regex('pattern', /^([a-zA-Z_][a-zA-Z0-9_]*)/)
+        },
+        privilege: {
+          required
+        },
+        password: {
+          required: requiredIf(function() {
+            return this.requirePassword();
+          }),
+          minLength: minLength(this.passwordRequirements.minLength),
+          maxLength: maxLength(this.passwordRequirements.maxLength)
+        },
+        passwordConfirmation: {
+          required: requiredIf(function() {
+            return this.requirePassword();
+          }),
+          sameAsPassword: sameAs('password')
+        }
       }
-    }
+    };
   },
   methods: {
     handleSubmit() {