feat: persist link share auth rule in url hash (#3336)

Reviewed-on: vikunja/frontend#3336
This commit is contained in:
konrad 2023-06-19 14:26:32 +00:00
commit da3eaf0d35
5 changed files with 77 additions and 22 deletions

View File

@ -56,11 +56,13 @@ import {useOnline} from '@/composables/useOnline'
import {getAuthForRoute} from '@/router' import {getAuthForRoute} from '@/router'
import {useBaseStore} from '@/stores/base' import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const baseStore = useBaseStore() const baseStore = useBaseStore()
const authStore = useAuthStore()
const ready = computed(() => baseStore.ready) const ready = computed(() => baseStore.ready)
const online = useOnline() const online = useOnline()
@ -72,7 +74,7 @@ async function load() {
try { try {
await baseStore.loadApp() await baseStore.loadApp()
baseStore.setReady(true) baseStore.setReady(true)
const redirectTo = await getAuthForRoute(route) const redirectTo = await getAuthForRoute(route, authStore)
if (typeof redirectTo !== 'undefined') { if (typeof redirectTo !== 'undefined') {
await router.push(redirectTo) await router.push(redirectTo)
} }

View File

@ -5,22 +5,31 @@ export function useRedirectToLastVisited() {
const router = useRouter() const router = useRouter()
function redirectIfSaved() { function getLastVisitedRoute() {
const last = getLastVisited() const last = getLastVisited()
if (last !== null) { if (last === null) {
router.push({ return null
name: last.name,
params: last.params,
query: last.query,
})
clearLastVisited()
return
} }
router.push({name: 'home'}) clearLastVisited()
return {
name: last.name,
params: last.params,
query: last.query,
}
}
function redirectIfSaved() {
const lastRoute = getLastVisitedRoute()
if (!lastRoute) {
return router.push({name: 'home'})
}
return router.push(lastRoute)
} }
return { return {
redirectIfSaved, redirectIfSaved,
getLastVisitedRoute,
} }
} }

View File

@ -0,0 +1 @@
export const LINK_SHARE_HASH_PREFIX = '#share-auth-token='

View File

@ -6,6 +6,7 @@ import {saveProjectView, getProjectView} from '@/helpers/projectView'
import {parseDateOrString} from '@/helpers/time/parseDateOrString' import {parseDateOrString} from '@/helpers/time/parseDateOrString'
import {getNextWeekDate} from '@/helpers/time/getNextWeekDate' import {getNextWeekDate} from '@/helpers/time/getNextWeekDate'
import {setTitle} from '@/helpers/setTitle' import {setTitle} from '@/helpers/setTitle'
import {LINK_SHARE_HASH_PREFIX} from '@/constants/linkShareHash'
import {useProjectStore} from '@/stores/projects' import {useProjectStore} from '@/stores/projects'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
@ -80,7 +81,7 @@ const router = createRouter({
} }
// Scroll to anchor should still work // Scroll to anchor should still work
if (to.hash) { if (to.hash && !to.hash.startsWith(LINK_SHARE_HASH_PREFIX)) {
return {el: to.hash} return {el: to.hash}
} }
@ -442,8 +443,7 @@ const router = createRouter({
], ],
}) })
export async function getAuthForRoute(route: RouteLocation) { export async function getAuthForRoute(to: RouteLocation, authStore) {
const authStore = useAuthStore()
if (authStore.authUser || authStore.authLinkShare) { if (authStore.authUser || authStore.authLinkShare) {
return return
} }
@ -464,26 +464,52 @@ export async function getAuthForRoute(route: RouteLocation) {
'user.register', 'user.register',
'link-share.auth', 'link-share.auth',
'openid.auth', 'openid.auth',
].includes(route.name as string) && ].includes(to.name as string) &&
localStorage.getItem('passwordResetToken') === null && localStorage.getItem('passwordResetToken') === null &&
localStorage.getItem('emailConfirmToken') === null && localStorage.getItem('emailConfirmToken') === null &&
!(route.name === 'home' && (typeof route.query.userPasswordReset !== 'undefined' || typeof route.query.userEmailConfirm !== 'undefined')) !(to.name === 'home' && (typeof to.query.userPasswordReset !== 'undefined' || typeof to.query.userEmailConfirm !== 'undefined'))
) { ) {
saveLastVisited(route.name as string, route.params, route.query) saveLastVisited(to.name as string, to.params, to.query)
return {name: 'user.login'} return {name: 'user.login'}
} }
if(localStorage.getItem('passwordResetToken') !== null && route.name !== 'user.password-reset.reset') { if(localStorage.getItem('passwordResetToken') !== null && to.name !== 'user.password-reset.reset') {
return {name: 'user.password-reset.reset'} return {name: 'user.password-reset.reset'}
} }
if(localStorage.getItem('emailConfirmToken') !== null && route.name !== 'user.login') { if(localStorage.getItem('emailConfirmToken') !== null && to.name !== 'user.login') {
return {name: 'user.login'} return {name: 'user.login'}
} }
} }
router.beforeEach(async (to) => { router.beforeEach(async (to, from) => {
return getAuthForRoute(to) const authStore = useAuthStore()
if(from.hash && from.hash.startsWith(LINK_SHARE_HASH_PREFIX)) {
to.hash = from.hash
}
if (to.hash.startsWith(LINK_SHARE_HASH_PREFIX) && !authStore.authLinkShare) {
saveLastVisited(to.name as string, to.params, to.query)
return {
name: 'link-share.auth',
params: {
share: to.hash.replace(LINK_SHARE_HASH_PREFIX, ''),
},
}
}
const newRoute = await getAuthForRoute(to, authStore)
if(newRoute) {
return {
...newRoute,
hash: to.hash,
}
}
if(!to.fullPath.endsWith(to.hash)) {
return to.fullPath + to.hash
}
}) })
export default router export default router

View File

@ -40,12 +40,15 @@ import {useTitle} from '@vueuse/core'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import {PROJECT_VIEWS, type ProjectView} from '@/types/ProjectView' import {PROJECT_VIEWS, type ProjectView} from '@/types/ProjectView'
import {LINK_SHARE_HASH_PREFIX} from '@/constants/linkShareHash'
import {useBaseStore} from '@/stores/base' import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
import {useRedirectToLastVisited} from '@/composables/useRedirectToLastVisited'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
useTitle(t('sharing.authenticating')) useTitle(t('sharing.authenticating'))
const {getLastVisitedRoute} = useRedirectToLastVisited()
function useAuth() { function useAuth() {
const baseStore = useBaseStore() const baseStore = useBaseStore()
@ -87,7 +90,21 @@ function useAuth() {
? route.query.view ? route.query.view
: 'list' : 'list'
router.push({name: `project.${view}`, params: {projectId}}) const hash = LINK_SHARE_HASH_PREFIX + route.params.share
const last = getLastVisitedRoute()
if (last) {
return router.push({
...last,
hash,
})
}
return router.push({
name: `project.${view}`,
params: {projectId},
hash,
})
} catch (e: any) { } catch (e: any) {
if (e.response?.data?.code === 13001) { if (e.response?.data?.code === 13001) {
authenticateWithPassword.value = true authenticateWithPassword.value = true