feat: roles SPA foundations
This commit is contained in:
1 parent
80f7037d3a
commit
907949aa12
180 files changed
+4308
-835
No files matched your search
@@ -1,6 +1,10 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { ApiError, useApi, type MeAuthor, type UserRole } from '@/composables/useApi'
|
||||
import { ref } from 'vue'
|
||||
import { ApiError, useApi, type MeAuthor } from '@/composables/useApi'
|
||||
import type { Access } from '@/lib/permissions'
|
||||
|
||||
const REFUSAL_REFRESH_GAP_MS = 5000
|
||||
const STALE_AFTER_MS = 30000
|
||||
|
||||
export type SessionStatus = 'idle' | 'checking' | 'ready' | 'error'
|
||||
|
||||
@@ -10,7 +14,7 @@ export interface Session {
|
||||
username?: string
|
||||
email?: string
|
||||
displayName: string
|
||||
role?: UserRole
|
||||
access?: Access
|
||||
author?: MeAuthor
|
||||
}
|
||||
|
||||
@@ -19,10 +23,8 @@ export const useSessionStore = defineStore('session', () => {
|
||||
const session = ref<Session | null>(null)
|
||||
let pending: Promise<void> | null = null
|
||||
|
||||
const isOwner = computed(() => session.value?.role === 'owner')
|
||||
const canManageContent = computed(
|
||||
() => session.value?.role === 'owner' || session.value?.role === 'admin',
|
||||
)
|
||||
let lastAnswerAt: number | null = null
|
||||
let lastAttemptAt: number | null = null
|
||||
|
||||
function check() {
|
||||
if (pending) {
|
||||
@@ -36,6 +38,7 @@ export const useSessionStore = defineStore('session', () => {
|
||||
.then((result) => {
|
||||
session.value = result
|
||||
status.value = 'ready'
|
||||
lastAnswerAt = Date.now()
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error instanceof ApiError && error.status === 401) {
|
||||
@@ -59,13 +62,31 @@ export const useSessionStore = defineStore('session', () => {
|
||||
|
||||
async function refresh() {
|
||||
const { getMe } = useApi()
|
||||
lastAttemptAt = Date.now()
|
||||
try {
|
||||
session.value = await getMe()
|
||||
lastAnswerAt = Date.now()
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshAfterRefusal() {
|
||||
if (lastAttemptAt !== null && Date.now() - lastAttemptAt < REFUSAL_REFRESH_GAP_MS) {
|
||||
return
|
||||
}
|
||||
await refresh()
|
||||
}
|
||||
|
||||
async function refreshIfStale() {
|
||||
if (!session.value || lastAnswerAt === null) {
|
||||
return
|
||||
}
|
||||
if (Date.now() - lastAnswerAt > STALE_AFTER_MS) {
|
||||
await refresh()
|
||||
}
|
||||
}
|
||||
|
||||
function setAuthor(author: MeAuthor | undefined) {
|
||||
if (!session.value) {
|
||||
return
|
||||
@@ -87,13 +108,21 @@ export const useSessionStore = defineStore('session', () => {
|
||||
return {
|
||||
status,
|
||||
session,
|
||||
isOwner,
|
||||
canManageContent,
|
||||
check,
|
||||
retry,
|
||||
refresh,
|
||||
refreshAfterRefusal,
|
||||
refreshIfStale,
|
||||
clear,
|
||||
setAuthor,
|
||||
setDisplayName,
|
||||
}
|
||||
})
|
||||
|
||||
export function refreshSessionWhenVisible() {
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
void useSessionStore().refreshIfStale()
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user