@@ -10,6 +10,7 @@ | |||||
"start": "webpack-dev-server --open" | "start": "webpack-dev-server --open" | ||||
}, | }, | ||||
"dependencies": { | "dependencies": { | ||||
"qrcode": "^1.4.4", | |||||
"safe-eval": "^0.4.1", | "safe-eval": "^0.4.1", | ||||
"vee-validate": "^2.2.8", | "vee-validate": "^2.2.8", | ||||
"vue": "^2.6.10", | "vue": "^2.6.10", | ||||
@@ -1,3 +1,8 @@ | |||||
let landingPage = null; | |||||
export function getLandingPage () { return landingPage; } | |||||
export function setLandingPage (page) { landingPage = page; } | |||||
export function resetLandingPage () { landingPage = null; } | |||||
export function currentUser() { | export function currentUser() { | ||||
let userJson = localStorage.getItem('user'); | let userJson = localStorage.getItem('user'); | ||||
return userJson ? JSON.parse(userJson) : null; | return userJson ? JSON.parse(userJson) : null; | ||||
@@ -23,21 +28,25 @@ export function getWithAuth() { | |||||
}; | }; | ||||
} | } | ||||
export function postWithAuth(obj) { | |||||
return { | |||||
method: 'POST', | |||||
headers: { ...authHeader(), 'Content-Type': 'application/json' }, | |||||
body: JSON.stringify(obj) | |||||
}; | |||||
function entityWithAuth(method, obj) { | |||||
console.log("entityWithAuth("+method+"): obj="+obj+" (type="+(typeof obj)+")"); | |||||
if (typeof obj === 'undefined' || obj === null || obj === 'undefined') { | |||||
return { | |||||
method: method, | |||||
headers: { ...authHeader(), 'Content-Type': 'application/json' } | |||||
}; | |||||
} else { | |||||
return { | |||||
method: method, | |||||
headers: { ...authHeader(), 'Content-Type': 'application/json' }, | |||||
body: JSON.stringify(obj) | |||||
}; | |||||
} | |||||
} | } | ||||
export function putWithAuth(obj) { | |||||
return { | |||||
method: 'PUT', | |||||
headers: { ...authHeader(), 'Content-Type': 'application/json' }, | |||||
body: JSON.stringify(obj) | |||||
}; | |||||
} | |||||
export function postWithAuth(obj) { return entityWithAuth('POST', obj); } | |||||
export function putWithAuth(obj) { return entityWithAuth('PUT', obj); } | |||||
export function deleteWithAuth() { | export function deleteWithAuth() { | ||||
return { | return { | ||||
@@ -5,6 +5,7 @@ import HomePage from '../account/HomePage' | |||||
import RegisterPage from '../auth/RegisterPage' | import RegisterPage from '../auth/RegisterPage' | ||||
import LoginPage from '../auth/LoginPage' | import LoginPage from '../auth/LoginPage' | ||||
import ProfilePage from '../account/profile/ProfilePage' | import ProfilePage from '../account/profile/ProfilePage' | ||||
import ActionPage from '../account/profile/ActionPage' | |||||
import PolicyPage from '../account/profile/PolicyPage' | import PolicyPage from '../account/profile/PolicyPage' | ||||
import NotificationsPage from '../account/NotificationsPage' | import NotificationsPage from '../account/NotificationsPage' | ||||
import ChangePasswordPage from '../account/profile/ChangePasswordPage' | import ChangePasswordPage from '../account/profile/ChangePasswordPage' | ||||
@@ -15,7 +16,7 @@ import AccountsPage from '../admin/AccountsPage' | |||||
import StripePayment from "../account/payment/StripePayment"; | import StripePayment from "../account/payment/StripePayment"; | ||||
import InviteCodePayment from "../account/payment/InviteCodePayment"; | import InviteCodePayment from "../account/payment/InviteCodePayment"; | ||||
import UnknownPayment from "../account/payment/UnknownPayment"; | import UnknownPayment from "../account/payment/UnknownPayment"; | ||||
import { currentUser } from '../_helpers' | |||||
import { currentUser, setLandingPage } from '../_helpers' | |||||
Vue.use(Router); | Vue.use(Router); | ||||
@@ -43,6 +44,7 @@ export const router = new Router({ | |||||
}, | }, | ||||
{ path: '/me', component: ProfilePage }, | { path: '/me', component: ProfilePage }, | ||||
{ path: '/me/policy', component: PolicyPage }, | { path: '/me/policy', component: PolicyPage }, | ||||
{ path: '/me/action', component: ActionPage }, | |||||
{ path: '/me/changePassword', component: ChangePasswordPage }, | { path: '/me/changePassword', component: ChangePasswordPage }, | ||||
{ path: '/notifications', component: NotificationsPage }, | { path: '/notifications', component: NotificationsPage }, | ||||
{ | { | ||||
@@ -78,7 +80,10 @@ router.beforeEach((to, from, next) => { | |||||
if (authRequired) { | if (authRequired) { | ||||
// redirect to login page if not logged in and trying to access a restricted page | // redirect to login page if not logged in and trying to access a restricted page | ||||
if (!user) return next('/login'); | |||||
if (!user) { | |||||
setLandingPage(to); | |||||
return next('/login'); | |||||
} | |||||
// redirect to home page if not admin and trying to access an admin page | // redirect to home page if not admin and trying to access an admin page | ||||
if (to.path.startsWith('/admin') && user.admin !== true) return next('/'); | if (to.path.startsWith('/admin') && user.admin !== true) return next('/'); | ||||
@@ -12,9 +12,20 @@ export const userService = { | |||||
addPolicyContactById, | addPolicyContactById, | ||||
removePolicyContactByUuid, | removePolicyContactByUuid, | ||||
update, | update, | ||||
delete: _delete | |||||
delete: _delete, | |||||
approveAction, | |||||
denyAction | |||||
}; | }; | ||||
function setSessionUser (user) { | |||||
// login successful if there's a session token in the response | |||||
if (user.token) { | |||||
// store user details and session token in local storage to keep user logged in between page refreshes | |||||
localStorage.setItem('user', JSON.stringify(user)); | |||||
} | |||||
return user; | |||||
} | |||||
function login(name, password, messages, errors) { | function login(name, password, messages, errors) { | ||||
const requestOptions = { | const requestOptions = { | ||||
method: 'POST', | method: 'POST', | ||||
@@ -23,14 +34,7 @@ function login(name, password, messages, errors) { | |||||
}; | }; | ||||
return fetch(`${config.apiUrl}/auth/login`, requestOptions) | return fetch(`${config.apiUrl}/auth/login`, requestOptions) | ||||
.then(handleAuthResponse(messages, errors)) | .then(handleAuthResponse(messages, errors)) | ||||
.then(user => { | |||||
// login successful if there's a session token in the response | |||||
if (user.token) { | |||||
// store user details and session token in local storage to keep user logged in between page refreshes | |||||
localStorage.setItem('user', JSON.stringify(user)); | |||||
} | |||||
return user; | |||||
}); | |||||
.then(setSessionUser); | |||||
} | } | ||||
function logout() { | function logout() { | ||||
@@ -46,13 +50,7 @@ function register(user, messages, errors) { | |||||
}; | }; | ||||
return fetch(`${config.apiUrl}/auth/register`, requestOptions) | return fetch(`${config.apiUrl}/auth/register`, requestOptions) | ||||
.then(handleAuthResponse(messages, errors)) | .then(handleAuthResponse(messages, errors)) | ||||
.then(user => { | |||||
if (user.token) { | |||||
// store user details and session token in local storage to keep user logged in between page refreshes | |||||
localStorage.setItem('user', JSON.stringify(user)); | |||||
} | |||||
return user; | |||||
}); | |||||
.then(setSessionUser); | |||||
} | } | ||||
function getAll(messages, errors) { | function getAll(messages, errors) { | ||||
@@ -79,6 +77,16 @@ function removePolicyContactByUuid(id, uuid, messages, errors) { | |||||
return fetch(`${config.apiUrl}/users/${id}/policy/contacts/${uuid}`, deleteWithAuth()).then(handleCrudResponse(messages, errors)); | return fetch(`${config.apiUrl}/users/${id}/policy/contacts/${uuid}`, deleteWithAuth()).then(handleCrudResponse(messages, errors)); | ||||
} | } | ||||
function approveAction(id, code, messages, errors) { | |||||
return fetch(`${config.apiUrl}/auth/approve/${code}`, postWithAuth()) | |||||
.then(handleCrudResponse(messages, errors)) | |||||
.then(setSessionUser); | |||||
} | |||||
function denyAction(id, code, messages, errors) { | |||||
return fetch(`${config.apiUrl}/auth/deny/${code}`, postWithAuth()).then(handleCrudResponse(messages, errors)); | |||||
} | |||||
function update(user, messages, errors) { | function update(user, messages, errors) { | ||||
return fetch(`${config.apiUrl}/users/${user.uuid}`, postWithAuth(user)).then(handleCrudResponse(messages, errors)); | return fetch(`${config.apiUrl}/users/${user.uuid}`, postWithAuth(user)).then(handleCrudResponse(messages, errors)); | ||||
} | } | ||||
@@ -1,13 +1,13 @@ | |||||
import { userService } from '../_services'; | import { userService } from '../_services'; | ||||
import { router } from '../_helpers'; | |||||
import { router, getLandingPage, resetLandingPage } from '../_helpers'; | |||||
// todo: why can't we import currentUser from api-util and use that here? | // todo: why can't we import currentUser from api-util and use that here? | ||||
// when I try to do that, webpack succeeds but then an error occurs loading any page, with the | // when I try to do that, webpack succeeds but then an error occurs loading any page, with the | ||||
// error message "_helpers.currentUser is not defined" | // error message "_helpers.currentUser is not defined" | ||||
const user = JSON.parse(localStorage.getItem('user')); | const user = JSON.parse(localStorage.getItem('user')); | ||||
const state = user | const state = user | ||||
? { status: { loggedIn: true }, user } | |||||
: { status: {}, user: null }; | |||||
? { status: { loggedIn: true }, user, actionStatus: {} } | |||||
: { status: {}, user: null, actionStatus: {} }; | |||||
const actions = { | const actions = { | ||||
login({ dispatch, commit }, { user, messages, errors }) { | login({ dispatch, commit }, { user, messages, errors }) { | ||||
@@ -16,7 +16,14 @@ const actions = { | |||||
.then( | .then( | ||||
user => { | user => { | ||||
commit('loginSuccess', user); | commit('loginSuccess', user); | ||||
router.push('/'); | |||||
const landing = getLandingPage(); | |||||
console.log('getLandingPage returned: '+JSON.stringify(landing)); | |||||
if (landing === null) { | |||||
router.push('/'); | |||||
} else { | |||||
resetLandingPage(); | |||||
router.push(landing.fullPath); | |||||
} | |||||
}, | }, | ||||
error => { | error => { | ||||
commit('loginFailure', error); | commit('loginFailure', error); | ||||
@@ -55,7 +62,7 @@ const actions = { | |||||
router.push('/me'); | router.push('/me'); | ||||
setTimeout(() => { | setTimeout(() => { | ||||
// display success message after route change completes | // display success message after route change completes | ||||
dispatch('alert/success', 'Profile update was successful', { root: true }); | |||||
dispatch('alert/success', messages.message_profile_update_success, { root: true }); | |||||
}) | }) | ||||
}, | }, | ||||
error => { | error => { | ||||
@@ -63,7 +70,25 @@ const actions = { | |||||
dispatch('alert/error', error, { root: true }); | dispatch('alert/error', error, { root: true }); | ||||
} | } | ||||
); | ); | ||||
} | |||||
}, | |||||
approveAction({ commit }, {uuid, code, messages, errors}) { | |||||
commit('approveActionRequest'); | |||||
userService.approveAction(uuid, code, messages, errors) | |||||
.then( | |||||
policy => commit('approveActionSuccess', policy), | |||||
error => commit('approveActionFailure', error) | |||||
); | |||||
}, | |||||
denyAction({ commit }, {uuid, code, messages, errors}) { | |||||
commit('denyActionRequest'); | |||||
userService.denyAction(uuid, code, messages, errors) | |||||
.then( | |||||
policy => commit('denyActionSuccess', policy), | |||||
error => commit('denyActionFailure', error) | |||||
); | |||||
}, | |||||
}; | }; | ||||
const mutations = { | const mutations = { | ||||
@@ -79,10 +104,12 @@ const mutations = { | |||||
state.status = {}; | state.status = {}; | ||||
state.user = null; | state.user = null; | ||||
}, | }, | ||||
logout(state) { | logout(state) { | ||||
state.status = {}; | state.status = {}; | ||||
state.user = null; | state.user = null; | ||||
}, | }, | ||||
registerRequest(state, user) { | registerRequest(state, user) { | ||||
state.status = { registering: true }; | state.status = { registering: true }; | ||||
state.user = user; | state.user = user; | ||||
@@ -93,7 +120,29 @@ const mutations = { | |||||
}, | }, | ||||
registerFailure(state) { | registerFailure(state) { | ||||
state.status = {}; | state.status = {}; | ||||
}, | |||||
approveActionRequest(state) { | |||||
state.actionStatus = { requesting: true, type: 'approve' }; | |||||
}, | |||||
approveActionSuccess(state, user) { | |||||
state.actionStatus = { success: true, type: 'approve', result: user }; | |||||
if (user.token) state.user = user; | |||||
}, | |||||
approveActionFailure(state, error) { | |||||
state.actionStatus = { error: error, type: 'approve' }; | |||||
}, | |||||
denyActionRequest(state) { | |||||
state.actionStatus = { requesting: true, type: 'deny' }; | |||||
}, | |||||
denyActionSuccess(state, denial) { | |||||
state.actionStatus = { success: true, type: 'deny', result: denial }; | |||||
state.denial = denial; | |||||
}, | |||||
denyActionFailure(state, error) { | |||||
state.actionStatus = { error: error, type: 'deny' }; | |||||
} | } | ||||
}; | }; | ||||
export const account = { | export const account = { | ||||
@@ -6,7 +6,8 @@ const state = { | |||||
user: null, | user: null, | ||||
policy: {}, | policy: {}, | ||||
policyStatus: {}, | policyStatus: {}, | ||||
contact: null | |||||
contact: null, | |||||
authenticator: null | |||||
}; | }; | ||||
const actions = { | const actions = { | ||||
@@ -131,6 +132,9 @@ const mutations = { | |||||
}, | }, | ||||
addPolicyContactByUuidSuccess(state, contact) { | addPolicyContactByUuidSuccess(state, contact) { | ||||
state.contact = contact; | state.contact = contact; | ||||
if (contact.type === 'authenticator') { | |||||
state.authenticator = contact.info; | |||||
} | |||||
}, | }, | ||||
addPolicyContactByUuidFailure(state, error) { | addPolicyContactByUuidFailure(state, error) { | ||||
state.contact = { error }; | state.contact = { error }; | ||||
@@ -0,0 +1,65 @@ | |||||
<template> | |||||
<div> | |||||
<h2>{{messages.message_action_processing}} {{messages['message_inbound_'+actionType]}} ...</h2> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import { mapState, mapActions } from 'vuex' | |||||
export default { | |||||
data () { | |||||
return {actionType: null} | |||||
}, | |||||
computed: { | |||||
...mapState('account', { | |||||
currentUser: state => state.user | |||||
}), | |||||
...mapState('account', ['actionStatus']) | |||||
}, | |||||
methods: { | |||||
...mapActions("account", ['approveAction', 'denyAction']), | |||||
...mapState('system', ['messages']), | |||||
}, | |||||
created () { | |||||
console.log('ActionPage.created: starting. query='+JSON.stringify(this.$route.query)); | |||||
if (this.$route.query.approve) { | |||||
this.actionType = 'approve'; | |||||
console.log('ActionPage.created: calling approveAction'); | |||||
this.approveAction({ | |||||
uuid: this.currentUser.uuid, | |||||
code: this.$route.query.approve, | |||||
messages: this.messages, | |||||
errors: this.errors | |||||
}); | |||||
} else if (this.$route.query.deny) { | |||||
this.actionType = 'deny'; | |||||
console.log('ActionPage.created: calling denyAction'); | |||||
this.denyAction({ | |||||
uuid: this.currentUser.uuid, | |||||
code: this.$route.query.deny, | |||||
messages: this.messages, | |||||
errors: this.errors | |||||
}); | |||||
} else { | |||||
this.$router.push({path:'/me/profile', params: {'action': 'invalid'}}); | |||||
} | |||||
}, | |||||
watch: { | |||||
actionStatus (status) { | |||||
console.log('ActionPage.watch.actionStatus: received: '+JSON.stringify(status)); | |||||
if (status.requesting) { | |||||
console.log('ActionPage.watch.actionStatus: still requesting, doing nothing'); | |||||
} else { | |||||
if (status.success) { | |||||
console.log('ActionPage.watch.actionStatus: sending to policy page with success'); | |||||
this.$router.push({path: '/me/policy', query: {action: this.actionType, ok: 'true'}}); | |||||
} else { | |||||
console.log('ActionPage.watch.actionStatus: sending to policy page with failure'); | |||||
this.$router.push({path: '/me/policy', query: {action: this.actionType}}); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
}; | |||||
</script> |
@@ -1,5 +1,12 @@ | |||||
<template> | <template> | ||||
<div> | <div> | ||||
<div v-if="inboundAction" :class="`alert ${inboundAction.alertType}`"> | |||||
{{messages['message_inbound_'+inboundAction.actionType]}} | |||||
{{messages['message_inbound_'+inboundAction.status]}} | |||||
<div v-if="errors.has('token')" class="invalid-feedback d-block">{{ errors.first('token') }}</div> | |||||
<div v-if="errors.has('request')" class="invalid-feedback d-block">{{ errors.first('request') }}</div> | |||||
</div> | |||||
<h2>{{messages.form_label_title_account_policy}}</h2> | <h2>{{messages.form_label_title_account_policy}}</h2> | ||||
<form @submit.prevent="updatePolicy"> | <form @submit.prevent="updatePolicy"> | ||||
<hr/> | <hr/> | ||||
@@ -8,7 +15,7 @@ | |||||
<select v-model="deletionPolicy" name="deletionPolicy" class="form-control"> | <select v-model="deletionPolicy" name="deletionPolicy" class="form-control"> | ||||
<option v-for="opt in accountDeletionOptions" v-bind:value="opt">{{messages['account_deletion_name_'+opt]}}</option> | <option v-for="opt in accountDeletionOptions" v-bind:value="opt">{{messages['account_deletion_name_'+opt]}}</option> | ||||
</select> | </select> | ||||
<span>{{messages['account_deletion_description_'+policy.deletionPolicy]}}</span> | |||||
<span>{{messages['account_deletion_description_'+deletionPolicy]}}</span> | |||||
<div v-if="submitted && errors.has('deletionPolicy')" class="invalid-feedback d-block">{{ errors.first('deletionPolicy') }}</div> | <div v-if="submitted && errors.has('deletionPolicy')" class="invalid-feedback d-block">{{ errors.first('deletionPolicy') }}</div> | ||||
</div> | </div> | ||||
@@ -103,8 +110,25 @@ | |||||
<span class="sr-only">{{messages.message_true}}</span> | <span class="sr-only">{{messages.message_true}}</span> | ||||
</td> | </td> | ||||
<td v-else> | <td v-else> | ||||
<i aria-hidden="true" :class="messages.field_label_policy_contact_value_disabled_icon" :title="messages.message_false"></i> | |||||
<span class="sr-only">{{messages.message_false}}</span> | |||||
<form v-if="verifyingContact === contact.uuid" @submit.prevent="submitVerification(contact.uuid)"> | |||||
<div class="form-group"> | |||||
<div v-if="contact.type === 'authenticator'"> | |||||
<canvas :id="'canvas_'+contact.uuid"></canvas> | |||||
<hr/> | |||||
<span>{{messages.message_verify_authenticator_backupCodes}}<br/> | |||||
<span :id="'backupCodes_'+contact.uuid"></span> | |||||
</span> | |||||
<hr/> | |||||
<span>{{messages.message_verify_authenticator_backupCodes_description}}</span> | |||||
</div> | |||||
<label htmlFor="verifyCode">{{messages.field_label_policy_contact_verify_code}}</label> | |||||
<input :disabled="actionStatus.requesting" :id="'verifyContactCode_'+contact.uuid" v-validate="'required'" name="verifyCode" type="text" size="8"/> | |||||
<div v-if="errors.has('token')" class="invalid-feedback d-block">{{ errors.first('token') }}</div> | |||||
<button class="btn btn-primary" :disabled="actionStatus.requesting">{{messages.button_label_submit_verify_code}}</button> | |||||
<button class="btn btn-primary" :disabled="actionStatus.requesting" @click="cancelVerifyContact()">{{messages.button_label_cancel}}</button> | |||||
</div> | |||||
</form> | |||||
<button v-if="verifyingContact !== contact.uuid" @click="startVerifyContact(contact)" class="btn btn-primary">{{messages.button_label_submit_verify_code}}</button> | |||||
</td> | </td> | ||||
<td v-if="contact.authFactor === 'required'"> | <td v-if="contact.authFactor === 'required'"> | ||||
@@ -238,7 +262,7 @@ | |||||
<div v-if="newContact.type !== '' && newContact.type !== 'authenticator'" class="form-group"> | <div v-if="newContact.type !== '' && newContact.type !== 'authenticator'" class="form-group"> | ||||
<label htmlFor="contactInfo">{{messages['field_label_policy_contact_type_'+newContact.type+'_field']}}</label> | <label htmlFor="contactInfo">{{messages['field_label_policy_contact_type_'+newContact.type+'_field']}}</label> | ||||
<v-select v-if="newContact.type !== '' && newContact.type === 'sms'" :options="countries" :reduce="c => c.code" label="countryName" v-model="newContactSmsCountry" name="newContactSmsCountry" class="form-control"/> | <v-select v-if="newContact.type !== '' && newContact.type === 'sms'" :options="countries" :reduce="c => c.code" label="countryName" v-model="newContactSmsCountry" name="newContactSmsCountry" class="form-control"/> | ||||
<input v-model="newContact.info" name="contactInfo" class="form-control"/> | |||||
<input v-model="newContact.info" :type="newContact.type === 'sms' ? 'tel' : 'text'" name="contactInfo" class="form-control"/> | |||||
<div v-if="contactSubmitted && errors.has('contactInfo')" class="invalid-feedback d-block">{{ errors.first('contactInfo') }}</div> | <div v-if="contactSubmitted && errors.has('contactInfo')" class="invalid-feedback d-block">{{ errors.first('contactInfo') }}</div> | ||||
<div v-if="contactSubmitted && errors.has('email')" class="invalid-feedback d-block">{{ errors.first('email') }}</div> | <div v-if="contactSubmitted && errors.has('email')" class="invalid-feedback d-block">{{ errors.first('email') }}</div> | ||||
<div v-if="contactSubmitted && errors.has('phone')" class="invalid-feedback d-block">{{ errors.first('phone') }}</div> | <div v-if="contactSubmitted && errors.has('phone')" class="invalid-feedback d-block">{{ errors.first('phone') }}</div> | ||||
@@ -297,7 +321,8 @@ | |||||
</template> | </template> | ||||
<script> | <script> | ||||
import { mapState, mapActions } from 'vuex' | |||||
import { mapState, mapActions } from 'vuex'; | |||||
const QRCode = require('qrcode'); | |||||
function initNewContact () { | function initNewContact () { | ||||
return { | return { | ||||
@@ -330,18 +355,21 @@ | |||||
contacts: [], | contacts: [], | ||||
contactSubmitted: false, | contactSubmitted: false, | ||||
newContactSmsCountry: '', | newContactSmsCountry: '', | ||||
newContact: initNewContact() | |||||
newContact: initNewContact(), | |||||
verifyingContact: null, | |||||
inboundAction: null | |||||
} | } | ||||
}, | }, | ||||
computed: { | computed: { | ||||
...mapState('account', { | ...mapState('account', { | ||||
currentUser: state => state.user | currentUser: state => state.user | ||||
}), | }), | ||||
...mapState('account', ['actionStatus']), | |||||
...mapState('system', [ | ...mapState('system', [ | ||||
'messages', 'accountDeletionOptions', 'timeDurationOptions', 'timeDurationOptionsReversed', | 'messages', 'accountDeletionOptions', 'timeDurationOptions', 'timeDurationOptionsReversed', | ||||
'contactTypes', 'detectedLocale', 'countries' | 'contactTypes', 'detectedLocale', 'countries' | ||||
]), | ]), | ||||
...mapState('users', ['policy', 'policyStatus', 'contact']), | |||||
...mapState('users', ['policy', 'policyStatus', 'contact', 'authenticator']), | |||||
hasAuthenticator() { | hasAuthenticator() { | ||||
for (let i=0; i<this.contacts.length; i++) { | for (let i=0; i<this.contacts.length; i++) { | ||||
if (this.contacts[i].type === 'authenticator') return true; | if (this.contacts[i].type === 'authenticator') return true; | ||||
@@ -371,7 +399,10 @@ | |||||
} | } | ||||
}, | }, | ||||
methods: { | methods: { | ||||
...mapActions('users', ['getPolicyByUuid', 'updatePolicyByUuid', 'addPolicyContactByUuid', 'removePolicyContactByUuid']), | |||||
...mapActions('account', ['approveAction', 'denyAction']), | |||||
...mapActions('users', [ | |||||
'getPolicyByUuid', 'updatePolicyByUuid', 'addPolicyContactByUuid', 'removePolicyContactByUuid', | |||||
]), | |||||
updatePolicy(e) { | updatePolicy(e) { | ||||
this.submitted = true; | this.submitted = true; | ||||
this.updatePolicyByUuid({ | this.updatePolicyByUuid({ | ||||
@@ -417,11 +448,54 @@ | |||||
messages: this.messages, | messages: this.messages, | ||||
errors: this.errors | errors: this.errors | ||||
}); | }); | ||||
}, | |||||
startVerifyContact(contact) { | |||||
console.log('startVerifyContact: '+JSON.stringify(contact)); | |||||
this.verifyingContact = contact.uuid; | |||||
if (contact.type === 'authenticator') { | |||||
const canvas = document.getElementById('canvas_'+contact.uuid); | |||||
QRCode.toCanvas(canvas, this.authenticator.key, function (error) { | |||||
if (error) { | |||||
console.error('QR generation error: '+error); | |||||
} else { | |||||
console.log('QR generation success'); | |||||
} | |||||
}); | |||||
const backupCodes = document.getElementById('backupCodes_'+contact.uuid); | |||||
if (backupCodes != null && typeof this.authenticator.backupCodes !== 'undefined' && this.authenticator.backupCodes != null && this.authenticator.backupCodes.length > 0) { | |||||
backupCodes.innerText = this.authenticator.backupCodes.join(' '); | |||||
} else { | |||||
console.log('backupCodes element not found, or no backupCodes defined'); | |||||
} | |||||
} | |||||
return false; // do not follow the click | |||||
}, | |||||
cancelVerifyContact() { | |||||
this.verifyingContact = null; | |||||
this.errors.clear(); | |||||
return false; // do not follow the click | |||||
}, | |||||
submitVerification(uuid) { | |||||
const codeElementId = 'verifyContactCode_'+uuid; | |||||
const codeElement = document.getElementById(codeElementId); | |||||
if (codeElement != null) { | |||||
const code = codeElement.value; | |||||
this.errors.clear(); | |||||
this.approveAction({ | |||||
uuid: this.currentUser.uuid, | |||||
code: code, | |||||
messages: this.messages, | |||||
errors: this.errors | |||||
}); | |||||
console.log('submitVerification: would submit: ' + code); | |||||
} else { | |||||
console.log('submitVerification: DOM element not found: '+codeElementId); | |||||
} | |||||
} | } | ||||
}, | }, | ||||
watch: { | watch: { | ||||
policy (p) { | policy (p) { | ||||
console.log('watch.policy: received: '+JSON.stringify(p)); | |||||
// console.log('watch.policy: received: '+JSON.stringify(p)); | |||||
if (typeof p.deletionPolicy !== 'undefined' && p.deletionPolicy !== null) { | if (typeof p.deletionPolicy !== 'undefined' && p.deletionPolicy !== null) { | ||||
this.deletionPolicy = p.deletionPolicy; | this.deletionPolicy = p.deletionPolicy; | ||||
} | } | ||||
@@ -443,17 +517,40 @@ | |||||
this.newContact = initNewContact(); | this.newContact = initNewContact(); | ||||
}, | }, | ||||
contact (c) { | contact (c) { | ||||
console.log('watch.contact: received: '+JSON.stringify(c)); | |||||
// console.log('watch.contact: received: '+JSON.stringify(c)); | |||||
if (typeof c.error === 'undefined' || c.error === null) { | if (typeof c.error === 'undefined' || c.error === null) { | ||||
// force reload policy, refreshes contacts | // force reload policy, refreshes contacts | ||||
this.getPolicyByUuid({uuid: this.currentUser.uuid, messages: this.messages, errors: this.errors}); | this.getPolicyByUuid({uuid: this.currentUser.uuid, messages: this.messages, errors: this.errors}); | ||||
} | } | ||||
}, | |||||
actionStatus (status) { | |||||
console.log('watch.actionStatus: received: '+JSON.stringify(status)); | |||||
if (status.success) { | |||||
this.getPolicyByUuid({uuid: this.currentUser.uuid, messages: this.messages, errors: this.errors}); | |||||
} | |||||
} | } | ||||
}, | }, | ||||
created () { | created () { | ||||
this.getPolicyByUuid({uuid: this.currentUser.uuid, messages: this.messages, errors: this.errors}); | this.getPolicyByUuid({uuid: this.currentUser.uuid, messages: this.messages, errors: this.errors}); | ||||
console.log('PolicyPage.created: $route.params='+JSON.stringify(this.$route.query)); | |||||
if (this.$route.query.action) { | |||||
this.inboundAction = { | |||||
actionType: this.$route.query.action | |||||
}; | |||||
if (this.inboundAction.actionType === 'invalid') { | |||||
this.inboundAction.status = 'invalid'; | |||||
this.inboundAction.alertType = 'alert-danger'; | |||||
} else { | |||||
if (this.$route.query.ok) { | |||||
this.inboundAction.status = 'success'; | |||||
this.inboundAction.alertType = 'alert-success'; | |||||
} else { | |||||
this.inboundAction.status = 'failure'; | |||||
this.inboundAction.alertType = 'alert-danger'; | |||||
} | |||||
} | |||||
} | |||||
this.newContactSmsCountry = countryFromLocale(this.detectedLocale); | this.newContactSmsCountry = countryFromLocale(this.detectedLocale); | ||||
console.log('set this.newContactSmsCountry='+this.newContactSmsCountry); | |||||
} | } | ||||
}; | }; | ||||
</script> | </script> |