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 2 years ago
parent 95e93e0365
commit 46357637cd

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

@ -1,5 +1,6 @@
import _ from 'lodash' import _ from 'lodash'
import { i18n } from 'boot/i18n'
import { import {
get, get,
post, 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) { export async function getUserData (id) {
const allPromise = Promise.all([ const allPromise = Promise.all([
getSubscriberById(id), 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) { export async function createAuthToken (tokenExpiringTime) {
const response = await post({ const response = await post({
resource: 'authtokens', resource: 'authtokens',
@ -177,3 +210,7 @@ export async function createAuthToken (tokenExpiringTime) {
}) })
return response.token return response.token
} }
function _formatPasswordError (error) {
return error.split("'").slice(-2, -1)[0].replaceAll(',', ', ')
}

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

@ -58,6 +58,7 @@
"Block Mode for outbounds calls": "Block Mode for outbounds calls", "Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Ausgehende Anrufe blockieren", "Block Outgoing": "Ausgehende Anrufe blockieren",
"Block anonymous inbound calls": "Block anonymous inbound calls", "Block anonymous inbound calls": "Block anonymous inbound calls",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Begrüßung, wenn besetzt", "Busy Greeting": "Begrüßung, wenn besetzt",
"Busy Lamp Field": "Besetztlampenfeld", "Busy Lamp Field": "Besetztlampenfeld",
"CDR": "CDR", "CDR": "CDR",
@ -107,7 +108,7 @@
"Conference name": "Konferenzname", "Conference name": "Konferenzname",
"Confirm": "Bestätigen", "Confirm": "Bestätigen",
"Contact": "Kontakt", "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", "Content": "Inhalt",
"Conversations": "Konversationen", "Conversations": "Konversationen",
"Copy link": "Link kopieren", "Copy link": "Link kopieren",
@ -119,6 +120,7 @@
"Create Call Queue": "Anrufwarteschlange hinzufügen", "Create Call Queue": "Anrufwarteschlange hinzufügen",
"Create Config": "Konfiguration hinzufügen", "Create Config": "Konfiguration hinzufügen",
"Create List": "Liste erstellen", "Create List": "Liste erstellen",
"Create New Password": "Create New Password",
"Create destination": "Ziel erstellen", "Create destination": "Ziel erstellen",
"Create device": "Gerät hinzufügen", "Create device": "Gerät hinzufügen",
"Create group": "Gruppe hinzufügen", "Create group": "Gruppe hinzufügen",
@ -128,6 +130,7 @@
"Created device {device} successfully": "Gerät {device} hinzugefügt", "Created device {device} successfully": "Gerät {device} hinzugefügt",
"Created manager secretary config for {msConfig} successfully": "Konfiguration für {msConfig} 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", "Created sound set {soundSet} successfully": "Sound-Set {soundSet} hinzugefügt",
"Current Password": "Current Password",
"Custom Announcement": "Benutzerdefinierte Ansage", "Custom Announcement": "Benutzerdefinierte Ansage",
"Custom Announcements": "Individuelle Ansagen", "Custom Announcements": "Individuelle Ansagen",
"Custom sound": "Benutzerdefinierter Sound", "Custom sound": "Benutzerdefinierter Sound",
@ -300,6 +303,7 @@
"Ncos Set": "Ncos Set", "Ncos Set": "Ncos Set",
"Never": "Nie", "Never": "Nie",
"New Messages": "Neue Nachrichten", "New Messages": "Neue Nachrichten",
"New Password": "New Password",
"New SIP Password": "Neues SIP-Passwort", "New SIP Password": "Neues SIP-Passwort",
"New SIP Password confirm": "Neues SIP-Passwort bestätigen", "New SIP Password confirm": "Neues SIP-Passwort bestätigen",
"New Web Password": "Neues Web-Passwort", "New Web Password": "Neues Web-Passwort",
@ -356,10 +360,18 @@
"Parallel Ringing": "Paralleles Klingeln", "Parallel Ringing": "Paralleles Klingeln",
"Parent": "Eltern", "Parent": "Eltern",
"Password": "Passwort", "Password": "Passwort",
"Password Expired": "Password Expired",
"Password Retype": "Passwort-Neueingabe", "Password Retype": "Passwort-Neueingabe",
"Password changed successfully": "Passwort erfolgreich geändert", "Password changed successfully": "Passwort erfolgreich geändert",
"Password confirm": "Passwort bestätigen", "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": "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", "Passwords must be equal": "Passwörter müssen übereinstimmen",
"Phone model": "Telefonmodell", "Phone model": "Telefonmodell",
"Phone number": "Rufnummer", "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": "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 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 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", "Your web password has been changed successfully": "Ihr Web-Passwort wurde erfolgreich geändert",
"ago": "vor", "ago": "vor",
"and": "und", "and": "und",

@ -57,6 +57,7 @@
"Block Mode for outbounds calls": "Block Mode for outbounds calls", "Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Block Outgoing", "Block Outgoing": "Block Outgoing",
"Block anonymous inbound calls": "Block anonymous inbound calls", "Block anonymous inbound calls": "Block anonymous inbound calls",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Busy Greeting", "Busy Greeting": "Busy Greeting",
"Busy Lamp Field": "Busy Lamp Field", "Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR", "CDR": "CDR",
@ -105,7 +106,7 @@
"Conference": "Conference", "Conference": "Conference",
"Confirm": "Confirm", "Confirm": "Confirm",
"Contact": "Contact", "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", "Content": "Content",
"Conversations": "Conversations", "Conversations": "Conversations",
"Cost": "Cost", "Cost": "Cost",
@ -116,6 +117,7 @@
"Create Call Queue": "Create Call Queue", "Create Call Queue": "Create Call Queue",
"Create Config": "Create Config", "Create Config": "Create Config",
"Create List": "Create List", "Create List": "Create List",
"Create New Password": "Create New Password",
"Create destination": "Create destination", "Create destination": "Create destination",
"Create device": "Create device", "Create device": "Create device",
"Create group": "Create group", "Create group": "Create group",
@ -125,6 +127,7 @@
"Created device {device} successfully": "Created device {device} successfully", "Created device {device} successfully": "Created device {device} successfully",
"Created manager secretary config for {msConfig} successfully": "Created manager secretary config for {msConfig} 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", "Created sound set {soundSet} successfully": "Created sound set {soundSet} successfully",
"Current Password": "Current Password",
"Custom Announcement": "Custom Announcement", "Custom Announcement": "Custom Announcement",
"Custom Announcements": "Custom Announcements", "Custom Announcements": "Custom Announcements",
"Custom sound": "Custom sound", "Custom sound": "Custom sound",
@ -288,6 +291,7 @@
"Ncos": "Ncos", "Ncos": "Ncos",
"Ncos Set": "Ncos Set", "Ncos Set": "Ncos Set",
"Never": "Never", "Never": "Never",
"New Password": "New Password",
"New SIP Password": "New SIP Password", "New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm", "New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password", "New Web Password": "New Web Password",
@ -342,10 +346,18 @@
"Parallel Ringing": "Parallel Ringing", "Parallel Ringing": "Parallel Ringing",
"Parent": "Parent", "Parent": "Parent",
"Password": "Password", "Password": "Password",
"Password Expired": "Password Expired",
"Password Retype": "Password Retype", "Password Retype": "Password Retype",
"Password changed successfully": "Password changed successfully", "Password changed successfully": "Password changed successfully",
"Password confirm": "Password confirm", "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": "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", "Passwords must be equal": "Passwords must be equal",
"Phone model": "Phone model", "Phone model": "Phone model",
"Phone number": "Phone number", "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 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": "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 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", "ago": "ago",
"and": "and", "and": "and",
"and call from": "and call from", "and call from": "and call from",

@ -58,6 +58,7 @@
"Block Mode for outbounds calls": "Block Mode for outbounds calls", "Block Mode for outbounds calls": "Block Mode for outbounds calls",
"Block Outgoing": "Bloquear Salientes", "Block Outgoing": "Bloquear Salientes",
"Block anonymous inbound calls": "Block anonymous inbound calls", "Block anonymous inbound calls": "Block anonymous inbound calls",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Saludo de Ocupado", "Busy Greeting": "Saludo de Ocupado",
"Busy Lamp Field": "Campo de lámpara ocupado", "Busy Lamp Field": "Campo de lámpara ocupado",
"CDR": "CDR", "CDR": "CDR",
@ -107,7 +108,7 @@
"Conference name": "Nombre de la conferencia", "Conference name": "Nombre de la conferencia",
"Confirm": "Confirmar", "Confirm": "Confirmar",
"Contact": "Contacto", "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", "Content": "Contenido",
"Conversations": "Conversaciones", "Conversations": "Conversaciones",
"Copy link": "Copiar enlace", "Copy link": "Copiar enlace",
@ -119,6 +120,7 @@
"Create Call Queue": "Crear Cola de Llamadas", "Create Call Queue": "Crear Cola de Llamadas",
"Create Config": "Crear Configuración", "Create Config": "Crear Configuración",
"Create List": "Crear Lista", "Create List": "Crear Lista",
"Create New Password": "Create New Password",
"Create destination": "Crear destino", "Create destination": "Crear destino",
"Create device": "Crear dispositivo", "Create device": "Crear dispositivo",
"Create group": "Crear grupo", "Create group": "Crear grupo",
@ -128,6 +130,7 @@
"Created device {device} successfully": "Dispositivo {device} creado exitosamente", "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 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", "Created sound set {soundSet} successfully": "Conjunto de sonido {soundSet} creado exitosamente",
"Current Password": "Current Password",
"Custom Announcement": "Anuncio Personalizado", "Custom Announcement": "Anuncio Personalizado",
"Custom Announcements": "Anuncios Personalizados", "Custom Announcements": "Anuncios Personalizados",
"Custom sound": "Sonido personalizado", "Custom sound": "Sonido personalizado",
@ -301,6 +304,7 @@
"Ncos Set": "Ncos Set", "Ncos Set": "Ncos Set",
"Never": "Nunca", "Never": "Nunca",
"New Messages": "Nuevos Mensajes", "New Messages": "Nuevos Mensajes",
"New Password": "New Password",
"New SIP Password": "New SIP Password", "New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm", "New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password", "New Web Password": "New Web Password",
@ -355,10 +359,18 @@
"Parallel Ringing": "Llamada en paralelo", "Parallel Ringing": "Llamada en paralelo",
"Parent": "Parent", "Parent": "Parent",
"Password": "Contraseña", "Password": "Contraseña",
"Password Expired": "Password Expired",
"Password Retype": "Repetir contraseña", "Password Retype": "Repetir contraseña",
"Password changed successfully": "La contraseña ha sido cambiada correctamente.", "Password changed successfully": "La contraseña ha sido cambiada correctamente.",
"Password confirm": "Password confirm", "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": "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", "Passwords must be equal": "Las contraseñas deben ser iguales",
"Phone model": "Modelo de teléfono", "Phone model": "Modelo de teléfono",
"Phone number": "Número 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": "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 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 been changed successfully": "Su contraseña ha sido cambiada exitosamente",
"Your password has expired": "Your password has expired",
"ago": "atrás", "ago": "atrás",
"and": "y", "and": "y",
"and call from": "y llamar desde", "and call from": "y llamar desde",

@ -58,6 +58,7 @@
"Block Mode for outbounds calls": "Mode blocage pour les appels sortants", "Block Mode for outbounds calls": "Mode blocage pour les appels sortants",
"Block Outgoing": "Bloquer les sortants", "Block Outgoing": "Bloquer les sortants",
"Block anonymous inbound calls": "Bloquer les appels entrants anonymes", "Block anonymous inbound calls": "Bloquer les appels entrants anonymes",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Message d'accueil en cas d'occupation", "Busy Greeting": "Message d'accueil en cas d'occupation",
"Busy Lamp Field": "Champ de la lampe occupée", "Busy Lamp Field": "Champ de la lampe occupée",
"CDR": "CDR", "CDR": "CDR",
@ -107,7 +108,7 @@
"Conference name": "Nom de la conférence", "Conference name": "Nom de la conférence",
"Confirm": "Confirmer", "Confirm": "Confirmer",
"Contact": "Contact", "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", "Content": "Contenu",
"Conversations": "Conversations", "Conversations": "Conversations",
"Copy link": "Copier le lien", "Copy link": "Copier le lien",
@ -119,6 +120,7 @@
"Create Call Queue": "Créer une file dattente", "Create Call Queue": "Créer une file dattente",
"Create Config": "Créer Configuration", "Create Config": "Créer Configuration",
"Create List": "Créer une liste", "Create List": "Créer une liste",
"Create New Password": "Create New Password",
"Create destination": "Créer une destination", "Create destination": "Créer une destination",
"Create device": "Créer un appareil", "Create device": "Créer un appareil",
"Create group": "Créer un groupe", "Create group": "Créer un groupe",
@ -128,6 +130,7 @@
"Created device {device} successfully": "Le poste {device} a été créé avec succès", "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 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", "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 Announcement": "Annonce personnalisée",
"Custom Announcements": "Annonces personnalisées", "Custom Announcements": "Annonces personnalisées",
"Custom sound": "Son personnalisé", "Custom sound": "Son personnalisé",
@ -300,6 +303,7 @@
"Ncos Set": "Ncos Set", "Ncos Set": "Ncos Set",
"Never": "Jamais", "Never": "Jamais",
"New Messages": "Nouveaux messages", "New Messages": "Nouveaux messages",
"New Password": "New Password",
"New SIP Password": "New SIP Password", "New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm", "New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password", "New Web Password": "New Web Password",
@ -356,10 +360,18 @@
"Parallel Ringing": "Sonnerie parallèle", "Parallel Ringing": "Sonnerie parallèle",
"Parent": "Parent", "Parent": "Parent",
"Password": "Mot de passe", "Password": "Mot de passe",
"Password Expired": "Password Expired",
"Password Retype": "Retaper le mot de passe", "Password Retype": "Retaper le mot de passe",
"Password changed successfully": "Le mot de passe a été modifié avec succès", "Password changed successfully": "Le mot de passe a été modifié avec succès",
"Password confirm": "Password confirm", "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": "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", "Passwords must be equal": "Les mots de passe doivent être égaux",
"Phone model": "Modèle du poste", "Phone model": "Modèle du poste",
"Phone number": "Numéro de téléphone", "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": "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 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 been changed successfully": "Votre mot de passe a été modifié avec succès",
"Your password has expired": "Your password has expired",
"ago": ".", "ago": ".",
"and": "et", "and": "et",
"and call from": "et appeler de", "and call from": "et appeler de",

@ -56,6 +56,7 @@
"Block Mode for outbounds calls": "Modalità di blocco per le chiamate in uscita", "Block Mode for outbounds calls": "Modalità di blocco per le chiamate in uscita",
"Block Outgoing": "Blocca chiamate in uscita", "Block Outgoing": "Blocca chiamate in uscita",
"Block anonymous inbound calls": "Blocca chiamate anonime in entrata", "Block anonymous inbound calls": "Blocca chiamate anonime in entrata",
"Block outgoing": "Block outgoing",
"Busy Greeting": "Messaggio per numero occupato", "Busy Greeting": "Messaggio per numero occupato",
"Busy Lamp Field": "Busy Lamp Field", "Busy Lamp Field": "Busy Lamp Field",
"CDR": "CDR", "CDR": "CDR",
@ -117,6 +118,7 @@
"Create Call Queue": "Crea coda chiamate", "Create Call Queue": "Crea coda chiamate",
"Create Config": "Crea configurazione", "Create Config": "Crea configurazione",
"Create List": "Crea lista", "Create List": "Crea lista",
"Create New Password": "Create New Password",
"Create destination": "Crea destinazione", "Create destination": "Crea destinazione",
"Create device": "Crea dispositivo", "Create device": "Crea dispositivo",
"Create group": "Crea gruppo", "Create group": "Crea gruppo",
@ -126,6 +128,7 @@
"Created device {device} successfully": "Dispositivo {device} creato correttamente", "Created device {device} successfully": "Dispositivo {device} creato correttamente",
"Created manager secretary config for {msConfig} successfully": "Configurazione segreteria per {msConfig} creata 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", "Created sound set {soundSet} successfully": "Set di messaggi audio {soundSet} creato correttamente",
"Current Password": "Current Password",
"Custom Announcement": "Custom Announcement", "Custom Announcement": "Custom Announcement",
"Custom Announcements": "Custom Announcements", "Custom Announcements": "Custom Announcements",
"Custom sound": "Audio personalizzato", "Custom sound": "Audio personalizzato",
@ -292,6 +295,7 @@
"Ncos Set": "Ncos Set", "Ncos Set": "Ncos Set",
"Never": "Never", "Never": "Never",
"New Messages": "Nuovi messaggi", "New Messages": "Nuovi messaggi",
"New Password": "New Password",
"New SIP Password": "New SIP Password", "New SIP Password": "New SIP Password",
"New SIP Password confirm": "New SIP Password confirm", "New SIP Password confirm": "New SIP Password confirm",
"New Web Password": "New Web Password", "New Web Password": "New Web Password",
@ -348,10 +352,18 @@
"Parallel Ringing": "Squilli in parallelo", "Parallel Ringing": "Squilli in parallelo",
"Parent": "Parent", "Parent": "Parent",
"Password": "Password", "Password": "Password",
"Password Expired": "Password Expired",
"Password Retype": "Password Retype", "Password Retype": "Password Retype",
"Password changed successfully": "Password changed successfully", "Password changed successfully": "Password changed successfully",
"Password confirm": "Password confirm", "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": "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", "Passwords must be equal": "Le passwords devono essere identiche",
"Phone model": "Modello telefono", "Phone model": "Modello telefono",
"Phone number": "Numero di 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": "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 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 been changed successfully": "Password modificata",
"Your password has expired": "Your password has expired",
"ago": "fa", "ago": "fa",
"and": "e", "and": "e",
"and call from": "and call from", "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) { loginError (error) {
if (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 CscPageCallRecording from 'src/pages/CscPageCallRecording'
import CscPageCallSettings from 'pages/CscPageCallSettings' import CscPageCallSettings from 'pages/CscPageCallSettings'
import CscPageCf from 'pages/CscPageCf' import CscPageCf from 'pages/CscPageCf'
import CscPageChangePassword from 'src/pages/CscChangeExpiredPassword.vue'
import CscPageConversations from 'src/pages/CscPageConversations' import CscPageConversations from 'src/pages/CscPageConversations'
import CscPageCustomerPhonebook from 'src/pages/CscPageCustomerPhonebook' import CscPageCustomerPhonebook from 'src/pages/CscPageCustomerPhonebook'
import CscPageCustomerPhonebookAdd from 'src/pages/CscPageCustomerPhonebookAdd' import CscPageCustomerPhonebookAdd from 'src/pages/CscPageCustomerPhonebookAdd'
@ -45,6 +46,8 @@ import CscRecoverPassword from 'src/pages/CscRecoverPassword'
import CscPageCustomerPreferences from 'src/pages/CscPageCustomerPreferences' import CscPageCustomerPreferences from 'src/pages/CscPageCustomerPreferences'
import { i18n } from 'src/boot/i18n' import { i18n } from 'src/boot/i18n'
export const PATH_CHANGE_PASSWORD = '/changepassword'
const getToken = (route) => { const getToken = (route) => {
return { return {
token: route.query.token token: route.query.token
@ -543,6 +546,11 @@ const routes = [
} }
} }
}, },
{
name: 'passwordChange',
path: PATH_CHANGE_PASSWORD,
component: CscPageChangePassword
},
{ {
path: '/recoverpassword', path: '/recoverpassword',
component: CscLayoutLogin, component: CscLayoutLogin,

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

Loading…
Cancel
Save