1<template>
2  <b-modal id="modal-user" ref="modal" @hidden="resetForm">
3    <template #modal-title>
4      <template v-if="newUser">
5        {{ $t('pageUserManagement.addUser') }}
6      </template>
7      <template v-else>
8        {{ $t('pageUserManagement.editUser') }}
9      </template>
10    </template>
11    <b-form id="form-user" novalidate @submit.prevent="handleSubmit">
12      <b-container>
13        <!-- Manual unlock form control -->
14        <b-row v-if="!newUser && manualUnlockPolicy && user.Locked">
15          <b-col sm="9">
16            <alert :show="true" variant="warning" small>
17              <template v-if="!$v.form.manualUnlock.$dirty">
18                {{ $t('pageUserManagement.modal.accountLocked') }}
19              </template>
20              <template v-else>
21                {{ $t('pageUserManagement.modal.clickSaveToUnlockAccount') }}
22              </template>
23            </alert>
24          </b-col>
25          <b-col sm="3">
26            <input
27              v-model="form.manualUnlock"
28              data-test-id="userManagement-input-manualUnlock"
29              type="hidden"
30              value="false"
31            />
32            <b-button
33              variant="primary"
34              :disabled="$v.form.manualUnlock.$dirty"
35              data-test-id="userManagement-button-manualUnlock"
36              @click="$v.form.manualUnlock.$touch()"
37            >
38              {{ $t('pageUserManagement.modal.unlock') }}
39            </b-button>
40          </b-col>
41        </b-row>
42        <b-row>
43          <b-col>
44            <b-form-group :label="$t('pageUserManagement.modal.accountStatus')">
45              <b-form-radio
46                v-model="form.status"
47                name="user-status"
48                :value="true"
49                data-test-id="userManagement-radioButton-statusEnabled"
50                @input="$v.form.status.$touch()"
51              >
52                {{ $t('global.status.enabled') }}
53              </b-form-radio>
54              <b-form-radio
55                v-model="form.status"
56                name="user-status"
57                data-test-id="userManagement-radioButton-statusDisabled"
58                :value="false"
59                :disabled="!newUser && originalUsername === disabled"
60                @input="$v.form.status.$touch()"
61              >
62                {{ $t('global.status.disabled') }}
63              </b-form-radio>
64            </b-form-group>
65            <b-form-group
66              :label="$t('pageUserManagement.modal.username')"
67              label-for="username"
68            >
69              <b-form-text id="username-help-block">
70                {{ $t('pageUserManagement.modal.cannotStartWithANumber') }}
71                <br />
72                {{
73                  $t(
74                    'pageUserManagement.modal.noSpecialCharactersExceptUnderscore'
75                  )
76                }}
77              </b-form-text>
78              <b-form-input
79                id="username"
80                v-model="form.username"
81                type="text"
82                aria-describedby="username-help-block"
83                data-test-id="userManagement-input-username"
84                :state="getValidationState($v.form.username)"
85                :disabled="!newUser && originalUsername === disabled"
86                @input="$v.form.username.$touch()"
87              />
88              <b-form-invalid-feedback role="alert">
89                <template v-if="!$v.form.username.required">
90                  {{ $t('global.form.fieldRequired') }}
91                </template>
92                <template v-else-if="!$v.form.username.maxLength">
93                  {{
94                    $t('global.form.lengthMustBeBetween', { min: 1, max: 16 })
95                  }}
96                </template>
97                <template v-else-if="!$v.form.username.pattern">
98                  {{ $t('global.form.invalidFormat') }}
99                </template>
100              </b-form-invalid-feedback>
101            </b-form-group>
102            <b-form-group
103              :label="$t('pageUserManagement.modal.privilege')"
104              label-for="privilege"
105            >
106              <b-form-select
107                id="privilege"
108                v-model="form.privilege"
109                :options="privilegeTypes"
110                data-test-id="userManagement-select-privilege"
111                :state="getValidationState($v.form.privilege)"
112                @input="$v.form.privilege.$touch()"
113              >
114                <template #first>
115                  <b-form-select-option :value="null" disabled>
116                    {{ $t('global.form.selectAnOption') }}
117                  </b-form-select-option>
118                </template>
119              </b-form-select>
120              <b-form-invalid-feedback role="alert">
121                <template v-if="!$v.form.privilege.required">
122                  {{ $t('global.form.fieldRequired') }}
123                </template>
124              </b-form-invalid-feedback>
125            </b-form-group>
126          </b-col>
127          <b-col>
128            <b-form-group
129              :label="$t('pageUserManagement.modal.userPassword')"
130              label-for="password"
131            >
132              <b-form-text id="password-help-block">
133                {{
134                  $t('pageUserManagement.modal.passwordMustBeBetween', {
135                    min: passwordRequirements.minLength,
136                    max: passwordRequirements.maxLength,
137                  })
138                }}
139              </b-form-text>
140              <input-password-toggle>
141                <b-form-input
142                  id="password"
143                  v-model="form.password"
144                  type="password"
145                  data-test-id="userManagement-input-password"
146                  aria-describedby="password-help-block"
147                  :state="getValidationState($v.form.password)"
148                  class="form-control-with-button"
149                  @input="$v.form.password.$touch()"
150                />
151                <b-form-invalid-feedback role="alert">
152                  <template v-if="!$v.form.password.required">
153                    {{ $t('global.form.fieldRequired') }}
154                  </template>
155                  <template
156                    v-if="
157                      !$v.form.password.minLength || !$v.form.password.maxLength
158                    "
159                  >
160                    {{
161                      $t('pageUserManagement.modal.passwordMustBeBetween', {
162                        min: passwordRequirements.minLength,
163                        max: passwordRequirements.maxLength,
164                      })
165                    }}
166                  </template>
167                </b-form-invalid-feedback>
168              </input-password-toggle>
169            </b-form-group>
170            <b-form-group
171              :label="$t('pageUserManagement.modal.confirmUserPassword')"
172              label-for="password-confirmation"
173            >
174              <input-password-toggle>
175                <b-form-input
176                  id="password-confirmation"
177                  v-model="form.passwordConfirmation"
178                  data-test-id="userManagement-input-passwordConfirmation"
179                  type="password"
180                  :state="getValidationState($v.form.passwordConfirmation)"
181                  class="form-control-with-button"
182                  @input="$v.form.passwordConfirmation.$touch()"
183                />
184                <b-form-invalid-feedback role="alert">
185                  <template v-if="!$v.form.passwordConfirmation.required">
186                    {{ $t('global.form.fieldRequired') }}
187                  </template>
188                  <template
189                    v-else-if="!$v.form.passwordConfirmation.sameAsPassword"
190                  >
191                    {{ $t('pageUserManagement.modal.passwordsDoNotMatch') }}
192                  </template>
193                </b-form-invalid-feedback>
194              </input-password-toggle>
195            </b-form-group>
196          </b-col>
197        </b-row>
198      </b-container>
199    </b-form>
200    <template #modal-footer="{ cancel }">
201      <b-button
202        variant="secondary"
203        data-test-id="userManagement-button-cancel"
204        @click="cancel()"
205      >
206        {{ $t('global.action.cancel') }}
207      </b-button>
208      <b-button
209        form="form-user"
210        data-test-id="userManagement-button-submit"
211        type="submit"
212        variant="primary"
213        @click="onOk"
214      >
215        <template v-if="newUser">
216          {{ $t('pageUserManagement.addUser') }}
217        </template>
218        <template v-else>
219          {{ $t('global.action.save') }}
220        </template>
221      </b-button>
222    </template>
223  </b-modal>
224</template>
225
226<script>
227import {
228  required,
229  maxLength,
230  minLength,
231  sameAs,
232  helpers,
233  requiredIf,
234} from 'vuelidate/lib/validators';
235import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
236import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
237import Alert from '@/components/Global/Alert';
238
239export default {
240  components: { Alert, InputPasswordToggle },
241  mixins: [VuelidateMixin],
242  props: {
243    user: {
244      type: Object,
245      default: null,
246    },
247    passwordRequirements: {
248      type: Object,
249      required: true,
250    },
251  },
252  data() {
253    return {
254      originalUsername: '',
255      form: {
256        status: true,
257        username: '',
258        privilege: null,
259        password: '',
260        passwordConfirmation: '',
261        manualUnlock: false,
262      },
263      disabled: this.$store.getters['global/username'],
264    };
265  },
266  computed: {
267    newUser() {
268      return this.user ? false : true;
269    },
270    accountSettings() {
271      return this.$store.getters['userManagement/accountSettings'];
272    },
273    manualUnlockPolicy() {
274      return !this.accountSettings.accountLockoutDuration;
275    },
276    privilegeTypes() {
277      return this.$store.getters['userManagement/accountRoles'];
278    },
279  },
280  watch: {
281    user: function (value) {
282      if (value === null) return;
283      this.originalUsername = value.username;
284      this.form.username = value.username;
285      this.form.status = value.Enabled;
286      this.form.privilege = value.privilege;
287    },
288  },
289  validations() {
290    return {
291      form: {
292        status: {
293          required,
294        },
295        username: {
296          required,
297          maxLength: maxLength(16),
298          pattern: helpers.regex('pattern', /^([a-zA-Z_][a-zA-Z0-9_]*)/),
299        },
300        privilege: {
301          required,
302        },
303        password: {
304          required: requiredIf(function () {
305            return this.requirePassword();
306          }),
307          minLength: minLength(this.passwordRequirements.minLength),
308          maxLength: maxLength(this.passwordRequirements.maxLength),
309        },
310        passwordConfirmation: {
311          required: requiredIf(function () {
312            return this.requirePassword();
313          }),
314          sameAsPassword: sameAs('password'),
315        },
316        manualUnlock: {},
317      },
318    };
319  },
320  methods: {
321    handleSubmit() {
322      let userData = {};
323
324      if (this.newUser) {
325        this.$v.$touch();
326        if (this.$v.$invalid) return;
327        userData.username = this.form.username;
328        userData.status = this.form.status;
329        userData.privilege = this.form.privilege;
330        userData.password = this.form.password;
331      } else {
332        if (this.$v.$invalid) return;
333        userData.originalUsername = this.originalUsername;
334        if (this.$v.form.status.$dirty) {
335          userData.status = this.form.status;
336        }
337        if (this.$v.form.username.$dirty) {
338          userData.username = this.form.username;
339        }
340        if (this.$v.form.privilege.$dirty) {
341          userData.privilege = this.form.privilege;
342        }
343        if (this.$v.form.password.$dirty) {
344          userData.password = this.form.password;
345        }
346        if (this.$v.form.manualUnlock.$dirty) {
347          // If form manualUnlock control $dirty then
348          // set user Locked property to false
349          userData.locked = false;
350        }
351        if (Object.entries(userData).length === 1) {
352          this.closeModal();
353          return;
354        }
355      }
356
357      this.$emit('ok', { isNewUser: this.newUser, userData });
358      this.closeModal();
359    },
360    closeModal() {
361      this.$nextTick(() => {
362        this.$refs.modal.hide();
363      });
364    },
365    resetForm() {
366      this.form.originalUsername = '';
367      this.form.status = true;
368      this.form.username = '';
369      this.form.privilege = null;
370      this.form.password = '';
371      this.form.passwordConfirmation = '';
372      this.$v.$reset();
373      this.$emit('hidden');
374    },
375    requirePassword() {
376      if (this.newUser) return true;
377      if (this.$v.form.password.$dirty) return true;
378      if (this.$v.form.passwordConfirmation.$dirty) return true;
379      return false;
380    },
381    onOk(bvModalEvt) {
382      // prevent modal close
383      bvModalEvt.preventDefault();
384      this.handleSubmit();
385    },
386  },
387};
388</script>
389