diff --git a/src/api/subscriber.js b/src/api/subscriber.js
index 5b7359a1..900a2a84 100644
--- a/src/api/subscriber.js
+++ b/src/api/subscriber.js
@@ -517,3 +517,20 @@ export function changePassword (subscriber, newPassword) {
})
})
}
+
+export async function resetPassword (userName) {
+ const payLoad = {
+ domain: Vue.$config.baseHttpUrl.replace(/(^\w+:|^)\/\//, ''),
+ type: 'subscriber',
+ username: userName
+ }
+ return await Vue.http.post('api/passwordreset/', payLoad)
+}
+
+export async function recoverPassword (data) {
+ const payLoad = {
+ new_password: data.password,
+ token: data.token
+ }
+ return await Vue.http.post('api/passwordrecovery/', payLoad)
+}
diff --git a/src/boot/routes.js b/src/boot/routes.js
index 27ad2738..473c18b6 100644
--- a/src/boot/routes.js
+++ b/src/boot/routes.js
@@ -11,22 +11,35 @@ import {
export default ({ app, router, store }) => {
router.beforeEach((to, from, next) => {
- if (!hasJwt() && to.path !== '/login') {
- next({
- path: '/login'
- })
- } else if (hasJwt() && to.path === '/login') {
- next({
- path: '/'
- })
- } else if (hasJwt() && to.path === '/conference') {
- next({
- path: '/conference/room123'
- })
+ const publicUrls = ['/login', '/recoverpassword']
+ // not authorized user
+ if (!hasJwt()) {
+ if (!publicUrls.includes(to.path)) {
+ next({
+ path: '/login'
+ })
+ } else {
+ next()
+ }
} else {
- next()
+ // already authorized user
+ switch (to.path) {
+ case '/login':
+ next({
+ path: '/'
+ })
+ break
+ case '/conference':
+ next({
+ path: '/conference/room123'
+ })
+ break
+ default:
+ next()
+ }
}
})
+
router.afterEach((to, from) => {
const mainTitle = app.i18n.t('title')
let title = _.get(to, 'meta.title', '')
diff --git a/src/boot/vuelidate.js b/src/boot/vuelidate.js
index e22676ad..b3488d5f 100644
--- a/src/boot/vuelidate.js
+++ b/src/boot/vuelidate.js
@@ -1,6 +1,15 @@
-
import Vuelidate from 'vuelidate'
+import _ from 'lodash'
-export default ({ Vue, store }) => {
+export default ({ Vue, app }) => {
Vue.use(Vuelidate)
+ Vue.prototype.$errorMessage = (def) => {
+ let message = null
+ _.forEach(def.$params, (param, paramName) => {
+ if (def[paramName] === false) {
+ message = app.i18n.t('validators.' + paramName)
+ }
+ })
+ return message
+ }
}
diff --git a/src/components/CscChangePasswordDialog.vue b/src/components/CscChangePasswordDialog.vue
index 3f3c3563..f0ea5790 100644
--- a/src/components/CscChangePasswordDialog.vue
+++ b/src/components/CscChangePasswordDialog.vue
@@ -4,9 +4,10 @@
:value="value"
:loading="loading"
title-icon="vpn_key"
- title="Change password"
+ :title="$t('pages.login.changePassword')"
class="csc-pbx-password-dialog"
@input="$emit('input')"
+ @hide="$emit('dialog-closed')"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/i18n/en.json b/src/i18n/en.json
index f8c87e76..ad3a5bc2 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -42,7 +42,10 @@
"callAvailable": "You are now able to start and receive calls",
"callNotAvailable": "Could not initialize call functionality properly",
"conferencingAvailable": "You are now able to create WebRTC multiparty conferences",
- "changeSessionLanguageSuccessMessage": "Session language successfully changed"
+ "changeSessionLanguageSuccessMessage": "Session language successfully changed",
+ "passwordChangedSuccessfully": "Password changed successfully",
+ "errorPasswordReset": "There was an error, please retry later",
+ "send": "Send"
},
"validationErrors": {
"generic": "You have invalid form input. Please check and try again.",
@@ -142,7 +145,10 @@
"username": "Username",
"username_helper": "Input username or username@domain",
"password": "Password",
- "password_helper": ""
+ "password_helper": "",
+ "forgotPassword": "Forgot password?",
+ "recoverPassword": "Recover password",
+ "changePassword": "Change password"
},
"callBlockingIncoming": {
"title": "Block/Allow incoming calls",
diff --git a/src/layouts/CscLayoutLogin.vue b/src/layouts/CscLayoutLogin.vue
new file mode 100644
index 00000000..30fa1838
--- /dev/null
+++ b/src/layouts/CscLayoutLogin.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/pages/CscPageLogin.vue b/src/pages/CscPageLogin.vue
index e9894b26..2a3f7a77 100644
--- a/src/pages/CscPageLogin.vue
+++ b/src/pages/CscPageLogin.vue
@@ -76,8 +76,15 @@
+
+
@@ -117,18 +128,21 @@ import CscLanguageMenu from 'components/CscLanguageMenu'
import CscSpinner from 'components/CscSpinner'
import CscInputPassword from 'components/form/CscInputPassword'
import CscInput from 'components/form/CscInput'
+import CscRetrievePasswordDialog from 'components/CscRetrievePasswordDialog'
export default {
name: 'Login',
components: {
CscInput,
CscInputPassword,
CscSpinner,
- CscLanguageMenu
+ CscLanguageMenu,
+ CscRetrievePasswordDialog
},
data () {
return {
username: '',
- password: ''
+ password: '',
+ showDialog: false
}
},
computed: {
@@ -176,6 +190,9 @@ export default {
},
changeLanguage (language) {
this.$store.dispatch('user/changeSessionLanguage', language)
+ },
+ showRetrievePasswordDialog () {
+ this.showDialog = true
}
}
}
diff --git a/src/pages/CscRecoverPassword.vue b/src/pages/CscRecoverPassword.vue
new file mode 100644
index 00000000..5099d14e
--- /dev/null
+++ b/src/pages/CscRecoverPassword.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
diff --git a/src/router/routes.js b/src/router/routes.js
index 83329014..f693525d 100644
--- a/src/router/routes.js
+++ b/src/router/routes.js
@@ -1,6 +1,7 @@
import CscLayoutConference from 'src/layouts/CscLayoutConference'
import CscLayoutMain from 'src/layouts/CscLayoutMain'
+import CscLayoutLogin from 'src/layouts/CscLayoutLogin'
import CscPageLogin from 'src/pages/CscPageLogin'
import CscPageHome from 'src/pages/CscPageHome'
@@ -24,6 +25,13 @@ import CscPagePbxSettings from 'src/pages/CscPagePbxSettings'
import CscPageVoicebox from 'src/pages/CscPageVoicebox'
import CscPageUserSettings from 'src/pages/CscPageUserSettings'
import CscPageError404 from 'src/pages/CscPageError404'
+import CscRecoverPassword from 'src/pages/CscRecoverPassword'
+
+const getToken = (route) => {
+ return {
+ token: route.query.token
+ }
+}
export default function routes (app) {
const i18n = app.i18n
@@ -214,6 +222,21 @@ export default function routes (app) {
title: 'Conference'
}
},
+ {
+ path: '/recoverpassword',
+ component: CscLayoutLogin,
+ children: [
+ {
+ path: '',
+ component: CscRecoverPassword,
+ props: getToken,
+ meta: {
+ title: 'Reset Password',
+ permission: 'public'
+ }
+ }
+ ]
+ },
{
path: '/',
redirect: {
@@ -226,21 +249,3 @@ export default function routes (app) {
}
]
}
-
-// const routes = [
-// {
-// path: '/',
-// component: () => import('layouts/MainLayout.vue'),
-// children: [
-// { path: '', component: () => import('pages/Index.vue') }
-// ]
-// },
-// // Always leave this as last one,
-// // but you can also remove it
-// {
-// path: '*',
-// component: () => import('pages/Error404.vue')
-// }
-// ]
-//
-// export default routes
diff --git a/src/store/user.js b/src/store/user.js
index b3433049..fcf9db4d 100644
--- a/src/store/user.js
+++ b/src/store/user.js
@@ -13,7 +13,7 @@ import {
login,
getUserData
} from '../api/user'
-import { changePassword } from '../api/subscriber'
+import { changePassword, resetPassword, recoverPassword } from '../api/subscriber'
import { deleteJwt, getJwt, getSubscriberId, setJwt, setSubscriberId } from 'src/auth'
import { setSession } from 'src/storage'
@@ -41,7 +41,8 @@ export default {
changeSessionLocaleError: null,
languageLabels: [],
changePasswordState: RequestState.initiated,
- changePasswordError: null
+ changePasswordError: null,
+ newPasswordRequesting: false
},
getters: {
isLogged (state) {
@@ -243,8 +244,11 @@ export default {
state.changePasswordError = null
},
userPasswordFailed (state, error) {
- state.changePasswordState = RequestState.failed
state.changePasswordError = error
+ state.changePasswordState = RequestState.failed
+ },
+ newPasswordRequesting (state, isRequesting) {
+ state.newPasswordRequesting = isRequesting
}
},
actions: {
@@ -317,6 +321,25 @@ export default {
context.commit('userPasswordFailed', err.message)
})
},
+ async resetPassword ({ commit }, data) {
+ commit('newPasswordRequesting', true)
+ const response = await resetPassword(data)
+ commit('newPasswordRequesting', false)
+ return response
+ },
+ async recoverPassword ({ commit, dispatch, state, rootGetters }, data) {
+ commit('userPasswordRequesting')
+ try {
+ const res = await recoverPassword(data)
+ if (res.status === 200 || res.status === 201) {
+ commit('userPasswordSucceeded')
+ } else {
+ commit('userPasswordFailed')
+ }
+ } catch (err) {
+ commit('userPasswordFailed', err.message)
+ }
+ },
async forwardHome (context) {
if (context.rootState.route.path === '/user/home' && !context.getters.isRtcEngineUiVisible) {
await router.push({ path: '/user/conversations' })