xref: /openbmc/webui-vue/src/views/ProfileSettings/ProfileSettings.vue (revision 7d6b44cb263da09e575c7cb28cab88c1eb339c7b)
1<template>
2  <b-container fluid="xl">
3    <page-title />
4
5    <b-row>
6      <b-col md="8" lg="8" xl="6">
7        <page-section
8          :section-title="$t('pageProfileSettings.profileInfoTitle')"
9        >
10          <dl>
11            <dt>{{ $t('pageProfileSettings.username') }}</dt>
12            <dd>
13              {{ username }}
14            </dd>
15          </dl>
16        </page-section>
17      </b-col>
18    </b-row>
19
20    <b-form @submit.prevent="submitForm">
21      <b-row>
22        <b-col sm="8" md="6" xl="3">
23          <page-section
24            :section-title="$t('pageProfileSettings.changePassword')"
25          >
26            <b-form-group
27              id="input-group-0"
28              :label="$t('pageProfileSettings.currentPassword')"
29              label-for="input-0"
30            >
31              <input-password-toggle>
32                <b-form-input
33                  id="old-password"
34                  v-model="form.currentPassword"
35                  type="password"
36                  data-test-id="profileSettings-input-ocurrentPassword"
37                  class="form-control-with-button"
38                />
39              </input-password-toggle>
40            </b-form-group>
41            <b-form-group
42              id="input-group-1"
43              :label="$t('pageProfileSettings.newPassword')"
44              label-for="input-1"
45            >
46              <b-form-text id="password-help-block">
47                {{
48                  $t('pageUserManagement.modal.passwordMustBeBetween', {
49                    min: passwordRequirements.minLength,
50                    max: passwordRequirements.maxLength,
51                  })
52                }}
53              </b-form-text>
54              <input-password-toggle>
55                <b-form-input
56                  id="password"
57                  v-model="form.newPassword"
58                  type="password"
59                  aria-describedby="password-help-block"
60                  :state="getValidationState($v.form.newPassword)"
61                  data-test-id="profileSettings-input-newPassword"
62                  class="form-control-with-button"
63                  @input="$v.form.newPassword.$touch()"
64                />
65                <b-form-invalid-feedback role="alert">
66                  <template
67                    v-if="
68                      !$v.form.newPassword.minLength ||
69                      !$v.form.newPassword.maxLength
70                    "
71                  >
72                    {{
73                      $t('pageProfileSettings.newPassLabelTextInfo', {
74                        min: passwordRequirements.minLength,
75                        max: passwordRequirements.maxLength,
76                      })
77                    }}
78                  </template>
79                </b-form-invalid-feedback>
80              </input-password-toggle>
81            </b-form-group>
82            <b-form-group
83              id="input-group-2"
84              :label="$t('pageProfileSettings.confirmPassword')"
85              label-for="input-2"
86            >
87              <input-password-toggle>
88                <b-form-input
89                  id="password-confirmation"
90                  v-model="form.confirmPassword"
91                  type="password"
92                  :state="getValidationState($v.form.confirmPassword)"
93                  data-test-id="profileSettings-input-confirmPassword"
94                  class="form-control-with-button"
95                  @input="$v.form.confirmPassword.$touch()"
96                />
97                <b-form-invalid-feedback role="alert">
98                  <template v-if="!$v.form.confirmPassword.sameAsPassword">
99                    {{ $t('pageProfileSettings.passwordsDoNotMatch') }}
100                  </template>
101                </b-form-invalid-feedback>
102              </input-password-toggle>
103            </b-form-group>
104          </page-section>
105        </b-col>
106      </b-row>
107      <page-section :section-title="$t('pageProfileSettings.timezoneDisplay')">
108        <p>{{ $t('pageProfileSettings.timezoneDisplayDesc') }}</p>
109        <b-row>
110          <b-col md="9" lg="8" xl="9">
111            <b-form-group :label="$t('pageProfileSettings.timezone')">
112              <b-form-radio
113                v-model="form.isUtcDisplay"
114                :value="true"
115                data-test-id="profileSettings-radio-defaultUTC"
116              >
117                {{ $t('pageProfileSettings.defaultUTC') }}
118              </b-form-radio>
119              <b-form-radio
120                v-model="form.isUtcDisplay"
121                :value="false"
122                data-test-id="profileSettings-radio-browserOffset"
123              >
124                {{
125                  $t('pageProfileSettings.browserOffset', {
126                    timezone,
127                  })
128                }}
129              </b-form-radio>
130            </b-form-group>
131          </b-col>
132        </b-row>
133      </page-section>
134      <b-button
135        variant="primary"
136        type="submit"
137        data-test-id="profileSettings-button-saveSettings"
138      >
139        {{ $t('global.action.saveSettings') }}
140      </b-button>
141    </b-form>
142  </b-container>
143</template>
144
145<script>
146import BVToastMixin from '@/components/Mixins/BVToastMixin';
147import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
148import { maxLength, minLength, sameAs } from '@vuelidate/validators';
149import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
150import LocalTimezoneLabelMixin from '@/components/Mixins/LocalTimezoneLabelMixin';
151import PageTitle from '@/components/Global/PageTitle';
152import PageSection from '@/components/Global/PageSection';
153import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
154import { useVuelidate } from '@vuelidate/core';
155
156export default {
157  name: 'ProfileSettings',
158  components: { InputPasswordToggle, PageSection, PageTitle },
159  mixins: [
160    BVToastMixin,
161    LocalTimezoneLabelMixin,
162    LoadingBarMixin,
163    VuelidateMixin,
164  ],
165  setup() {
166    return {
167      v$: useVuelidate(),
168    };
169  },
170  data() {
171    return {
172      form: {
173        newPassword: '',
174        confirmPassword: '',
175        currentPassword: '',
176        isUtcDisplay: this.$store.getters['global/isUtcDisplay'],
177      },
178    };
179  },
180  computed: {
181    username() {
182      return this.$store.getters['global/username'];
183    },
184    passwordRequirements() {
185      return this.$store.getters['userManagement/accountPasswordRequirements'];
186    },
187    timezone() {
188      return this.localOffset();
189    },
190  },
191  created() {
192    this.startLoader();
193    this.$store
194      .dispatch('userManagement/getAccountSettings')
195      .finally(() => this.endLoader());
196  },
197  validations() {
198    return {
199      form: {
200        newPassword: {
201          minLength: minLength(this.passwordRequirements.minLength),
202          maxLength: maxLength(this.passwordRequirements.maxLength),
203        },
204        confirmPassword: {
205          sameAsPassword: sameAs('newPassword'),
206        },
207      },
208    };
209  },
210  methods: {
211    saveNewPasswordInputData() {
212      this.$v.form.confirmPassword.$touch();
213      this.$v.form.newPassword.$touch();
214      if (this.$v.$invalid) return;
215      let userData = {
216        originalUsername: this.username,
217        password: this.form.newPassword,
218      };
219
220      this.$store
221        .dispatch('userManagement/updateUser', userData)
222        .then((message) => {
223          (this.form.newPassword = ''),
224            (this.form.confirmPassword = ''),
225            (this.form.currentPassword = '');
226          this.$v.$reset();
227          this.successToast(message);
228          this.$store.dispatch('authentication/logout');
229        })
230        .catch(({ message }) => this.errorToast(message));
231    },
232    saveTimeZonePrefrenceData() {
233      localStorage.setItem('storedUtcDisplay', this.form.isUtcDisplay);
234      this.$store.commit('global/setUtcTime', this.form.isUtcDisplay);
235      this.successToast(
236        this.$t('pageProfileSettings.toast.successUpdatingTimeZone'),
237      );
238    },
239    submitForm() {
240      if (
241        this.form.confirmPassword &&
242        this.form.newPassword &&
243        this.form.currentPassword
244      ) {
245        this.confirmAuthenticate();
246      }
247      if (
248        this.$store.getters['global/isUtcDisplay'] != this.form.isUtcDisplay
249      ) {
250        this.saveTimeZonePrefrenceData();
251      }
252    },
253    confirmAuthenticate() {
254      this.$v.form.newPassword.$touch();
255      if (this.$v.$invalid) return;
256
257      const username = this.username;
258      const password = this.form.currentPassword;
259
260      this.$store
261        .dispatch('authentication/login', { username, password })
262        .then(() => {
263          this.saveNewPasswordInputData();
264        })
265        .catch(() => {
266          this.$v.$reset();
267          this.errorToast(
268            this.$t('pageProfileSettings.toast.wrongCredentials'),
269          );
270        });
271    },
272  },
273};
274</script>
275