MT#60689 Add change password page for CSC

The backend returns "403 - Password Expired" when user's
password is too old and we redirect the user to the
/changepassword page where they can update their pw.
Users will be required to insert username, current password,
new password and to retype the new one.
Success: user redirected to login page.
Failure: a banner with the error is shown for 10 seconds.
NOTE:
* Password requirements are always presented in the frontend
  as guidelines but validations are not enforced.
  It was a joint decision with the backend team not to expose
  whether the web_validation is active on the platform.
* If the web_validation is active, the backend will respond
  with a 422 and the error message will describe the missed
  password requirements.

Change-Id: Ic8b34980ff3099712f72042294409a2eb8e9347f
mr13.1
Debora Crescenzo 7 months ago
parent 95e93e0365
commit 46357637cd

@ -12,6 +12,7 @@ import { getCurrentLangAsV1Format } from 'src/i18n'
import { i18n } from 'src/boot/i18n'
import saveAs from 'file-saver'
import { PATH_CHANGE_PASSWORD } from 'src/router/routes'
export const LIST_DEFAULT_PAGE = 1
export const LIST_DEFAULT_ROWS = 24
export const LIST_ALL_ROWS = 1000
@ -177,6 +178,11 @@ function handleResponseError (err) {
if (code === 403 && message === 'Invalid license') {
message = i18n.global.tc('Contact your administrator to activate this functionality')
}
if (code === 403 && message === 'Password expired') {
message = i18n.global.tc('Password Expired')
return this.$router.push({ path: PATH_CHANGE_PASSWORD })
}
if (code !== null && message !== null) {
throw new ApiResponseError(code, message)
}

@ -1,5 +1,6 @@
import _ from 'lodash'
import { i18n } from 'boot/i18n'
import {
get,
post,
@ -51,6 +52,15 @@ export async function loginByExchangeToken (token) {
}
}
export async function getPreLoginPasswordInfo () {
try {
const res = await httpApi.get('api/platforminfo')
return res.data.security.password
} catch (err) {
throw new Error(err.response.data.message)
}
}
export async function getUserData (id) {
const allPromise = Promise.all([
getSubscriberById(id),
@ -167,6 +177,29 @@ export async function getPlatformInfo () {
})
}
export function changeExpiredPassword (payload) {
return new Promise((resolve, reject) => {
httpApi.post('/api/passwordchange/', {
new_password: payload.new_password
}, {
auth: {
username: payload.username,
password: payload.old_password
}
}).then((result) => {
resolve(result)
}).catch((err) => {
if (err.response.status === 401) {
reject(`Unauthorized. ${i18n.global.tc('Wrong username or password')}`)
} else if (err.response.status === 422) {
reject(_formatPasswordError(err.response.data.message))
} else {
reject('Unexpected error')
}
})
})
}
export async function createAuthToken (tokenExpiringTime) {
const response = await post({
resource: 'authtokens',
@ -177,3 +210,7 @@ export async function createAuthToken (tokenExpiringTime) {
})
return response.token
}
function _formatPasswordError (error) {
return error.split("'").slice(-2, -1)[0].replaceAll(',', ', ')
}

@ -9,7 +9,7 @@ import {
export default ({ app, router, store }) => {
router.beforeEach((to, from, next) => {
const publicUrls = ['/login', '/recoverpassword']
const publicUrls = ['/login', '/recoverpassword', '/changepassword']
// not authorized user
if (!hasJwt()) {
if (!publicUrls.includes(to.path)) {

@ -58,6 +58,7 @@
"Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Ausgehende Anrufe blockieren",
"Block anonymous inbound calls": "Block anonymous inbound calls",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Begrüßung, wenn besetzt",
"Busy Lamp Field": "Besetztlampenfeld",
"CDR": "CDR",
@ -107,7 +108,7 @@
"Conference name": "Konferenzname",
"Confirm": "Bestätigen",
"Contact": "Kontakt",
"Contact your administrator to activate this functionality":"Zur Aktivierung dieser Funktion kontaktieren Sie Ihren Administrator.",
"Contact your administrator to activate this functionality": "Zur Aktivierung dieser Funktion kontaktieren Sie Ihren Administrator.",
"Content": "Inhalt",
"Conversations": "Konversationen",
"Copy link": "Link kopieren",
@ -119,6 +120,7 @@
"Create Call Queue": "Anrufwarteschlange hinzufügen",
"Create Config": "Konfiguration hinzufügen",
"Create List": "Liste erstellen",
"Create New Password": "Create New Password",
"Create destination": "Ziel erstellen",
"Create device": "Gerät hinzufügen",
"Create group": "Gruppe hinzufügen",
@ -128,6 +130,7 @@
"Created device {device} successfully": "Gerät {device} hinzugefügt",
"Created manager secretary config for {msConfig} successfully": "Konfiguration für {msConfig} hinzugefügt",
"Created sound set {soundSet} successfully": "Sound-Set {soundSet} hinzugefügt",
"Current Password": "Current Password",
"Custom Announcement": "Benutzerdefinierte Ansage",
"Custom Announcements": "Individuelle Ansagen",
"Custom sound": "Benutzerdefinierter Sound",
@ -300,6 +303,7 @@
"Ncos Set": "Ncos Set",
"Never": "Nie",
"New Messages": "Neue Nachrichten",
"New Password": "New Password",
"New SIP Password": "Neues SIP-Passwort",
"New SIP Password confirm": "Neues SIP-Passwort bestätigen",
"New Web Password": "Neues Web-Passwort",
@ -356,10 +360,18 @@
"Parallel Ringing": "Paralleles Klingeln",
"Parent": "Eltern",
"Password": "Passwort",
"Password Expired": "Password Expired",
"Password Retype": "Passwort-Neueingabe",
"Password changed successfully": "Passwort erfolgreich geändert",
"Password confirm": "Passwort bestätigen",
"Password is considered weak": "Password is considered weak",
"Password is not strong enough": "Passwort ist nicht sicher genug",
"Password is not strong enough, add more digits": "Password is not strong enough, add more digits",
"Password is not strong enough, add more lowercase letters": "Password is not strong enough, add more lowercase letters",
"Password is not strong enough, add more special characters": "Password is not strong enough, add more special characters",
"Password is not strong enough, add more uppercase letters": "Password is not strong enough, add more uppercase letters",
"Password must be at least {max} characters long": "Password must be at least {max} characters long",
"Password must be at least {min} characters long": "Password must be at least {min} characters long",
"Passwords must be equal": "Passwörter müssen übereinstimmen",
"Phone model": "Telefonmodell",
"Phone number": "Rufnummer",
@ -602,6 +614,7 @@
"Your number is visible to the callee": "Rufnummer wird dem Angerufenen angezeigt",
"Your number is visible to the callee within own PBX": "Ihre Rufnummer wird dem Angerufenen bei PBX-internen Verbindungen angezeigt",
"Your password has been changed successfully": "Ihr Passwort wurde erfolgreich geändert",
"Your password has expired": "Your password has expired",
"Your web password has been changed successfully": "Ihr Web-Passwort wurde erfolgreich geändert",
"ago": "vor",
"and": "und",

@ -57,6 +57,7 @@
"Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Block Outgoing",
"Block anonymous inbound calls": "Block anonymous inbound calls",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Busy Greeting",
"Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR",
@ -105,7 +106,7 @@
"Conference": "Conference",
"Confirm": "Confirm",
"Contact": "Contact",
"Contact your administrator to activate this functionality":"Contact your administrator to activate this functionality",
"Contact your administrator to activate this functionality": "Contact your administrator to activate this functionality",
"Content": "Content",
"Conversations": "Conversations",
"Cost": "Cost",
@ -116,6 +117,7 @@
"Create Call Queue": "Create Call Queue",
"Create Config": "Create Config",
"Create List": "Create List",
"Create New Password": "Create New Password",
"Create destination": "Create destination",
"Create device": "Create device",
"Create group": "Create group",
@ -125,6 +127,7 @@
"Created device {device} successfully": "Created device {device} successfully",
"Created manager secretary config for {msConfig} successfully": "Created manager secretary config for {msConfig} successfully",
"Created sound set {soundSet} successfully": "Created sound set {soundSet} successfully",
"Current Password": "Current Password",
"Custom Announcement": "Custom Announcement",
"Custom Announcements": "Custom Announcements",
"Custom sound": "Custom sound",
@ -288,6 +291,7 @@
"Ncos": "Ncos",
"Ncos Set": "Ncos Set",
"Never": "Never",
"New Password": "New Password",
"New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password",
@ -342,10 +346,18 @@
"Parallel Ringing": "Parallel Ringing",
"Parent": "Parent",
"Password": "Password",
"Password Expired": "Password Expired",
"Password Retype": "Password Retype",
"Password changed successfully": "Password changed successfully",
"Password confirm": "Password confirm",
"Password is considered weak": "Password is considered weak",
"Password is not strong enough": "Password is not strong enough",
"Password is not strong enough, add more digits": "Password is not strong enough, add more digits",
"Password is not strong enough, add more lowercase letters": "Password is not strong enough, add more lowercase letters",
"Password is not strong enough, add more special characters": "Password is not strong enough, add more special characters",
"Password is not strong enough, add more uppercase letters": "Password is not strong enough, add more uppercase letters",
"Password must be at least {max} characters long": "Password must be at least {max} characters long",
"Password must be at least {min} characters long": "Password must be at least {min} characters long",
"Passwords must be equal": "Passwords must be equal",
"Phone model": "Phone model",
"Phone number": "Phone number",
@ -581,6 +593,7 @@
"Your number is hidden to the callee within own PBX": "Your number is hidden to the callee within own PBX",
"Your number is visible to the callee": "Your number is visible to the callee",
"Your number is visible to the callee within own PBX": "Your number is visible to the callee within own PBX",
"Your password has expired": "Your password has expired",
"ago": "ago",
"and": "and",
"and call from": "and call from",

@ -58,6 +58,7 @@
"Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Bloquear Salientes",
"Block anonymous inbound calls": "Block anonymous inbound calls",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Saludo de Ocupado",
"Busy Lamp Field": "Campo de lámpara ocupado",
"CDR": "CDR",
@ -107,7 +108,7 @@
"Conference name": "Nombre de la conferencia",
"Confirm": "Confirmar",
"Contact": "Contacto",
"Contact your administrator to activate this functionality":"Póngase en contacto con su administrador para activar esta funcionalidad",
"Contact your administrator to activate this functionality": "Póngase en contacto con su administrador para activar esta funcionalidad",
"Content": "Contenido",
"Conversations": "Conversaciones",
"Copy link": "Copiar enlace",
@ -119,6 +120,7 @@
"Create Call Queue": "Crear Cola de Llamadas",
"Create Config": "Crear Configuración",
"Create List": "Crear Lista",
"Create New Password": "Create New Password",
"Create destination": "Crear destino",
"Create device": "Crear dispositivo",
"Create group": "Crear grupo",
@ -128,6 +130,7 @@
"Created device {device} successfully": "Dispositivo {device} creado exitosamente",
"Created manager secretary config for {msConfig} successfully": "Se creó exitosamente la configuración de Jefe-Asistente para {msConfig}",
"Created sound set {soundSet} successfully": "Conjunto de sonido {soundSet} creado exitosamente",
"Current Password": "Current Password",
"Custom Announcement": "Anuncio Personalizado",
"Custom Announcements": "Anuncios Personalizados",
"Custom sound": "Sonido personalizado",
@ -301,6 +304,7 @@
"Ncos Set": "Ncos Set",
"Never": "Nunca",
"New Messages": "Nuevos Mensajes",
"New Password": "New Password",
"New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password",
@ -355,10 +359,18 @@
"Parallel Ringing": "Llamada en paralelo",
"Parent": "Parent",
"Password": "Contraseña",
"Password Expired": "Password Expired",
"Password Retype": "Repetir contraseña",
"Password changed successfully": "La contraseña ha sido cambiada correctamente.",
"Password confirm": "Password confirm",
"Password is considered weak": "Password is considered weak",
"Password is not strong enough": "La contraseña no es lo suficientemente fuerte",
"Password is not strong enough, add more digits": "Password is not strong enough, add more digits",
"Password is not strong enough, add more lowercase letters": "Password is not strong enough, add more lowercase letters",
"Password is not strong enough, add more special characters": "Password is not strong enough, add more special characters",
"Password is not strong enough, add more uppercase letters": "Password is not strong enough, add more uppercase letters",
"Password must be at least {max} characters long": "Password must be at least {max} characters long",
"Password must be at least {min} characters long": "Password must be at least {min} characters long",
"Passwords must be equal": "Las contraseñas deben ser iguales",
"Phone model": "Modelo de teléfono",
"Phone number": "Número de teléfono",
@ -606,6 +618,7 @@
"Your number is visible to the callee": "Su número es visible para la persona que llama",
"Your number is visible to the callee within own PBX": "Su número es visible para el receptor de la llamada en su propia centralita.",
"Your password has been changed successfully": "Su contraseña ha sido cambiada exitosamente",
"Your password has expired": "Your password has expired",
"ago": "atrás",
"and": "y",
"and call from": "y llamar desde",

@ -58,6 +58,7 @@
"Block Mode for outbounds calls": "Mode blocage pour les appels sortants",
"Block Outgoing": "Bloquer les sortants",
"Block anonymous inbound calls": "Bloquer les appels entrants anonymes",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Message d'accueil en cas d'occupation",
"Busy Lamp Field": "Champ de la lampe occupée",
"CDR": "CDR",
@ -107,7 +108,7 @@
"Conference name": "Nom de la conférence",
"Confirm": "Confirmer",
"Contact": "Contact",
"Contact your administrator to activate this functionality":"Contactez votre administrateur pour activer cette fonctionnalité",
"Contact your administrator to activate this functionality": "Contactez votre administrateur pour activer cette fonctionnalité",
"Content": "Contenu",
"Conversations": "Conversations",
"Copy link": "Copier le lien",
@ -119,6 +120,7 @@
"Create Call Queue": "Créer une file dattente",
"Create Config": "Créer Configuration",
"Create List": "Créer une liste",
"Create New Password": "Create New Password",
"Create destination": "Créer une destination",
"Create device": "Créer un appareil",
"Create group": "Créer un groupe",
@ -128,6 +130,7 @@
"Created device {device} successfully": "Le poste {device} a été créé avec succès",
"Created manager secretary config for {msConfig} successfully": "Création réussie de la configuration du secrétaire du gestionnaire pour {msConfig}",
"Created sound set {soundSet} successfully": "Création du jeu de sons {soundSet} avec succès",
"Current Password": "Current Password",
"Custom Announcement": "Annonce personnalisée",
"Custom Announcements": "Annonces personnalisées",
"Custom sound": "Son personnalisé",
@ -300,6 +303,7 @@
"Ncos Set": "Ncos Set",
"Never": "Jamais",
"New Messages": "Nouveaux messages",
"New Password": "New Password",
"New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password",
@ -356,10 +360,18 @@
"Parallel Ringing": "Sonnerie parallèle",
"Parent": "Parent",
"Password": "Mot de passe",
"Password Expired": "Password Expired",
"Password Retype": "Retaper le mot de passe",
"Password changed successfully": "Le mot de passe a été modifié avec succès",
"Password confirm": "Password confirm",
"Password is considered weak": "Password is considered weak",
"Password is not strong enough": "Le mot de passe n'est pas assez fort",
"Password is not strong enough, add more digits": "Password is not strong enough, add more digits",
"Password is not strong enough, add more lowercase letters": "Password is not strong enough, add more lowercase letters",
"Password is not strong enough, add more special characters": "Password is not strong enough, add more special characters",
"Password is not strong enough, add more uppercase letters": "Password is not strong enough, add more uppercase letters",
"Password must be at least {max} characters long": "Password must be at least {max} characters long",
"Password must be at least {min} characters long": "Password must be at least {min} characters long",
"Passwords must be equal": "Les mots de passe doivent être égaux",
"Phone model": "Modèle du poste",
"Phone number": "Numéro de téléphone",
@ -602,6 +614,7 @@
"Your number is visible to the callee": "Votre numéro est visible par le destinataire de l'appel",
"Your number is visible to the callee within own PBX": "Votre numéro est visible par appelant dans son propre PBX",
"Your password has been changed successfully": "Votre mot de passe a été modifié avec succès",
"Your password has expired": "Your password has expired",
"ago": ".",
"and": "et",
"and call from": "et appeler de",

@ -56,6 +56,7 @@
"Block Mode for outbounds calls": "Modalità di blocco per le chiamate in uscita",
"Block Outgoing": "Blocca chiamate in uscita",
"Block anonymous inbound calls": "Blocca chiamate anonime in entrata",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Messaggio per numero occupato",
"Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR",
@ -117,6 +118,7 @@
"Create Call Queue": "Crea coda chiamate",
"Create Config": "Crea configurazione",
"Create List": "Crea lista",
"Create New Password": "Create New Password",
"Create destination": "Crea destinazione",
"Create device": "Crea dispositivo",
"Create group": "Crea gruppo",
@ -126,6 +128,7 @@
"Created device {device} successfully": "Dispositivo {device} creato correttamente",
"Created manager secretary config for {msConfig} successfully": "Configurazione segreteria per {msConfig} creata correttamente",
"Created sound set {soundSet} successfully": "Set di messaggi audio {soundSet} creato correttamente",
"Current Password": "Current Password",
"Custom Announcement": "Custom Announcement",
"Custom Announcements": "Custom Announcements",
"Custom sound": "Audio personalizzato",
@ -292,6 +295,7 @@
"Ncos Set": "Ncos Set",
"Never": "Never",
"New Messages": "Nuovi messaggi",
"New Password": "New Password",
"New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password",
@ -348,10 +352,18 @@
"Parallel Ringing": "Squilli in parallelo",
"Parent": "Parent",
"Password": "Password",
"Password Expired": "Password Expired",
"Password Retype": "Password Retype",
"Password changed successfully": "Password changed successfully",
"Password confirm": "Password confirm",
"Password is considered weak": "Password is considered weak",
"Password is not strong enough": "Password is not strong enough",
"Password is not strong enough, add more digits": "Password is not strong enough, add more digits",
"Password is not strong enough, add more lowercase letters": "Password is not strong enough, add more lowercase letters",
"Password is not strong enough, add more special characters": "Password is not strong enough, add more special characters",
"Password is not strong enough, add more uppercase letters": "Password is not strong enough, add more uppercase letters",
"Password must be at least {max} characters long": "Password must be at least {max} characters long",
"Password must be at least {min} characters long": "Password must be at least {min} characters long",
"Passwords must be equal": "Le passwords devono essere identiche",
"Phone model": "Modello telefono",
"Phone number": "Numero di telefono",
@ -590,6 +602,7 @@
"Your number is visible to the callee": "Il tuo numero è visible al chiamato",
"Your number is visible to the callee within own PBX": "Your number is visible to the callee within own PBX",
"Your password has been changed successfully": "Password modificata",
"Your password has expired": "Your password has expired",
"ago": "fa",
"and": "e",
"and call from": "and call from",

@ -0,0 +1,293 @@
<template>
<q-layout
id="csc-layout-login"
view="lHh lpR lFf"
class="bg-page"
>
<q-header
id="csc-header-login"
class="bg-transparent"
>
<q-toolbar
id="csc-header-toolbar-login"
>
<csc-selection-language />
</q-toolbar>
</q-header>
<q-page-container>
<q-page
id="csc-page-login"
class="flex flex-center row"
>
<q-card
id="csc-login-card"
class="bg-main-menu no-shadow no-border-radius col-xs-12 col-sm-6 col-md-4 q-pa-sm"
>
<q-card-section class="text-h5 text-center">
{{ $t('Create New Password') }}
</q-card-section>
<q-card-section>
<q-banner
dense
inline-actions
class="text-white text-center bg-red-14"
>
{{ $t('Your password has expired') }}
</q-banner>
</q-card-section>
<q-card-section>
<div
v-if="validationGuidelines && validationGuidelines.length > 0"
inline-actions
class="q-mb-md q-pa-md"
>
<p>Suggested password format:</p>
<q-item
v-for="(message, index) in validationGuidelines"
:key="index"
dense
>
<q-item-section>
<span>
<q-icon
name="lock"
size="1em"
class="q-pa-xs"
/> {{ message }}
</span>
</q-item-section>
</q-item>
</div>
</q-card-section>
<q-card-section>
<q-form key="login-form">
<csc-input
v-model.trim="username"
outlined
:label="$t('Username')"
data-cy="csc-login-username"
:error="v$.username && v$.username.$errors.length > 0"
:error-message="$errMsg(v$.username.$errors)"
@keyup.enter="changePasswordAction"
>
<template
#prepend
>
<q-icon
name="person"
/>
</template>
</csc-input>
<csc-input-password
v-model.trim="currentPassword"
outlined
clearable
:label="$t('Current Password')"
data-cy="csc-login-password"
:error="v$.currentPassword && v$.currentPassword.$errors.length > 0"
:error-message="$errMsg(v$.currentPassword.$errors)"
@keyup.enter="changePasswordAction"
/>
<csc-input-password
v-model.trim="newPassword"
outlined
clearable
:label="$t('New Password')"
data-cy="csc-login-password"
:error="v$.newPassword && v$.newPassword.$errors.length > 0"
:error-message="$errMsg(v$.newPassword.$errors)"
@keyup.enter="changePasswordAction"
/>
<csc-input
ref="passwordRetypeInput"
v-model.trim="passwordRetype"
outlined
clearable
icon="lock"
color="secondary"
:label="$t('Password Retype')"
data-cy="password-retype-field"
type="password"
autocomplete="new-password"
:error="v$.passwordRetype && v$.passwordRetype.$errors.length > 0"
:error-message="$errMsg(v$.passwordRetype.$errors)"
@keyup.enter="changePasswordAction"
>
<template
#prepend
>
<q-icon
name="lock"
/>
</template>
</csc-input>
<div class="row justify-center q-pa-md">
<q-btn
data-cy="sign-in"
unelevated
color="primary"
icon="arrow_forward"
:label="$t('Change Password')"
@click="changePasswordAction"
/>
</div>
</q-form>
</q-card-section>
</q-card>
</q-page>
</q-page-container>
</q-layout>
</template>
<script>
import useValidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import { mapActions, mapState } from 'vuex'
import CscSelectionLanguage from 'src/components/CscSelectionLanguage.vue'
import CscInput from 'src/components/form/CscInput.vue'
import CscInputPassword from 'src/components/form/CscInputPassword.vue'
import { RequestState } from 'src/store/common'
import { mapWaitingActions } from 'vue-wait'
export default {
name: 'ChangeExpiredPassword',
components: {
CscSelectionLanguage,
CscInput,
CscInputPassword
},
data () {
return {
v$: useValidate(),
username: '',
currentPassword: '',
newPassword: '',
passwordStrengthScore: null,
passwordRetype: '',
validationGuidelines: []
}
},
validations () {
return {
username: {
required
},
currentPassword: {
required
},
newPassword: {
required
},
passwordRetype: {
sameAsPassword (val) {
return val === this.newPassword
}
}
}
},
computed: {
...mapState('user', [
'changePasswordState',
'changePasswordError'
])
},
watch: {
changePasswordState (state) {
if (state === RequestState.succeeded) {
this.$q.notify({
position: 'top',
color: 'positive',
icon: 'check',
message: this.$t('Password changed successfully')
})
this.redirectToLogin()
} else if (state === RequestState.failed) {
this.$q.notify({
position: 'top',
color: 'negative',
icon: 'error',
timeout: 10000,
message: this.changePasswordError || this.$t('There was an error, please retry later')
})
}
}
},
async mounted () {
const guidelines = await this.getValidationGuidelines()
this.validationGuidelines = this.formatValidationGuidelines(guidelines)
},
methods: {
...mapWaitingActions('user', [
'fetchPreLoginPasswordInfo'
]),
...mapActions('user', [
'changeExpiredPassword'
]),
strengthMeterScoreUpdate (score) {
this.passwordStrengthScore = score
},
async changePasswordAction () {
this.v$.$touch()
if (this.v$.$errors.length === 0) {
return this.changeExpiredPassword({
username: this.username,
old_password: this.currentPassword,
new_password: this.newPassword
})
}
},
formatValidationGuidelines (validationRulesObject) {
const guidelines = []
for (const rule in validationRulesObject) {
switch (rule) {
case 'min_length':
guidelines.push(`Minimum ${validationRulesObject[rule]} characters long.`)
break
case 'max_length':
guidelines.push(`Maximum ${validationRulesObject[rule]} characters long.`)
break
case 'musthave_digit':
guidelines.push(`Contains a minimum of ${validationRulesObject[rule]} digits.`)
break
case 'musthave_lowercase':
guidelines.push(`Contains a minimum of ${validationRulesObject[rule]} lowercases.`)
break
case 'musthave_specialchar':
guidelines.push(`Contains a minimum of ${validationRulesObject[rule]} special characters.`)
break
case 'musthave_uppercase':
guidelines.push(`Contains a minimum of ${validationRulesObject[rule]} uppercases.`)
break
default:
}
}
return guidelines
},
async getValidationGuidelines () {
const defaultGuidelines = {
max_length: 40,
min_length: 12,
musthave_digit: 3,
musthave_lowercase: 3,
musthave_specialchar: 3,
musthave_uppercase: 3
}
const customGuidelines = await this.fetchPreLoginPasswordInfo()
return customGuidelines ?? defaultGuidelines
},
redirectToLogin () {
this.$router.push({ path: '/login' })
}
}
}
</script>
<style>
</style>

@ -157,7 +157,7 @@ export default {
},
loginError (error) {
if (error) {
showGlobalError(this.$t('Wrong username or password'))
showGlobalError(error)
}
}
},

@ -8,6 +8,7 @@ import CscPageCallBlockingPrivacy from 'src/pages/CscPageCallBlockingPrivacy'
import CscPageCallRecording from 'src/pages/CscPageCallRecording'
import CscPageCallSettings from 'pages/CscPageCallSettings'
import CscPageCf from 'pages/CscPageCf'
import CscPageChangePassword from 'src/pages/CscChangeExpiredPassword.vue'
import CscPageConversations from 'src/pages/CscPageConversations'
import CscPageCustomerPhonebook from 'src/pages/CscPageCustomerPhonebook'
import CscPageCustomerPhonebookAdd from 'src/pages/CscPageCustomerPhonebookAdd'
@ -45,6 +46,8 @@ import CscRecoverPassword from 'src/pages/CscRecoverPassword'
import CscPageCustomerPreferences from 'src/pages/CscPageCustomerPreferences'
import { i18n } from 'src/boot/i18n'
export const PATH_CHANGE_PASSWORD = '/changepassword'
const getToken = (route) => {
return {
token: route.query.token
@ -543,6 +546,11 @@ const routes = [
}
}
},
{
name: 'passwordChange',
path: PATH_CHANGE_PASSWORD,
component: CscPageChangePassword
},
{
path: '/recoverpassword',
component: CscLayoutLogin,

@ -6,7 +6,9 @@ import {
import {
login,
getUserData,
createAuthToken
createAuthToken,
changeExpiredPassword,
getPreLoginPasswordInfo
} from '../api/user'
import {
changePassword,
@ -46,6 +48,7 @@ import {
httpApi,
apiDownloadFile
} from 'src/api/common'
import { PATH_CHANGE_PASSWORD } from 'src/router/routes'
export default {
namespaced: true,
@ -340,6 +343,9 @@ export default {
await this.$router.push({ name: 'dashboard' })
} catch (err) {
context.commit('loginFailed', err.message)
if (err.message === 'Password expired') {
this.$router.push({ path: PATH_CHANGE_PASSWORD })
}
}
},
logout () {
@ -378,6 +384,16 @@ export default {
}
}
},
async changeExpiredPassword (context, newPassword) {
context.commit('userPasswordRequesting')
try {
await changeExpiredPassword(newPassword)
} catch (error) {
return context.commit('userPasswordFailed', error)
}
context.commit('userPasswordSucceeded')
},
async changePassword (context, newPassword) {
const subscriberId = getSubscriberId()
await changePassword(subscriberId, newPassword)
@ -572,6 +588,9 @@ export default {
commit('setQrCode', null)
}
},
async fetchPreLoginPasswordInfo () {
return await getPreLoginPasswordInfo()
},
async generatePasswordUser () {
const password = await generateGeneralPassword()

Loading…
Cancel
Save