feat: add tenant and user management with migrations, handlers, and tests
- Implemented tenant and user management features including: - Tenant creation and management with associated migrations. - User creation and management with associated migrations. - Tenant membership management with associated migrations. - Platform user roles management with associated migrations. - Quota management with associated migrations. - Article and template management with associated migrations. - Added HTTP handlers for templates and workspaces. - Created tests for protected and public routes. - Introduced a script to check tenant scope in SQL queries. - Documented task plan for backend completion and frontend foundation.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
import type { LoginRequest, UserInfo } from "@geo/shared-types";
|
||||
|
||||
import { authApi } from "@/lib/api";
|
||||
import {
|
||||
clearStoredSession,
|
||||
readStoredSession,
|
||||
setStoredTokens,
|
||||
setStoredUser,
|
||||
subscribeStoredSession,
|
||||
type SessionSnapshot,
|
||||
} from "@/lib/session";
|
||||
|
||||
export const useAuthStore = defineStore("auth", () => {
|
||||
const accessToken = ref<string | null>(null);
|
||||
const refreshToken = ref<string | null>(null);
|
||||
const user = ref<UserInfo | null>(null);
|
||||
const initialized = ref(false);
|
||||
let unsubscribe: (() => void) | null = null;
|
||||
|
||||
function sync(snapshot: SessionSnapshot = readStoredSession()): void {
|
||||
accessToken.value = snapshot.accessToken;
|
||||
refreshToken.value = snapshot.refreshToken;
|
||||
user.value = snapshot.user;
|
||||
}
|
||||
|
||||
async function bootstrap(): Promise<void> {
|
||||
if (!unsubscribe) {
|
||||
unsubscribe = subscribeStoredSession(sync);
|
||||
}
|
||||
|
||||
sync();
|
||||
if (accessToken.value) {
|
||||
try {
|
||||
const currentUser = await authApi.me();
|
||||
setStoredUser(currentUser);
|
||||
} catch {
|
||||
clearStoredSession();
|
||||
}
|
||||
}
|
||||
|
||||
initialized.value = true;
|
||||
}
|
||||
|
||||
async function login(payload: LoginRequest): Promise<UserInfo> {
|
||||
const response = await authApi.login(payload);
|
||||
setStoredTokens({
|
||||
accessToken: response.access_token,
|
||||
refreshToken: response.refresh_token,
|
||||
});
|
||||
setStoredUser(response.user);
|
||||
return response.user;
|
||||
}
|
||||
|
||||
async function logout(): Promise<void> {
|
||||
try {
|
||||
if (accessToken.value) {
|
||||
await authApi.logout();
|
||||
}
|
||||
} finally {
|
||||
clearStoredSession();
|
||||
}
|
||||
}
|
||||
|
||||
const isAuthenticated = computed(() => Boolean(accessToken.value && user.value));
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
user,
|
||||
initialized,
|
||||
isAuthenticated,
|
||||
bootstrap,
|
||||
login,
|
||||
logout,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { createPinia } from "pinia";
|
||||
|
||||
export const pinia = createPinia();
|
||||
|
||||
Reference in New Issue
Block a user