Files
opencloud/src/stores/auth.ts
T
2026-07-30 22:35:51 +08:00

132 lines
3.1 KiB
TypeScript

import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import {
AUTH_EXPIRED_EVENT,
AUTH_UPDATED_EVENT,
apiRequest,
clearAccessToken,
refreshSession,
setAccessToken,
} from '@/lib/api'
import type { AuthResponse, AuthUser } from '@/types/api'
import type { Profile } from '@/types/database'
export const useAuthStore = defineStore('auth', () => {
const user = ref<AuthUser | null>(null)
const profile = ref<Profile | null>(null)
const loading = ref(true)
let listenersAttached = false
const isLoggedIn = computed(() => !!user.value)
const isAdmin = computed(() => profile.value?.role === 'admin')
function applyAuth(auth: AuthResponse) {
setAccessToken(auth.access_token)
user.value = auth.user
profile.value = {
id: auth.user.id,
username: auth.user.username,
avatar_url: auth.user.avatar_url,
role: auth.user.role,
is_disabled: auth.user.is_disabled,
created_at: auth.user.created_at,
}
}
function clearAuth() {
clearAccessToken()
user.value = null
profile.value = null
}
async function login(email: string, password: string) {
const auth = await apiRequest<AuthResponse>('/auth/login', {
method: 'POST',
auth: false,
body: { email, password },
})
applyAuth(auth)
}
async function register(email: string, password: string, username: string) {
await apiRequest('/auth/register', {
method: 'POST',
auth: false,
body: { email, password, username },
})
}
async function logout() {
try {
await apiRequest('/auth/logout', { method: 'POST', retry: false })
} finally {
clearAuth()
}
}
async function updateUsername(username: string) {
const updatedUser = await apiRequest<AuthUser>('/profiles/me', {
method: 'PATCH',
body: { username },
})
user.value = updatedUser
profile.value = {
id: updatedUser.id,
username: updatedUser.username,
avatar_url: updatedUser.avatar_url,
role: updatedUser.role,
is_disabled: updatedUser.is_disabled,
created_at: updatedUser.created_at,
}
}
async function updatePassword(password: string) {
const auth = await apiRequest<AuthResponse>('/auth/password', {
method: 'PATCH',
body: { password },
})
applyAuth(auth)
}
async function sendPasswordReset(email: string) {
await apiRequest('/auth/forgot-password', {
method: 'POST',
auth: false,
body: { email },
})
}
async function initialize() {
if (!listenersAttached) {
window.addEventListener(AUTH_UPDATED_EVENT, event => {
applyAuth((event as CustomEvent<AuthResponse>).detail)
})
window.addEventListener(AUTH_EXPIRED_EVENT, clearAuth)
listenersAttached = true
}
try {
applyAuth(await refreshSession())
} catch {
clearAuth()
} finally {
loading.value = false
}
}
return {
user,
profile,
loading,
isLoggedIn,
isAdmin,
login,
register,
logout,
updateUsername,
updatePassword,
sendPasswordReset,
initialize,
}
})