IA update: Update access and control section

This is the fifth commit of the information architecture changes and
has the following changes:

- The icon for access and control has been updated
- Access and control section has been updated to security and
access section
- Security settings page has been updated to policies page and moved to
security and access section
- Client sessions page has been updated to sessions page
- Local user management page has been updated to user management page
- SSL certificates page has been updated to certificates page

Signed-off-by: Sandeepa Singh <sandeepa.singh@ibm.com>
Change-Id: Ie93cee9002742ecf7d33615636f4f159f4395fc4
diff --git a/src/store/modules/SecurityAndAccess/CertificatesStore.js b/src/store/modules/SecurityAndAccess/CertificatesStore.js
new file mode 100644
index 0000000..97241f3
--- /dev/null
+++ b/src/store/modules/SecurityAndAccess/CertificatesStore.js
@@ -0,0 +1,202 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+export const CERTIFICATE_TYPES = [
+  {
+    type: 'HTTPS Certificate',
+    location: '/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/',
+    label: i18n.t('pageCertificates.httpsCertificate'),
+  },
+  {
+    type: 'LDAP Certificate',
+    location: '/redfish/v1/AccountService/LDAP/Certificates/',
+    label: i18n.t('pageCertificates.ldapCertificate'),
+  },
+  {
+    type: 'TrustStore Certificate',
+    location: '/redfish/v1/Managers/bmc/Truststore/Certificates/',
+    // Web UI will show 'CA Certificate' instead of
+    // 'TrustStore Certificate' after user testing revealed
+    // the term 'TrustStore Certificate' wasn't recognized/was unfamilar
+    label: i18n.t('pageCertificates.caCertificate'),
+  },
+];
+
+const getCertificateProp = (type, prop) => {
+  const certificate = CERTIFICATE_TYPES.find(
+    (certificate) => certificate.type === type
+  );
+  return certificate ? certificate[prop] : null;
+};
+
+const CertificatesStore = {
+  namespaced: true,
+  state: {
+    allCertificates: [],
+    availableUploadTypes: [],
+  },
+  getters: {
+    allCertificates: (state) => state.allCertificates,
+    availableUploadTypes: (state) => state.availableUploadTypes,
+  },
+  mutations: {
+    setCertificates(state, certificates) {
+      state.allCertificates = certificates;
+    },
+    setAvailableUploadTypes(state, availableUploadTypes) {
+      state.availableUploadTypes = availableUploadTypes;
+    },
+  },
+  actions: {
+    async getCertificates({ commit }) {
+      return await api
+        .get('/redfish/v1/CertificateService/CertificateLocations')
+        .then(({ data: { Links: { Certificates } } }) =>
+          Certificates.map((certificate) => certificate['@odata.id'])
+        )
+        .then((certificateLocations) => {
+          const promises = certificateLocations.map((location) =>
+            api.get(location)
+          );
+          api.all(promises).then(
+            api.spread((...responses) => {
+              const certificates = responses.map(({ data }) => {
+                const {
+                  Name,
+                  ValidNotAfter,
+                  ValidNotBefore,
+                  Issuer = {},
+                  Subject = {},
+                } = data;
+                return {
+                  type: Name,
+                  location: data['@odata.id'],
+                  certificate: getCertificateProp(Name, 'label'),
+                  issuedBy: Issuer.CommonName,
+                  issuedTo: Subject.CommonName,
+                  validFrom: new Date(ValidNotBefore),
+                  validUntil: new Date(ValidNotAfter),
+                };
+              });
+              const availableUploadTypes = CERTIFICATE_TYPES.filter(
+                ({ type }) =>
+                  !certificates
+                    .map((certificate) => certificate.type)
+                    .includes(type)
+              );
+
+              commit('setCertificates', certificates);
+              commit('setAvailableUploadTypes', availableUploadTypes);
+            })
+          );
+        });
+    },
+    async addNewCertificate({ dispatch }, { file, type }) {
+      return await api
+        .post(getCertificateProp(type, 'location'), file, {
+          headers: { 'Content-Type': 'application/x-pem-file' },
+        })
+        .then(() => dispatch('getCertificates'))
+        .then(() =>
+          i18n.t('pageCertificates.toast.successAddCertificate', {
+            certificate: getCertificateProp(type, 'label'),
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          throw new Error(i18n.t('pageCertificates.toast.errorAddCertificate'));
+        });
+    },
+    async replaceCertificate(
+      { dispatch },
+      { certificateString, location, type }
+    ) {
+      const data = {};
+      data.CertificateString = certificateString;
+      data.CertificateType = 'PEM';
+      data.CertificateUri = { '@odata.id': location };
+
+      return await api
+        .post(
+          '/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate',
+          data
+        )
+        .then(() => dispatch('getCertificates'))
+        .then(() =>
+          i18n.t('pageCertificates.toast.successReplaceCertificate', {
+            certificate: getCertificateProp(type, 'label'),
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          throw new Error(
+            i18n.t('pageCertificates.toast.errorReplaceCertificate')
+          );
+        });
+    },
+    async deleteCertificate({ dispatch }, { type, location }) {
+      return await api
+        .delete(location)
+        .then(() => dispatch('getCertificates'))
+        .then(() =>
+          i18n.t('pageCertificates.toast.successDeleteCertificate', {
+            certificate: getCertificateProp(type, 'label'),
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          throw new Error(
+            i18n.t('pageCertificates.toast.errorDeleteCertificate')
+          );
+        });
+    },
+    async generateCsr(_, userData) {
+      const {
+        certificateType,
+        country,
+        state,
+        city,
+        companyName,
+        companyUnit,
+        commonName,
+        keyPairAlgorithm,
+        keyBitLength,
+        keyCurveId,
+        challengePassword,
+        contactPerson,
+        emailAddress,
+        alternateName,
+      } = userData;
+      const data = {};
+
+      data.CertificateCollection = {
+        '@odata.id': getCertificateProp(certificateType, 'location'),
+      };
+      data.Country = country;
+      data.State = state;
+      data.City = city;
+      data.Organization = companyName;
+      data.OrganizationalUnit = companyUnit;
+      data.CommonName = commonName;
+      data.KeyPairAlgorithm = keyPairAlgorithm;
+      data.AlternativeNames = alternateName;
+
+      if (keyCurveId) data.KeyCurveId = keyCurveId;
+      if (keyBitLength) data.KeyBitLength = keyBitLength;
+      if (challengePassword) data.ChallengePassword = challengePassword;
+      if (contactPerson) data.ContactPerson = contactPerson;
+      if (emailAddress) data.Email = emailAddress;
+
+      return await api
+        .post(
+          '/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR',
+          data
+        )
+        //TODO: Success response also throws error so
+        // can't accurately show legitimate error in UI
+        .catch((error) => console.log(error));
+    },
+  },
+};
+
+export default CertificatesStore;
diff --git a/src/store/modules/SecurityAndAccess/LdapStore.js b/src/store/modules/SecurityAndAccess/LdapStore.js
new file mode 100644
index 0000000..5aa31c2
--- /dev/null
+++ b/src/store/modules/SecurityAndAccess/LdapStore.js
@@ -0,0 +1,275 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+import { find } from 'lodash';
+
+const LdapStore = {
+  namespaced: true,
+  state: {
+    isServiceEnabled: null,
+    ldap: {
+      serviceEnabled: null,
+      serviceAddress: null,
+      bindDn: null,
+      baseDn: null,
+      userAttribute: null,
+      groupsAttribute: null,
+      roleGroups: [],
+    },
+    activeDirectory: {
+      serviceEnabled: null,
+      serviceAddress: null,
+      bindDn: null,
+      baseDn: null,
+      userAttribute: null,
+      groupsAttribute: null,
+      roleGroups: [],
+    },
+  },
+  getters: {
+    isServiceEnabled: (state) => state.isServiceEnabled,
+    ldap: (state) => state.ldap,
+    activeDirectory: (state) => state.activeDirectory,
+    isActiveDirectoryEnabled: (state) => {
+      return state.activeDirectory.serviceEnabled;
+    },
+    enabledRoleGroups: (state, getters) => {
+      const serviceType = getters.isActiveDirectoryEnabled
+        ? 'activeDirectory'
+        : 'ldap';
+      return state[serviceType].roleGroups;
+    },
+  },
+  mutations: {
+    setServiceEnabled: (state, serviceEnabled) =>
+      (state.isServiceEnabled = serviceEnabled),
+    setLdapProperties: (
+      state,
+      {
+        ServiceEnabled,
+        ServiceAddresses = [],
+        Authentication = {},
+        LDAPService: {
+          SearchSettings: {
+            BaseDistinguishedNames = [],
+            UsernameAttribute,
+            GroupsAttribute,
+          } = {},
+        } = {},
+        RemoteRoleMapping = [],
+      }
+    ) => {
+      state.ldap.serviceAddress = ServiceAddresses[0];
+      state.ldap.serviceEnabled = ServiceEnabled;
+      state.ldap.baseDn = BaseDistinguishedNames[0];
+      state.ldap.bindDn = Authentication.Username;
+      state.ldap.userAttribute = UsernameAttribute;
+      state.ldap.groupsAttribute = GroupsAttribute;
+      state.ldap.roleGroups = RemoteRoleMapping;
+    },
+    setActiveDirectoryProperties: (
+      state,
+      {
+        ServiceEnabled,
+        ServiceAddresses = [],
+        Authentication = {},
+        LDAPService: {
+          SearchSettings: {
+            BaseDistinguishedNames = [],
+            UsernameAttribute,
+            GroupsAttribute,
+          } = {},
+        } = {},
+        RemoteRoleMapping = [],
+      }
+    ) => {
+      state.activeDirectory.serviceEnabled = ServiceEnabled;
+      state.activeDirectory.serviceAddress = ServiceAddresses[0];
+      state.activeDirectory.bindDn = Authentication.Username;
+      state.activeDirectory.baseDn = BaseDistinguishedNames[0];
+      state.activeDirectory.userAttribute = UsernameAttribute;
+      state.activeDirectory.groupsAttribute = GroupsAttribute;
+      state.activeDirectory.roleGroups = RemoteRoleMapping;
+    },
+  },
+  actions: {
+    async getAccountSettings({ commit }) {
+      return await api
+        .get('/redfish/v1/AccountService')
+        .then(({ data: { LDAP = {}, ActiveDirectory = {} } }) => {
+          const ldapEnabled = LDAP.ServiceEnabled;
+          const activeDirectoryEnabled = ActiveDirectory.ServiceEnabled;
+
+          commit('setServiceEnabled', ldapEnabled || activeDirectoryEnabled);
+          commit('setLdapProperties', LDAP);
+          commit('setActiveDirectoryProperties', ActiveDirectory);
+        })
+        .catch((error) => console.log(error));
+    },
+    async saveLdapSettings({ state, dispatch }, properties) {
+      const data = { LDAP: properties };
+      if (state.activeDirectory.serviceEnabled) {
+        // Disable Active Directory service if enabled
+        await api.patch('/redfish/v1/AccountService', {
+          ActiveDirectory: { ServiceEnabled: false },
+        });
+      }
+      return await api
+        .patch('/redfish/v1/AccountService', data)
+        .then(() => dispatch('getAccountSettings'))
+        .then(() => i18n.t('pageLdap.toast.successSaveLdapSettings'))
+        .catch((error) => {
+          console.log(error);
+          throw new Error(i18n.t('pageLdap.toast.errorSaveLdapSettings'));
+        });
+    },
+    async saveActiveDirectorySettings({ state, dispatch }, properties) {
+      const data = { ActiveDirectory: properties };
+      if (state.ldap.serviceEnabled) {
+        // Disable LDAP service if enabled
+        await api.patch('/redfish/v1/AccountService', {
+          LDAP: { ServiceEnabled: false },
+        });
+      }
+      return await api
+        .patch('/redfish/v1/AccountService', data)
+        .then(() => dispatch('getAccountSettings'))
+        .then(() => i18n.t('pageLdap.toast.successSaveActiveDirectorySettings'))
+        .catch((error) => {
+          console.log(error);
+          throw new Error(
+            i18n.t('pageLdap.toast.errorSaveActiveDirectorySettings')
+          );
+        });
+    },
+    async saveAccountSettings(
+      { dispatch },
+      {
+        serviceEnabled,
+        serviceAddress,
+        activeDirectoryEnabled,
+        bindDn,
+        bindPassword,
+        baseDn,
+        userIdAttribute,
+        groupIdAttribute,
+      }
+    ) {
+      const data = {
+        ServiceEnabled: serviceEnabled,
+        ServiceAddresses: [serviceAddress],
+        Authentication: {
+          Username: bindDn,
+          Password: bindPassword,
+        },
+        LDAPService: {
+          SearchSettings: {
+            BaseDistinguishedNames: [baseDn],
+          },
+        },
+      };
+      if (groupIdAttribute)
+        data.LDAPService.SearchSettings.GroupsAttribute = groupIdAttribute;
+      if (userIdAttribute)
+        data.LDAPService.SearchSettings.UsernameAttribute = userIdAttribute;
+
+      if (activeDirectoryEnabled) {
+        return await dispatch('saveActiveDirectorySettings', data);
+      } else {
+        return await dispatch('saveLdapSettings', data);
+      }
+    },
+    async addNewRoleGroup(
+      { dispatch, getters },
+      { groupName, groupPrivilege }
+    ) {
+      const data = {};
+      const enabledRoleGroups = getters['enabledRoleGroups'];
+      const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled'];
+      const RemoteRoleMapping = [
+        ...enabledRoleGroups,
+        {
+          LocalRole: groupPrivilege,
+          RemoteGroup: groupName,
+        },
+      ];
+      if (isActiveDirectoryEnabled) {
+        data.ActiveDirectory = { RemoteRoleMapping };
+      } else {
+        data.LDAP = { RemoteRoleMapping };
+      }
+      return await api
+        .patch('/redfish/v1/AccountService', data)
+        .then(() => dispatch('getAccountSettings'))
+        .then(() =>
+          i18n.t('pageLdap.toast.successAddRoleGroup', {
+            groupName,
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          throw new Error(i18n.t('pageLdap.toast.errorAddRoleGroup'));
+        });
+    },
+    async saveRoleGroup({ dispatch, getters }, { groupName, groupPrivilege }) {
+      const data = {};
+      const enabledRoleGroups = getters['enabledRoleGroups'];
+      const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled'];
+      const RemoteRoleMapping = enabledRoleGroups.map((group) => {
+        if (group.RemoteGroup === groupName) {
+          return {
+            RemoteGroup: groupName,
+            LocalRole: groupPrivilege,
+          };
+        } else {
+          return {};
+        }
+      });
+      if (isActiveDirectoryEnabled) {
+        data.ActiveDirectory = { RemoteRoleMapping };
+      } else {
+        data.LDAP = { RemoteRoleMapping };
+      }
+      return await api
+        .patch('/redfish/v1/AccountService', data)
+        .then(() => dispatch('getAccountSettings'))
+        .then(() =>
+          i18n.t('pageLdap.toast.successSaveRoleGroup', { groupName })
+        )
+        .catch((error) => {
+          console.log(error);
+          throw new Error(i18n.t('pageLdap.toast.errorSaveRoleGroup'));
+        });
+    },
+    async deleteRoleGroup({ dispatch, getters }, { roleGroups = [] }) {
+      const data = {};
+      const enabledRoleGroups = getters['enabledRoleGroups'];
+      const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled'];
+      const RemoteRoleMapping = enabledRoleGroups.map((group) => {
+        if (find(roleGroups, { groupName: group.RemoteGroup })) {
+          return null;
+        } else {
+          return {};
+        }
+      });
+      if (isActiveDirectoryEnabled) {
+        data.ActiveDirectory = { RemoteRoleMapping };
+      } else {
+        data.LDAP = { RemoteRoleMapping };
+      }
+      return await api
+        .patch('/redfish/v1/AccountService', data)
+        .then(() => dispatch('getAccountSettings'))
+        .then(() =>
+          i18n.tc('pageLdap.toast.successDeleteRoleGroup', roleGroups.length)
+        )
+        .catch((error) => {
+          console.log(error);
+          throw new Error(
+            i18n.tc('pageLdap.toast.errorDeleteRoleGroup', roleGroups.length)
+          );
+        });
+    },
+  },
+};
+
+export default LdapStore;
diff --git a/src/store/modules/SecurityAndAccess/PoliciesStore.js b/src/store/modules/SecurityAndAccess/PoliciesStore.js
new file mode 100644
index 0000000..1e19552
--- /dev/null
+++ b/src/store/modules/SecurityAndAccess/PoliciesStore.js
@@ -0,0 +1,87 @@
+import api from '@/store/api';
+import i18n from '@/i18n';
+
+const PoliciesStore = {
+  namespaced: true,
+  state: {
+    sshProtocolEnabled: false,
+    ipmiProtocolEnabled: false,
+  },
+  getters: {
+    sshProtocolEnabled: (state) => state.sshProtocolEnabled,
+    ipmiProtocolEnabled: (state) => state.ipmiProtocolEnabled,
+  },
+  mutations: {
+    setSshProtocolEnabled: (state, sshProtocolEnabled) =>
+      (state.sshProtocolEnabled = sshProtocolEnabled),
+    setIpmiProtocolEnabled: (state, ipmiProtocolEnabled) =>
+      (state.ipmiProtocolEnabled = ipmiProtocolEnabled),
+  },
+  actions: {
+    async getNetworkProtocolStatus({ commit }) {
+      return await api
+        .get('/redfish/v1/Managers/bmc/NetworkProtocol')
+        .then((response) => {
+          const sshProtocol = response.data.SSH.ProtocolEnabled;
+          const ipmiProtocol = response.data.IPMI.ProtocolEnabled;
+          commit('setSshProtocolEnabled', sshProtocol);
+          commit('setIpmiProtocolEnabled', ipmiProtocol);
+        })
+        .catch((error) => console.log(error));
+    },
+    async saveIpmiProtocolState({ commit }, protocolEnabled) {
+      commit('setIpmiProtocolEnabled', protocolEnabled);
+      const ipmi = {
+        IPMI: {
+          ProtocolEnabled: protocolEnabled,
+        },
+      };
+      return await api
+        .patch('/redfish/v1/Managers/bmc/NetworkProtocol', ipmi)
+        .then(() => {
+          if (protocolEnabled) {
+            return i18n.t('pagePolicies.toast.successIpmiEnabled');
+          } else {
+            return i18n.t('pagePolicies.toast.successIpmiDisabled');
+          }
+        })
+        .catch((error) => {
+          console.log(error);
+          commit('setIpmiProtocolEnabled', !protocolEnabled);
+          if (protocolEnabled) {
+            throw new Error(i18n.t('pagePolicies.toast.errorIpmiEnabled'));
+          } else {
+            throw new Error(i18n.t('pagePolicies.toast.errorIpmiDisabled'));
+          }
+        });
+    },
+    async saveSshProtocolState({ commit }, protocolEnabled) {
+      commit('setSshProtocolEnabled', protocolEnabled);
+      const ssh = {
+        SSH: {
+          ProtocolEnabled: protocolEnabled,
+        },
+      };
+      return await api
+        .patch('/redfish/v1/Managers/bmc/NetworkProtocol', ssh)
+        .then(() => {
+          if (protocolEnabled) {
+            return i18n.t('pagePolicies.toast.successSshEnabled');
+          } else {
+            return i18n.t('pagePolicies.toast.successSshDisabled');
+          }
+        })
+        .catch((error) => {
+          console.log(error);
+          commit('setSshProtocolEnabled', !protocolEnabled);
+          if (protocolEnabled) {
+            throw new Error(i18n.t('pagePolicies.toast.errorSshEnabled'));
+          } else {
+            throw new Error(i18n.t('pagePolicies.toast.errorSshDisabled'));
+          }
+        });
+    },
+  },
+};
+
+export default PoliciesStore;
diff --git a/src/store/modules/SecurityAndAccess/SessionsStore.js b/src/store/modules/SecurityAndAccess/SessionsStore.js
new file mode 100644
index 0000000..54607ab
--- /dev/null
+++ b/src/store/modules/SecurityAndAccess/SessionsStore.js
@@ -0,0 +1,80 @@
+import api, { getResponseCount } from '@/store/api';
+import i18n from '@/i18n';
+
+const SessionsStore = {
+  namespaced: true,
+  state: {
+    allConnections: [],
+  },
+  getters: {
+    allConnections: (state) => state.allConnections,
+  },
+  mutations: {
+    setAllConnections: (state, allConnections) =>
+      (state.allConnections = allConnections),
+  },
+  actions: {
+    async getSessionsData({ commit }) {
+      return await api
+        .get('/redfish/v1/SessionService/Sessions')
+        .then((response) =>
+          response.data.Members.map((sessionLogs) => sessionLogs['@odata.id'])
+        )
+        .then((sessionUris) =>
+          api.all(sessionUris.map((sessionUri) => api.get(sessionUri)))
+        )
+        .then((sessionUris) => {
+          const allConnectionsData = sessionUris.map((sessionUri) => {
+            return {
+              clientID: sessionUri.data?.Oem?.OpenBMC.ClientID,
+              username: sessionUri.data?.UserName,
+              ipAddress: sessionUri.data?.ClientOriginIPAddress,
+              uri: sessionUri.data['@odata.id'],
+            };
+          });
+          commit('setAllConnections', allConnectionsData);
+        })
+        .catch((error) => {
+          console.log('Client Session Data:', error);
+        });
+    },
+    async disconnectSessions({ dispatch }, uris = []) {
+      const promises = uris.map((uri) =>
+        api.delete(uri).catch((error) => {
+          console.log(error);
+          return error;
+        })
+      );
+      return await api
+        .all(promises)
+        .then((response) => {
+          dispatch('getSessionsData');
+          return response;
+        })
+        .then(
+          api.spread((...responses) => {
+            const { successCount, errorCount } = getResponseCount(responses);
+            const toastMessages = [];
+
+            if (successCount) {
+              const message = i18n.tc(
+                'pageSessions.toast.successDelete',
+                successCount
+              );
+              toastMessages.push({ type: 'success', message });
+            }
+
+            if (errorCount) {
+              const message = i18n.tc(
+                'pageSessions.toast.errorDelete',
+                errorCount
+              );
+              toastMessages.push({ type: 'error', message });
+            }
+            return toastMessages;
+          })
+        );
+    },
+  },
+};
+export default SessionsStore;
diff --git a/src/store/modules/SecurityAndAccess/UserManagementStore.js b/src/store/modules/SecurityAndAccess/UserManagementStore.js
new file mode 100644
index 0000000..362f3f6
--- /dev/null
+++ b/src/store/modules/SecurityAndAccess/UserManagementStore.js
@@ -0,0 +1,318 @@
+import api, { getResponseCount } from '@/store/api';
+import i18n from '@/i18n';
+
+const UserManagementStore = {
+  namespaced: true,
+  state: {
+    allUsers: [],
+    accountRoles: [],
+    accountLockoutDuration: null,
+    accountLockoutThreshold: null,
+    accountMinPasswordLength: null,
+    accountMaxPasswordLength: null,
+  },
+  getters: {
+    allUsers(state) {
+      return state.allUsers;
+    },
+    accountRoles(state) {
+      return state.accountRoles;
+    },
+    accountSettings(state) {
+      return {
+        lockoutDuration: state.accountLockoutDuration,
+        lockoutThreshold: state.accountLockoutThreshold,
+      };
+    },
+    accountPasswordRequirements(state) {
+      return {
+        minLength: state.accountMinPasswordLength,
+        maxLength: state.accountMaxPasswordLength,
+      };
+    },
+  },
+  mutations: {
+    setUsers(state, allUsers) {
+      state.allUsers = allUsers;
+    },
+    setAccountRoles(state, accountRoles) {
+      state.accountRoles = accountRoles;
+    },
+    setLockoutDuration(state, lockoutDuration) {
+      state.accountLockoutDuration = lockoutDuration;
+    },
+    setLockoutThreshold(state, lockoutThreshold) {
+      state.accountLockoutThreshold = lockoutThreshold;
+    },
+    setAccountMinPasswordLength(state, minPasswordLength) {
+      state.accountMinPasswordLength = minPasswordLength;
+    },
+    setAccountMaxPasswordLength(state, maxPasswordLength) {
+      state.accountMaxPasswordLength = maxPasswordLength;
+    },
+  },
+  actions: {
+    async getUsers({ commit }) {
+      return await api
+        .get('/redfish/v1/AccountService/Accounts')
+        .then((response) =>
+          response.data.Members.map((user) => user['@odata.id'])
+        )
+        .then((userIds) => api.all(userIds.map((user) => api.get(user))))
+        .then((users) => {
+          const userData = users.map((user) => user.data);
+          commit('setUsers', userData);
+        })
+        .catch((error) => {
+          console.log(error);
+          const message = i18n.t('pageUserManagement.toast.errorLoadUsers');
+          throw new Error(message);
+        });
+    },
+    getAccountSettings({ commit }) {
+      api
+        .get('/redfish/v1/AccountService')
+        .then(({ data }) => {
+          commit('setLockoutDuration', data.AccountLockoutDuration);
+          commit('setLockoutThreshold', data.AccountLockoutThreshold);
+          commit('setAccountMinPasswordLength', data.MinPasswordLength);
+          commit('setAccountMaxPasswordLength', data.MaxPasswordLength);
+        })
+        .catch((error) => {
+          console.log(error);
+          const message = i18n.t(
+            'pageUserManagement.toast.errorLoadAccountSettings'
+          );
+          throw new Error(message);
+        });
+    },
+    getAccountRoles({ commit }) {
+      api
+        .get('/redfish/v1/AccountService/Roles')
+        .then(({ data: { Members = [] } = {} }) => {
+          const roles = Members.map((role) => {
+            return role['@odata.id'].split('/').pop();
+          });
+          commit('setAccountRoles', roles);
+        })
+        .catch((error) => console.log(error));
+    },
+    async createUser({ dispatch }, { username, password, privilege, status }) {
+      const data = {
+        UserName: username,
+        Password: password,
+        RoleId: privilege,
+        Enabled: status,
+      };
+      return await api
+        .post('/redfish/v1/AccountService/Accounts', data)
+        .then(() => dispatch('getUsers'))
+        .then(() =>
+          i18n.t('pageUserManagement.toast.successCreateUser', {
+            username,
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          const message = i18n.t('pageUserManagement.toast.errorCreateUser', {
+            username,
+          });
+          throw new Error(message);
+        });
+    },
+    async updateUser(
+      { dispatch },
+      { originalUsername, username, password, privilege, status, locked }
+    ) {
+      const data = {};
+      if (username) data.UserName = username;
+      if (password) data.Password = password;
+      if (privilege) data.RoleId = privilege;
+      if (status !== undefined) data.Enabled = status;
+      if (locked !== undefined) data.Locked = locked;
+      return await api
+        .patch(`/redfish/v1/AccountService/Accounts/${originalUsername}`, data)
+        .then(() => dispatch('getUsers'))
+        .then(() =>
+          i18n.t('pageUserManagement.toast.successUpdateUser', {
+            username: originalUsername,
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          const message = i18n.t('pageUserManagement.toast.errorUpdateUser', {
+            username: originalUsername,
+          });
+          throw new Error(message);
+        });
+    },
+    async deleteUser({ dispatch }, username) {
+      return await api
+        .delete(`/redfish/v1/AccountService/Accounts/${username}`)
+        .then(() => dispatch('getUsers'))
+        .then(() =>
+          i18n.t('pageUserManagement.toast.successDeleteUser', {
+            username,
+          })
+        )
+        .catch((error) => {
+          console.log(error);
+          const message = i18n.t('pageUserManagement.toast.errorDeleteUser', {
+            username,
+          });
+          throw new Error(message);
+        });
+    },
+    async deleteUsers({ dispatch }, users) {
+      const promises = users.map(({ username }) => {
+        return api
+          .delete(`/redfish/v1/AccountService/Accounts/${username}`)
+          .catch((error) => {
+            console.log(error);
+            return error;
+          });
+      });
+      return await api
+        .all(promises)
+        .then((response) => {
+          dispatch('getUsers');
+          return response;
+        })
+        .then(
+          api.spread((...responses) => {
+            const { successCount, errorCount } = getResponseCount(responses);
+            let toastMessages = [];
+
+            if (successCount) {
+              const message = i18n.tc(
+                'pageUserManagement.toast.successBatchDelete',
+                successCount
+              );
+              toastMessages.push({ type: 'success', message });
+            }
+
+            if (errorCount) {
+              const message = i18n.tc(
+                'pageUserManagement.toast.errorBatchDelete',
+                errorCount
+              );
+              toastMessages.push({ type: 'error', message });
+            }
+
+            return toastMessages;
+          })
+        );
+    },
+    async enableUsers({ dispatch }, users) {
+      const data = {
+        Enabled: true,
+      };
+      const promises = users.map(({ username }) => {
+        return api
+          .patch(`/redfish/v1/AccountService/Accounts/${username}`, data)
+          .catch((error) => {
+            console.log(error);
+            return error;
+          });
+      });
+      return await api
+        .all(promises)
+        .then((response) => {
+          dispatch('getUsers');
+          return response;
+        })
+        .then(
+          api.spread((...responses) => {
+            const { successCount, errorCount } = getResponseCount(responses);
+            let toastMessages = [];
+
+            if (successCount) {
+              const message = i18n.tc(
+                'pageUserManagement.toast.successBatchEnable',
+                successCount
+              );
+              toastMessages.push({ type: 'success', message });
+            }
+
+            if (errorCount) {
+              const message = i18n.tc(
+                'pageUserManagement.toast.errorBatchEnable',
+                errorCount
+              );
+              toastMessages.push({ type: 'error', message });
+            }
+
+            return toastMessages;
+          })
+        );
+    },
+    async disableUsers({ dispatch }, users) {
+      const data = {
+        Enabled: false,
+      };
+      const promises = users.map(({ username }) => {
+        return api
+          .patch(`/redfish/v1/AccountService/Accounts/${username}`, data)
+          .catch((error) => {
+            console.log(error);
+            return error;
+          });
+      });
+      return await api
+        .all(promises)
+        .then((response) => {
+          dispatch('getUsers');
+          return response;
+        })
+        .then(
+          api.spread((...responses) => {
+            const { successCount, errorCount } = getResponseCount(responses);
+            let toastMessages = [];
+
+            if (successCount) {
+              const message = i18n.tc(
+                'pageUserManagement.toast.successBatchDisable',
+                successCount
+              );
+              toastMessages.push({ type: 'success', message });
+            }
+
+            if (errorCount) {
+              const message = i18n.tc(
+                'pageUserManagement.toast.errorBatchDisable',
+                errorCount
+              );
+              toastMessages.push({ type: 'error', message });
+            }
+
+            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('pageUserManagement.toast.successSaveSettings'))
+        .catch((error) => {
+          console.log(error);
+          const message = i18n.t('pageUserManagement.toast.errorSaveSettings');
+          throw new Error(message);
+        });
+    },
+  },
+};
+
+export default UserManagementStore;