summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYoshie Muranaka <yoshiemuranaka@gmail.com>2020-02-20 21:18:36 +0300
committerYoshie Muranaka <yoshiemuranaka@gmail.com>2020-02-25 01:53:37 +0300
commit1b1c1005905c0d5a0145377718ad773fe08d0863 (patch)
tree977960b251df84403364eee9337e33810c606a87 /src
parent52b0223005c91dc95f82ef0752ea2f3ae50788e6 (diff)
downloadwebui-vue-1b1c1005905c0d5a0145377718ad773fe08d0863.tar.xz
Add account settings to local user page
Adds ability to change account LockoutThreshold and LockoutDuration properties from the GUI. Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com> Change-Id: Ieeb75aa83c07b3de840bccdfc28e2d6e87512e2e
Diffstat (limited to 'src')
-rw-r--r--src/locales/en.json21
-rw-r--r--src/store/modules/AccessControl/LocalUserMangementStore.js27
-rw-r--r--src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue14
-rw-r--r--src/views/AccessControl/LocalUserManagement/ModalSettings.vue183
4 files changed, 234 insertions, 11 deletions
diff --git a/src/locales/en.json b/src/locales/en.json
index dd3d588b..f392f4e8 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1,7 +1,9 @@
{
"global": {
"formField": {
- "validator": "Field required"
+ "fieldRequired": "Field required",
+ "valueMustBeBetween": "Value must be between %{min} – %{max}",
+ "mustBeAtLeast": "Must be at least %{value}"
},
"on": "on",
"off": "off",
@@ -13,6 +15,7 @@
"confirm": "Confirm",
"cancel": "Cancel",
"delete": "Delete",
+ "save": "Save",
"selected": "Selected"
},
"response": {
@@ -49,11 +52,11 @@
},
"password": {
"label": "Password",
- "validator": "@:global.formField.validator"
+ "validator": "@:global.formField.fieldRequired"
},
"username": {
"label": "Username",
- "validator": "@:global.formField.validator"
+ "validator": "@:global.formField.fieldRequired"
}
},
"overview": {
@@ -103,6 +106,7 @@
}
},
"localUserManagement": {
+ "accountPolicySettings": "Account policy settings",
"tableActions": {
"delete": "@:global.actions.delete",
"enable": "Enable",
@@ -114,7 +118,16 @@
"successEnableUsers": "Successfully enabled %{count} user. | Successfully enabled %{count} users.",
"errorEnableUsers": "Error enabling %{count} user. | Error enabling %{count} users.",
"successDisableUsers": "Successfully disabled %{count} user. | Successfully disabled %{count} users.",
- "errorDisableUsers": "Error disabling %{count} user. | Error disabling %{count} users."
+ "errorDisableUsers": "Error disabling %{count} user. | Error disabling %{count} users.",
+ "successSaveSettings": "Successfully saved account settings.",
+ "errorSaveSettings": "Error saving account settings."
+ },
+ "modals": {
+ "manual": "Manual",
+ "automaticAfterTimeout": "Automatic after timeout",
+ "timeoutDurationSeconds": "Timeout duration (seconds)",
+ "maxFailedLoginAttempts": "Max failed login attempts",
+ "userUnlockMethod": "User unlock method"
}
}
} \ No newline at end of file
diff --git a/src/store/modules/AccessControl/LocalUserMangementStore.js b/src/store/modules/AccessControl/LocalUserMangementStore.js
index 67c3a1e4..7ad3ff50 100644
--- a/src/store/modules/AccessControl/LocalUserMangementStore.js
+++ b/src/store/modules/AccessControl/LocalUserMangementStore.js
@@ -257,6 +257,33 @@ const LocalUserManagementStore = {
return toastMessages;
})
);
+ },
+ async saveAccountSettings(
+ { dispatch },
+ { lockoutThreshold, lockoutDuration }
+ ) {
+ const data = {};
+ if (lockoutThreshold !== undefined) {
+ data.AccountLockoutThreshold = lockoutThreshold;
+ }
+ if (lockoutDuration !== undefined) {
+ data.AccountLockoutDuration = lockoutDuration;
+ }
+
+ return await api
+ .patch('/redfish/v1/AccountService', data)
+ //GET new settings to update view
+ .then(() => dispatch('getAccountSettings'))
+ .then(() =>
+ i18n.t('localUserManagement.toastMessages.successSaveSettings')
+ )
+ .catch(error => {
+ console.log(error);
+ const message = i18n.t(
+ 'localUserManagement.toastMessages.errorSaveSettings'
+ );
+ throw new Error(message);
+ });
}
}
};
diff --git a/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue b/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
index 97b00e49..ee2ec433 100644
--- a/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
+++ b/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
@@ -75,7 +75,7 @@
</b-col>
</b-row>
<!-- Modals -->
- <modal-settings :settings="settings" />
+ <modal-settings :settings="settings" @ok="saveAccountSettings" />
<modal-user
:user="activeUser"
:password-requirements="passwordRequirements"
@@ -216,11 +216,7 @@ export default {
});
},
initModalSettings() {
- if (this.settings) {
- this.$bvModal.show('modal-settings');
- } else {
- // fetch settings then show modal
- }
+ this.$bvModal.show('modal-settings');
},
saveUser({ isNewUser, userData }) {
if (isNewUser) {
@@ -288,6 +284,12 @@ export default {
default:
break;
}
+ },
+ saveAccountSettings(settings) {
+ this.$store
+ .dispatch('localUsers/saveAccountSettings', settings)
+ .then(message => this.successToast(message))
+ .catch(({ message }) => this.errorToast(message));
}
}
};
diff --git a/src/views/AccessControl/LocalUserManagement/ModalSettings.vue b/src/views/AccessControl/LocalUserManagement/ModalSettings.vue
index afe2d95e..2e41b292 100644
--- a/src/views/AccessControl/LocalUserManagement/ModalSettings.vue
+++ b/src/views/AccessControl/LocalUserManagement/ModalSettings.vue
@@ -1,14 +1,195 @@
<template>
- <b-modal id="modal-settings" title="Account policy settings"> </b-modal>
+ <b-modal
+ id="modal-settings"
+ ref="modal"
+ :title="$t('localUserManagement.accountPolicySettings')"
+ :ok-title="$t('global.actions.save')"
+ @ok="onOk"
+ @hidden="resetForm"
+ >
+ <b-form novalidate @submit="handleSubmit">
+ <b-container>
+ <b-row>
+ <b-col>
+ <b-form-group
+ :label="$t('localUserManagement.modals.maxFailedLoginAttempts')"
+ label-for="lockout-threshold"
+ >
+ <b-form-text id="lockout-threshold-help-block">
+ {{
+ $t('global.formField.valueMustBeBetween', {
+ min: 0,
+ max: 65535
+ })
+ }}
+ </b-form-text>
+ <b-form-input
+ id="lockout-threshold"
+ v-model.number="form.lockoutThreshold"
+ type="number"
+ aria-describedby="lockout-threshold-help-block"
+ :state="getValidationState($v.form.lockoutThreshold)"
+ @input="$v.form.lockoutThreshold.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <template v-if="!$v.form.lockoutThreshold.required">
+ {{ $t('global.formField.fieldRequired') }}
+ </template>
+ <template
+ v-if="
+ !$v.form.lockoutThreshold.minLength ||
+ !$v.form.lockoutThreshold.maxLength
+ "
+ >
+ {{
+ $t('global.formField.valueMustBeBetween', {
+ min: 0,
+ max: 65535
+ })
+ }}
+ </template>
+ </b-form-invalid-feedback>
+ </b-form-group>
+ </b-col>
+ <b-col>
+ <b-form-group
+ :label="$t('localUserManagement.modals.userUnlockMethod')"
+ >
+ <b-form-radio
+ v-model="form.unlockMethod"
+ name="unlock-method"
+ class="mb-2"
+ :value="0"
+ @input="$v.form.unlockMethod.$touch()"
+ >
+ {{ $t('localUserManagement.modals.manual') }}
+ </b-form-radio>
+ <b-form-radio
+ v-model="form.unlockMethod"
+ name="unlock-method"
+ :value="1"
+ @input="$v.form.unlockMethod.$touch()"
+ >
+ {{ $t('localUserManagement.modals.automaticAfterTimeout') }}
+ </b-form-radio>
+ <div class="mt-3 ml-4">
+ <b-form-text id="lockout-duration-help-block">
+ {{ $t('localUserManagement.modals.timeoutDurationSeconds') }}
+ </b-form-text>
+ <b-form-input
+ v-model.number="form.lockoutDuration"
+ aria-describedby="lockout-duration-help-block"
+ type="number"
+ :state="getValidationState($v.form.lockoutDuration)"
+ :readonly="$v.form.unlockMethod.$model === 0"
+ @input="$v.form.lockoutDuration.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <template v-if="!$v.form.lockoutDuration.required">
+ {{ $t('global.formField.fieldRequired') }}
+ </template>
+ <template v-else-if="!$v.form.lockoutDuration.minvalue">
+ {{ $t('global.formField.mustBeAtLeast', { value: 1 }) }}
+ </template>
+ </b-form-invalid-feedback>
+ </div>
+ </b-form-group>
+ </b-col>
+ </b-row>
+ </b-container>
+ </b-form>
+ </b-modal>
</template>
<script>
+import VuelidateMixin from '../../../components/Mixins/VuelidateMixin.js';
+import {
+ required,
+ requiredIf,
+ minValue,
+ maxValue
+} from 'vuelidate/lib/validators';
+
export default {
+ mixins: [VuelidateMixin],
props: {
settings: {
type: Object,
required: true
}
+ },
+ data() {
+ return {
+ form: {
+ lockoutThreshold: 0,
+ unlockMethod: 0,
+ lockoutDuration: null
+ }
+ };
+ },
+ watch: {
+ settings: function({ lockoutThreshold, lockoutDuration }) {
+ this.form.lockoutThreshold = lockoutThreshold;
+ this.form.unlockMethod = lockoutDuration ? 1 : 0;
+ this.form.lockoutDuration = lockoutDuration ? lockoutDuration : null;
+ }
+ },
+ validations: {
+ form: {
+ lockoutThreshold: {
+ minValue: minValue(0),
+ maxValue: maxValue(65535),
+ required
+ },
+ unlockMethod: { required },
+ lockoutDuration: {
+ minValue: function(value) {
+ return this.form.unlockMethod === 0 || value > 0;
+ },
+ required: requiredIf(function() {
+ return this.form.unlockMethod === 1;
+ })
+ }
+ }
+ },
+ methods: {
+ handleSubmit() {
+ this.$v.$touch();
+ if (this.$v.$invalid) return;
+
+ let lockoutThreshold;
+ let lockoutDuration;
+ if (this.$v.form.lockoutThreshold.$dirty) {
+ lockoutThreshold = this.form.lockoutThreshold;
+ }
+ if (this.$v.form.unlockMethod.$dirty) {
+ lockoutDuration = this.form.unlockMethod
+ ? this.form.lockoutDuration
+ : 0;
+ }
+
+ this.$emit('ok', { lockoutThreshold, lockoutDuration });
+ this.closeModal();
+ },
+ onOk(bvModalEvt) {
+ // prevent modal close
+ bvModalEvt.preventDefault();
+ this.handleSubmit();
+ },
+ closeModal() {
+ this.$nextTick(() => {
+ this.$refs.modal.hide();
+ });
+ },
+ resetForm() {
+ // Reset form models
+ this.form.lockoutThreshold = this.settings.lockoutThreshold;
+ this.form.unlockMethod = this.settings.lockoutDuration ? 1 : 0;
+ this.form.lockoutDuration = this.settings.lockoutDuration
+ ? this.settings.lockoutDuration
+ : null;
+ this.$v.$reset(); // clear validations
+ }
}
};
</script>