mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-24 14:02:09 +02:00
Add Starter middleware & Restore the Data have changed notification
This commit is contained in:
parent
4dbbae24dc
commit
8c23aa884f
@ -47,7 +47,16 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<notifications id="vueNotification" role="alert" width="100%" position="top" :duration="4000" :speed="0" :max="1" classes="notification is-radiusless" />
|
<notifications
|
||||||
|
id="vueNotification"
|
||||||
|
role="alert"
|
||||||
|
width="100%"
|
||||||
|
position="top"
|
||||||
|
:duration="4000"
|
||||||
|
:speed="0"
|
||||||
|
:max="1"
|
||||||
|
classes="notification is-radiusless"
|
||||||
|
:dangerouslySetInnerHtml="true" />
|
||||||
<main class="main-section">
|
<main class="main-section">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</main>
|
</main>
|
||||||
|
5
resources/js_vue3/router/index.js
vendored
5
resources/js_vue3/router/index.js
vendored
@ -27,7 +27,8 @@ import EditCredential from '../views/settings/Credentials/Edit.vue'
|
|||||||
import Errors from '../views/Error.vue'
|
import Errors from '../views/Error.vue'
|
||||||
import About from '../views/About.vue'
|
import About from '../views/About.vue'
|
||||||
|
|
||||||
import authGuard from './middlewares/authGuard'
|
import authGuard from './middlewares/authGuard'
|
||||||
|
import starter from './middlewares/starter'
|
||||||
import noEmptyError from './middlewares/noEmptyError'
|
import noEmptyError from './middlewares/noEmptyError'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
@ -36,7 +37,7 @@ const router = createRouter({
|
|||||||
{ path: '/start', name: 'start', component: Start, meta: { middlewares: [authGuard] } },
|
{ path: '/start', name: 'start', component: Start, meta: { middlewares: [authGuard] } },
|
||||||
{ path: '/capture', name: 'capture', component: Capture, meta: { middlewares: [authGuard] } },
|
{ path: '/capture', name: 'capture', component: Capture, meta: { middlewares: [authGuard] } },
|
||||||
|
|
||||||
{ path: '/accounts', name: 'accounts', component: Accounts, meta: { middlewares: [authGuard] }, alias: '/' },
|
{ path: '/accounts', name: 'accounts', component: Accounts, meta: { middlewares: [authGuard, starter] }, alias: '/' },
|
||||||
{ path: '/account/create', name: 'createAccount', component: CreateAccount, meta: { middlewares: [authGuard] } },
|
{ path: '/account/create', name: 'createAccount', component: CreateAccount, meta: { middlewares: [authGuard] } },
|
||||||
{ path: '/account/import', name: 'importAccounts', component: ImportAccount, meta: { middlewares: [authGuard] } },
|
{ path: '/account/import', name: 'importAccounts', component: ImportAccount, meta: { middlewares: [authGuard] } },
|
||||||
{ path: '/account/:twofaccountId/edit', name: 'editAccount', component: EditAccount, meta: { middlewares: [authGuard] } },
|
{ path: '/account/:twofaccountId/edit', name: 'editAccount', component: EditAccount, meta: { middlewares: [authGuard] } },
|
||||||
|
19
resources/js_vue3/router/middlewares/starter.js
vendored
Normal file
19
resources/js_vue3/router/middlewares/starter.js
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { useTwofaccounts } from '@/stores/twofaccounts'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the user to access the main view only if he owns at least one twofaccount.
|
||||||
|
* Push to the starter view otherwise.
|
||||||
|
*/
|
||||||
|
export default function starter({ to, next }) {
|
||||||
|
const twofaccounts = useTwofaccounts()
|
||||||
|
|
||||||
|
if (twofaccounts.isEmpty) {
|
||||||
|
twofaccounts.refresh().then(() => {
|
||||||
|
if (twofaccounts.isEmpty) {
|
||||||
|
next({ name: 'start' });
|
||||||
|
}
|
||||||
|
else next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else next()
|
||||||
|
}
|
30
resources/js_vue3/stores/twofaccounts.js
vendored
30
resources/js_vue3/stores/twofaccounts.js
vendored
@ -51,8 +51,8 @@ export const useTwofaccounts = defineStore({
|
|||||||
return state.items.map(a => a.id)
|
return state.items.map(a => a.id)
|
||||||
},
|
},
|
||||||
|
|
||||||
isNotEmpty(state) {
|
isEmpty(state) {
|
||||||
return state.items.length > 0
|
return state.items.length == 0
|
||||||
},
|
},
|
||||||
|
|
||||||
count(state) {
|
count(state) {
|
||||||
@ -83,6 +83,32 @@ export const useTwofaccounts = defineStore({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the store is up-to-date with the backend
|
||||||
|
*/
|
||||||
|
async isUpToDateWithBackend() {
|
||||||
|
let isUpToDate = true
|
||||||
|
await twofaccountService.getAll().then(response => {
|
||||||
|
isUpToDate = response.data.length === this.items.length
|
||||||
|
|
||||||
|
this.items.forEach((item) => {
|
||||||
|
let matchingBackendItem = response.data.find(e => e.id === item.id)
|
||||||
|
if (matchingBackendItem == undefined) {
|
||||||
|
isUpToDate = false
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const field in item) {
|
||||||
|
if (item[field] != matchingBackendItem[field]) {
|
||||||
|
isUpToDate = false
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return isUpToDate
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an account to the current selection
|
* Adds an account to the current selection
|
||||||
*/
|
*/
|
||||||
|
@ -51,32 +51,20 @@
|
|||||||
* Returns whether or not the accounts should be displayed
|
* Returns whether or not the accounts should be displayed
|
||||||
*/
|
*/
|
||||||
const showAccounts = computed(() => {
|
const showAccounts = computed(() => {
|
||||||
return twofaccounts.isNotEmpty && !showGroupSwitch.value && !showDestinationGroupSelector.value
|
return !twofaccounts.isEmpty && !showGroupSwitch.value && !showDestinationGroupSelector.value
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
// we don't have to fetch fresh data so we try to load them from localstorage to avoid display latency
|
// This SFC is reached only if the user has some twofaccounts in the store (see the starter middleware).
|
||||||
// if( user.preferences.getOtpOnRequest && !this.toRefresh && !this.$route.params.isFirstLoad ) {
|
// This allows to display accounts without latency.
|
||||||
// const accounts = this.$storage.get('accounts', null) // use null as fallback if localstorage is empty
|
// We now check the twofaccounts store state in case the backend data have changed.
|
||||||
// if( accounts ) this.accounts = accounts
|
const isUpToDate = await twofaccounts.isUpToDateWithBackend()
|
||||||
|
if (! isUpToDate) {
|
||||||
// const groups = this.$storage.get('groups', null) // use null as fallback if localstorage is empty
|
notify.action({
|
||||||
// if( groups ) this.groups = groups
|
text: '<span class="is-size-7">' + trans('commons.data_have_changed_on_server_side') + '</span><br /><a href="." class="button is-rounded is-warning is-small">' + trans('commons.reload') + '</a>',
|
||||||
// }
|
duration: -1
|
||||||
|
})
|
||||||
// We fetch fresh data whatever. The user will be notified to reload the page if there are any data changes
|
}
|
||||||
twofaccounts.refresh()
|
|
||||||
groups.refresh()
|
|
||||||
|
|
||||||
// if (twofaccounts.count === 0) {
|
|
||||||
// // No account yet, we force user to land on the start view.
|
|
||||||
// router.push({ name: 'start' });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// stop OTP generation on modal close
|
|
||||||
// this.$on('modalClose', function() {
|
|
||||||
// this.$refs.OtpDisplayer.clearOTP()
|
|
||||||
// })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<VueFooter :showButtons="true" >
|
<VueFooter :showButtons="true" >
|
||||||
<!-- back button -->
|
<!-- back button -->
|
||||||
<p class="control" v-if="twofaccounts.length > 0">
|
<p class="control" v-if="! twofaccounts.isEmpty">
|
||||||
<UseColorMode v-slot="{ mode }">
|
<UseColorMode v-slot="{ mode }">
|
||||||
<RouterLink id="lnkBack" class="button is-rounded" :class="{'is-dark' : mode == 'dark'}" :to="{ name: 'accounts' }" >
|
<RouterLink id="lnkBack" class="button is-rounded" :class="{'is-dark' : mode == 'dark'}" :to="{ name: 'accounts' }" >
|
||||||
{{ $t('commons.back') }}
|
{{ $t('commons.back') }}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user