- Updated user statistics endpoint to include access token and hub tenant ID for improved data retrieval. - Refactored user listing functionality to support access token and hub tenant ID, ensuring accurate user data from the Hub. - Introduced new methods in UserService for fetching users with additional information from the Hub. - Enhanced security functions to ensure user-tenant relationships are maintained and synchronized with the Hub. - Improved frontend logic to handle company initialization and user authentication more effectively.
90 lines
3.2 KiB
TypeScript
90 lines
3.2 KiB
TypeScript
import { redirect } from '@sveltejs/kit';
|
|
import { env } from '$env/dynamic/private';
|
|
import type { LayoutServerLoad } from './$types';
|
|
import {
|
|
validateAuth,
|
|
getAuthTokens,
|
|
getUserCompanies,
|
|
clearAuthTokens
|
|
} from '$lib/server/api';
|
|
|
|
export const load: LayoutServerLoad = async ({ cookies, url, fetch }) => {
|
|
// Verificar si existe el token en las cookies
|
|
const { accessToken } = getAuthTokens(cookies);
|
|
console.log('[dashboard layout] access_token presente:', !!accessToken, '| url:', url.pathname);
|
|
|
|
// Si no hay token, redirigir al login, pero excluir la ruta /login para evitar bucle
|
|
if (!accessToken && url.pathname !== '/login') {
|
|
const redirectUrl = `/login?redirect=${encodeURIComponent(url.pathname)}`;
|
|
throw redirect(303, redirectUrl);
|
|
}
|
|
|
|
// Validar el token con el backend y obtener datos del usuario
|
|
// La función validateAuth maneja automáticamente el refresh de tokens
|
|
const redirectOnFail = `/login?redirect=${encodeURIComponent(url.pathname)}`;
|
|
|
|
try {
|
|
// Primero my-companies: ejecuta get_current_user y puede crear tenant/empresa/usuario
|
|
// antes de /me/profile en validateAuth (evita SSR sin la empresa recién provisionada).
|
|
const companies = await getUserCompanies(cookies, fetch);
|
|
|
|
const userData = await validateAuth(cookies, fetch, redirectOnFail);
|
|
|
|
// Si la cookie active_company_id apunta a una compañía que ya no existe, limpiarla
|
|
const cookieCompanyId = cookies.get('active_company_id');
|
|
if (cookieCompanyId) {
|
|
const cookieId = parseInt(cookieCompanyId);
|
|
const stillExists = companies.some((c) => c.id === cookieId);
|
|
if (!stillExists) {
|
|
cookies.delete('active_company_id', { path: '/' });
|
|
}
|
|
}
|
|
|
|
// Cargar los tenants del usuario desde Hub (fuente de verdad multi-tenant)
|
|
let userTenants: { id: number; name: string; slug: string }[] = [];
|
|
try {
|
|
const hubUrl = (env.INTERNAL_HUB_URL || env.HUB_URL || 'http://localhost:8001').replace(/\/+$/, '');
|
|
const tenantOverride = cookies.get('sso_tenant_id');
|
|
const tenantsRes = await fetch(`${hubUrl}/api/v1/auth/my-tenants`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${accessToken}`,
|
|
...(tenantOverride ? { 'X-Tenant-Override': tenantOverride } : {}),
|
|
},
|
|
});
|
|
if (tenantsRes.ok) {
|
|
userTenants = await tenantsRes.json();
|
|
}
|
|
} catch {
|
|
// No bloquear el dashboard si falla la carga de tenants
|
|
}
|
|
|
|
// Obtener la compañía activa de la cookie para persistencia
|
|
const activeCompanyId = cookies.get('active_company_id');
|
|
|
|
return {
|
|
authenticated: true,
|
|
user: { ...userData, token: accessToken },
|
|
companies,
|
|
activeCompanyId: activeCompanyId ? parseInt(activeCompanyId) : undefined,
|
|
userTenants,
|
|
error: undefined
|
|
};
|
|
} catch (error) {
|
|
// Si es un redirect, re-lanzarlo sin tocar las cookies
|
|
if (error && typeof error === 'object' && 'status' in error && 'location' in error) {
|
|
throw error;
|
|
}
|
|
|
|
// Si estamos ya en la página de login, no intentar redirigir de nuevo
|
|
if (url.pathname === '/login') {
|
|
console.error('🔐 [Dashboard] Error validando token en login page, limpiando cookies.');
|
|
clearAuthTokens(cookies);
|
|
return { authenticated: false, error: error };
|
|
}
|
|
|
|
// Para cualquier otro error (conexión, etc), limpiar token y redirigir
|
|
clearAuthTokens(cookies);
|
|
throw redirect(303, redirectOnFail);
|
|
}
|
|
};
|