fix(admin): scope remembered list state to the signed-in admin and recover from bad restored queries
- Store list queries under summer-admin.list:<admin id>:<controller>; me() and setCurrentUser set the owner, which removes other admins' keys and the unscoped keys of older builds; nothing is read or written without one - clearUser removes every stored query, so logout, session expiry and an unrecoverable 401 (expireSession, now used by main.ts) all clear them - A list request built from a restored query that fails for any reason (422, 500, network) forgets the query and loads the plain list once - A failing URL query keeps the error and offers a reset button (backend::lang.list.reset_list, en and pl) - Document remembered list state in docs/backend/lists-and-filters.md - Rebuild modules/boardwalk/dist
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
// Admin session state. The JWT travels in an HttpOnly cookie (D-19): the SPA
|
||||
// keeps only the profile and the access lifetime, never a token.
|
||||
import { readonly, ref } from 'vue'
|
||||
import type { Router } from 'vue-router'
|
||||
import type { RouteLocationNormalizedLoaded, Router } from 'vue-router'
|
||||
import { api, onRefreshed, refreshSession } from '../api/client'
|
||||
import type { AdminProfile } from '../api/types'
|
||||
import { clearListStates } from './listState'
|
||||
import { setListStateOwner } from './listState'
|
||||
import { setNavigation } from './useNavigation'
|
||||
import { setSettings } from './useSettings'
|
||||
|
||||
@@ -48,10 +48,15 @@ export async function login(identifier: string, password: string): Promise<boole
|
||||
return true
|
||||
}
|
||||
|
||||
/** Loads the signed-in admin; null when the session is missing or expired. */
|
||||
/**
|
||||
* Loads the signed-in admin; null when the session is missing or expired.
|
||||
* The stored list queries follow the answer: a profile keeps only that
|
||||
* admin's (another admin's are removed, T-16.1-03), no profile removes all.
|
||||
*/
|
||||
export async function me(): Promise<AdminProfile | null> {
|
||||
const { data, response } = await api.GET('/auth/me')
|
||||
user.value = response.ok && data ? data.data : null
|
||||
setListStateOwner(user.value?.id ?? null)
|
||||
return user.value
|
||||
}
|
||||
|
||||
@@ -73,12 +78,35 @@ export function profileInitials(user: Pick<AdminProfile, 'first_name' | 'last_na
|
||||
/** Replaces the signed-in profile, e.g. with the one PUT /account returned. */
|
||||
export function setCurrentUser(profile: AdminProfile): void {
|
||||
user.value = profile
|
||||
setListStateOwner(profile.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Forgets the session on this device: the refresh timer, the profile and
|
||||
* every stored list query (search terms can hold personal data and never
|
||||
* outlive the session, T-16.1-03).
|
||||
*/
|
||||
export function clearUser(): void {
|
||||
cancelRefresh()
|
||||
user.value = null
|
||||
expiresIn.value = null
|
||||
setListStateOwner(null)
|
||||
}
|
||||
|
||||
/**
|
||||
* The session ended on its own (expiry, or a 401 the refresh could not
|
||||
* recover): clears the local session, stored list queries included, and
|
||||
* sends the admin to the login screen with the current path as redirect.
|
||||
*/
|
||||
export function expireSession(router: {
|
||||
currentRoute: { value: Pick<RouteLocationNormalizedLoaded, 'name' | 'fullPath'> }
|
||||
push: Router['push']
|
||||
}): void {
|
||||
clearUser()
|
||||
const current = router.currentRoute.value
|
||||
if (current.name !== 'login') {
|
||||
void router.push({ name: 'login', query: { redirect: current.fullPath } }).catch(() => undefined)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +123,6 @@ export async function logout(router?: Pick<Router, 'replace'>): Promise<void> {
|
||||
// Network failure: the session still ends on this device.
|
||||
} finally {
|
||||
clearUser()
|
||||
clearListStates()
|
||||
setNavigation([])
|
||||
setSettings([])
|
||||
}
|
||||
@@ -110,6 +137,7 @@ export function useAuth() {
|
||||
expiresIn: readonly(expiresIn),
|
||||
login,
|
||||
logout,
|
||||
expireSession,
|
||||
me,
|
||||
setCurrentUser,
|
||||
clearUser,
|
||||
|
||||
Reference in New Issue
Block a user