diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py index bd014a1..78052c6 100644 --- a/backend/app/api/deps.py +++ b/backend/app/api/deps.py @@ -92,7 +92,7 @@ async def get_current_user( # Roles globales (is_global) pueden operar en cualquier tenant → omitir chequeo. # Roles de cliente (is_client) deben coincidir con su propio tenant. request_tenant_id = getattr(getattr(request, "state", None), "tenant_id", None) - if request_tenant_id and user.role.is_client and str(user.tenant_id) != str(request_tenant_id): + if request_tenant_id and not user.role.is_global and str(user.tenant_id) != str(request_tenant_id): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Tenant header does not match authenticated user", diff --git a/backend/app/api/v1/endpoints/auth.py b/backend/app/api/v1/endpoints/auth.py index bc024bd..296e99c 100644 --- a/backend/app/api/v1/endpoints/auth.py +++ b/backend/app/api/v1/endpoints/auth.py @@ -481,6 +481,7 @@ async def get_current_user( "role": user.role.value if hasattr(user.role, 'value') else user.role, "tenant_id": str(user.tenant_id), "tenant_name": user.tenant.name if user.tenant else None, + "tenant_slug": user.tenant.slug if user.tenant else None, "is_active": user.is_active, "is_two_factor_enabled": user.totp_secret is not None, "last_login": user.last_login.isoformat() if user.last_login else None, diff --git a/backend/app/api/v1/endpoints/tenants.py b/backend/app/api/v1/endpoints/tenants.py index 2f47ffb..b9d001a 100644 --- a/backend/app/api/v1/endpoints/tenants.py +++ b/backend/app/api/v1/endpoints/tenants.py @@ -34,7 +34,9 @@ async def create_tenant( if result.scalar_one_or_none(): raise HTTPException(status_code=400, detail="Tenant slug already exists") - db_tenant = Tenant(**tenant.model_dump()) + data = tenant.model_dump() + data['slug'] = data['slug'].lower().strip() + db_tenant = Tenant(**data) db.add(db_tenant) await db.commit() await db.refresh(db_tenant) diff --git a/backend/auth_backup.ts b/backend/auth_backup.ts deleted file mode 100644 index 4acf562..0000000 --- a/backend/auth_backup.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { Writable } from 'svelte/store'; -import { writable } from 'svelte/store'; -export interface User { - id: string; - email: string; - first_name: string; - last_name: string; - tenant_id: string; - role: 'CLIENT_ADMIN' | 'CLIENT_USER'; - is_active: boolean; - is_two_factor_enabled: boolean; - created_at: string; -} -export interface AuthState { - user: User | null; - token: string | null; - isAuthenticated: boolean; - isLoading: boolean; -} -export interface LoginRequest { - email: string; - password: string; - tenant_slug: string; - totp_code?: string; -} -export interface LoginResponse { - access_token: string; - token_type: string; - expires_in: number; - user: User; -} -const initialState: AuthState = { - user: null, - token: null, - isAuthenticated: false, - isLoading: false -}; -function createAuthStore() { - const { subscribe, set, update }: Writable = writable(initialState); - let _state = initialState; - subscribe(s => { _state = s; }); - return { - subscribe, - init: async () => { - if (typeof window !== 'undefined') { - try { - const response = await fetch('/api/v1/auth/me', { - credentials: 'include', - headers: { 'X-App': 'client', 'X-Tenant-Slug': 'aduanasoft' } - }); - if (response.ok) { - const user = await response.json(); - set({ user, token: null, isAuthenticated: true, isLoading: false }); - } - } catch (error) {} - } - }, - login: async (credentials: LoginRequest): Promise => { - update(state => ({ ...state, isLoading: true })); - try { - const response = await fetch('/api/v1/auth/login', { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - 'X-Tenant-Slug': credentials.tenant_slug, - }, - body: JSON.stringify(credentials) - }); - if (!response.ok) { - const error = await response.json(); - throw new Error(error.detail || 'Login failed'); - } - const data: LoginResponse = await response.json(); - set({ user: data.user, token: data.access_token, isAuthenticated: true, isLoading: false }); - } catch (error) { - update(state => ({ ...state, isLoading: false })); - throw error; - } - }, - logout: async () => { - try { - const token = _state.token; - await fetch('/api/v1/auth/logout', { - method: 'POST', - credentials: 'include', - headers: { - 'X-App': 'client', - 'X-Tenant-Slug': 'aduanasoft', - ...(token ? { 'Authorization': `Bearer ${token}` } : {}) - } - }); - } catch {} - set(initialState); - if (typeof window !== 'undefined') { - window.location.href = '/login'; - } - }, - updateUser: (user: User) => { update(state => ({ ...state, user })); }, - setUser: (user: User) => { set({ user, token: null, isAuthenticated: true, isLoading: false }); }, - setLoading: (isLoading: boolean) => { update(state => ({ ...state, isLoading })); } - }; -} -export const auth = createAuthStore(); \ No newline at end of file diff --git a/backend/check_lines.py b/backend/check_lines.py deleted file mode 100644 index 378adfc..0000000 --- a/backend/check_lines.py +++ /dev/null @@ -1,6 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - lines = f.readlines() - -for i, line in enumerate(lines): - if "tenant_id == current_user.tenant_id" in line: - print(f"Linea {i+1}: {line.rstrip()}") diff --git a/backend/check_user.py b/backend/check_user.py deleted file mode 100644 index 637289d..0000000 --- a/backend/check_user.py +++ /dev/null @@ -1,14 +0,0 @@ -import asyncio -from app.core.database import AsyncSessionLocal -from app.models.user import User -from sqlalchemy import select -import uuid - -async def check(): - async with AsyncSessionLocal() as db: - result = await db.execute(select(User)) - users = result.scalars().all() - for u in users: - print(f"ID: {u.id} | Email: {u.email} | Tenant: {u.tenant_id} | Rol: {u.role}") - -asyncio.run(check()) diff --git a/backend/debug_tenant.py b/backend/debug_tenant.py new file mode 100644 index 0000000..801923a --- /dev/null +++ b/backend/debug_tenant.py @@ -0,0 +1,19 @@ +import asyncio +from app.core.database import AsyncSessionLocal +from app.models.user import User +from app.models.tenant import Tenant +from sqlalchemy import select + +async def check(): + async with AsyncSessionLocal() as db: + result = await db.execute( + select(User, Tenant).join(Tenant).where(User.email == 'javier@ventas.com') + ) + user, tenant = result.one() + print(f"user.tenant_id: {user.tenant_id}") + print(f"tenant.id: {tenant.id}") + print(f"tenant.slug: {tenant.slug}") + print(f"user.role: {user.role}") + print(f"role.is_client: {user.role.is_client}") + +asyncio.run(check()) diff --git a/backend/fix_response.py b/backend/fix_response.py deleted file mode 100644 index b5ecf13..0000000 --- a/backend/fix_response.py +++ /dev/null @@ -1,16 +0,0 @@ -with open("/app/app/api/v1/endpoints/auth.py", "r") as f: - lines = f.readlines() - -# Linea 286 (0-indexed 285): "tenant_id": str(user.tenant_id), -# Agregar tenant_slug despues de tenant_id -for i, line in enumerate(lines): - if '"tenant_id": str(user.tenant_id),' in line: - indent = " " - new_line = indent + '"tenant_slug": tenant.slug if tenant else str(user.tenant_id),\n' - lines.insert(i + 1, new_line) - print(f"OK: tenant_slug agregado en linea {i+2}") - break - -with open("/app/app/api/v1/endpoints/auth.py", "w") as f: - f.writelines(lines) -print("Listo") diff --git a/backend/fix_syntax.py b/backend/fix_syntax.py deleted file mode 100644 index 2d591c9..0000000 --- a/backend/fix_syntax.py +++ /dev/null @@ -1,18 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py") as f: - lines = f.readlines() - -new_block = [ - " if current_user.role.value == 'ADMIN':\n", - " query = select(User).where(User.id == user_id)\n", - " else:\n", - " query = select(User).where(\n", - " User.id == user_id,\n", - " User.tenant_id == current_user.tenant_id\n", - " )\n", -] - -lines[150:161] = new_block - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.writelines(lines) -print("Listo") diff --git a/backend/fix_users.py b/backend/fix_users.py deleted file mode 100644 index c048025..0000000 --- a/backend/fix_users.py +++ /dev/null @@ -1,28 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - content = f.read() - -old1 = " User.tenant_id == current_user.tenant_id # " + "\u2705" + " Seguridad multi-tenant" -new1 = """ from app.models.user import UserRole as _UserRole - if current_user.role == _UserRole.ADMIN: - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - )""" - -if old1 in content: - content = content.replace(old1, new1) - print("OK bloque 1") -else: - print("SKIP bloque 1 - buscando alternativa") - old1b = " User.tenant_id == current_user.tenant_id\n )\n result = await db.execute(query)\n if not user:" - new1b = " User.tenant_id == current_user.tenant_id\n )\n result = await db.execute(query)\n if not user:" - print("Lineas con tenant_id encontradas:") - for i, line in enumerate(content.split("\n")): - if "tenant_id == current_user.tenant_id" in line: - print(f" Linea {i}: {line}") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.write(content) -print("Listo") diff --git a/backend/fix_users2.py b/backend/fix_users2.py deleted file mode 100644 index 61ba1b9..0000000 --- a/backend/fix_users2.py +++ /dev/null @@ -1,60 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - content = f.read() - -from app.models.user import UserRole as _UserRole - -# Reemplazar el patron comun de query con filtro de tenant -# por una version que permite a ADMIN ver todos los tenants - -old_get_user = """ query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - user = result.scalar_one_or_none() - if not user:""" - -new_get_user = """ if current_user.role.value == "ADMIN": - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - user = result.scalar_one_or_none() - if not user:""" - -old_update_user = """ query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - if not db_user:""" - -new_update_user = """ if current_user.role.value == "ADMIN": - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - if not db_user:""" - -count = 0 -for old, new in [(old_get_user, new_get_user), (old_update_user, new_update_user)]: - occurrences = content.count(old) - if occurrences > 0: - content = content.replace(old, new) - count += occurrences - print(f"OK: {occurrences} ocurrencia(s) reemplazada(s)") - else: - print(f"SKIP: bloque no encontrado") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.write(content) - -print(f"Total: {count} reemplazos aplicados") diff --git a/backend/fix_users3.py b/backend/fix_users3.py deleted file mode 100644 index 4f8e7fb..0000000 --- a/backend/fix_users3.py +++ /dev/null @@ -1,36 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - content = f.read() - -old1 = """ # Buscar usuario - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - - if not db_user:""" - -new1 = """ # Buscar usuario - ADMIN global puede editar cualquier tenant - if current_user.role.value == "ADMIN": - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - - if not db_user:""" - -count = content.count(old1) -if count > 0: - content = content.replace(old1, new1) - print(f"OK: {count} bloques reemplazados") -else: - print("ERROR: bloque no encontrado") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.write(content) -print("Listo") diff --git a/backend/fix_users4.py b/backend/fix_users4.py deleted file mode 100644 index 4ee96b7..0000000 --- a/backend/fix_users4.py +++ /dev/null @@ -1,38 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - lines = f.readlines() - -admin_check = [ - " # Buscar usuario - ADMIN global puede editar cualquier tenant\n", - " if current_user.role.value == \"ADMIN\":\n", - " query = select(User).where(User.id == user_id)\n", - " else:\n", - " query = select(User).where(\n", - " User.id == user_id,\n", - " User.tenant_id == current_user.tenant_id\n", - " )\n", -] - -# Reemplazar bloques en lineas 198, 305, 382 (0-indexed: 197, 304, 381) -replaced = 0 -new_lines = lines[:] -i = 0 -while i < len(new_lines): - if (new_lines[i].strip() == "# Buscar usuario" and - i+1 < len(new_lines) and "select(User).where(" in new_lines[i+1] and - i+2 < len(new_lines) and "User.id == user_id," in new_lines[i+2] and - i+3 < len(new_lines) and "User.tenant_id == current_user.tenant_id" in new_lines[i+3]): - - indent = " " - new_block = admin_check[:] - # Remove old 4 lines of query block (comment + query 4 lines) - new_lines[i:i+5] = new_block - replaced += 1 - i += len(new_block) - else: - i += 1 - -print(f"Reemplazos realizados: {replaced}") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.writelines(new_lines) -print("Listo") diff --git a/backend/show_context.py b/backend/show_context.py deleted file mode 100644 index 8be63fc..0000000 --- a/backend/show_context.py +++ /dev/null @@ -1,11 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - lines = f.readlines() - -# Mostrar contexto alrededor de lineas con tenant_id -targets = [51, 92, 159, 200, 307, 384] -for t in targets: - print(f"\n=== Linea {t} ===") - start = max(0, t-5) - end = min(len(lines), t+5) - for i in range(start, end): - print(f"{i+1}: {lines[i].rstrip()}") diff --git a/check_lines.py b/check_lines.py deleted file mode 100644 index 378adfc..0000000 --- a/check_lines.py +++ /dev/null @@ -1,6 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - lines = f.readlines() - -for i, line in enumerate(lines): - if "tenant_id == current_user.tenant_id" in line: - print(f"Linea {i+1}: {line.rstrip()}") diff --git a/check_user.py b/check_user.py deleted file mode 100644 index 637289d..0000000 --- a/check_user.py +++ /dev/null @@ -1,14 +0,0 @@ -import asyncio -from app.core.database import AsyncSessionLocal -from app.models.user import User -from sqlalchemy import select -import uuid - -async def check(): - async with AsyncSessionLocal() as db: - result = await db.execute(select(User)) - users = result.scalars().all() - for u in users: - print(f"ID: {u.id} | Email: {u.email} | Tenant: {u.tenant_id} | Rol: {u.role}") - -asyncio.run(check()) diff --git a/debug_tenant.py b/debug_tenant.py new file mode 100644 index 0000000..801923a --- /dev/null +++ b/debug_tenant.py @@ -0,0 +1,19 @@ +import asyncio +from app.core.database import AsyncSessionLocal +from app.models.user import User +from app.models.tenant import Tenant +from sqlalchemy import select + +async def check(): + async with AsyncSessionLocal() as db: + result = await db.execute( + select(User, Tenant).join(Tenant).where(User.email == 'javier@ventas.com') + ) + user, tenant = result.one() + print(f"user.tenant_id: {user.tenant_id}") + print(f"tenant.id: {tenant.id}") + print(f"tenant.slug: {tenant.slug}") + print(f"user.role: {user.role}") + print(f"role.is_client: {user.role.is_client}") + +asyncio.run(check()) diff --git a/fix_login.py b/fix_login.py deleted file mode 100644 index ccfa675..0000000 --- a/fix_login.py +++ /dev/null @@ -1,67 +0,0 @@ -import re - -with open("/app/app/api/v1/endpoints/auth.py", "r") as f: - content = f.read() - -old = ''' # 1. Validar tenant - tenant_result = await db.execute( - select(Tenant).where(Tenant.slug == login_data.tenant_slug) - ) - tenant = tenant_result.scalar_one_or_none() - if tenant is None: - logger.warning( - "Login failed - tenant not found", - email=login_data.email, - tenant_slug=login_data.tenant_slug, - ) - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Tenant not found", - )''' - -new = ''' # 1. Validar tenant - por slug si viene, sino detectar por email - if login_data.tenant_slug: - tenant_result = await db.execute( - select(Tenant).where(Tenant.slug == login_data.tenant_slug) - ) - tenant = tenant_result.scalar_one_or_none() - if tenant is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Tenant not found", - ) - else: - tenant = None''' - -if old in content: - content = content.replace(old, new) - print("OK: bloque tenant reemplazado") -else: - print("ERROR: bloque no encontrado") - -# Tambien actualizar la query de usuario para usar tenant o no -old2 = ''' # 2. Buscar usuario en base de datos (aislado por tenant) - query = select(User).where( - User.email == login_data.email, - User.tenant_id == tenant.id, - )''' - -new2 = ''' # 2. Buscar usuario - filtrar por tenant si se detecto, sino buscar por email - if tenant: - query = select(User).where( - User.email == login_data.email, - User.tenant_id == tenant.id, - ) - else: - query = select(User).where(User.email == login_data.email)''' - -if old2 in content: - content = content.replace(old2, new2) - print("OK: bloque query reemplazado") -else: - print("ERROR: bloque query no encontrado") - -with open("/app/app/api/v1/endpoints/auth.py", "w") as f: - f.write(content) - -print("Listo") diff --git a/fix_ratelimit.py b/fix_ratelimit.py deleted file mode 100644 index 462ddbb..0000000 --- a/fix_ratelimit.py +++ /dev/null @@ -1,23 +0,0 @@ -with open("/app/app/api/v1/endpoints/auth.py", "r") as f: - content = f.read() - -old = ''' # Rate limiting (best-effort): by (tenant,email) to slow brute force. - ident_key = None - if settings.RATE_LIMIT_ENABLED and not settings.TESTING: - email_norm = login_data.email.strip().lower() - ident_key = cache_key("rl", "login", "id", str(tenant.id), email_norm)''' - -new = ''' # Rate limiting (best-effort): by (tenant,email) to slow brute force. - ident_key = None - if settings.RATE_LIMIT_ENABLED and not settings.TESTING and tenant: - email_norm = login_data.email.strip().lower() - ident_key = cache_key("rl", "login", "id", str(tenant.id), email_norm)''' - -if old in content: - content = content.replace(old, new) - print("OK: rate limiting fix aplicado") -else: - print("ERROR: bloque no encontrado") - -with open("/app/app/api/v1/endpoints/auth.py", "w") as f: - f.write(content) diff --git a/fix_response.py b/fix_response.py deleted file mode 100644 index b5ecf13..0000000 --- a/fix_response.py +++ /dev/null @@ -1,16 +0,0 @@ -with open("/app/app/api/v1/endpoints/auth.py", "r") as f: - lines = f.readlines() - -# Linea 286 (0-indexed 285): "tenant_id": str(user.tenant_id), -# Agregar tenant_slug despues de tenant_id -for i, line in enumerate(lines): - if '"tenant_id": str(user.tenant_id),' in line: - indent = " " - new_line = indent + '"tenant_slug": tenant.slug if tenant else str(user.tenant_id),\n' - lines.insert(i + 1, new_line) - print(f"OK: tenant_slug agregado en linea {i+2}") - break - -with open("/app/app/api/v1/endpoints/auth.py", "w") as f: - f.writelines(lines) -print("Listo") diff --git a/fix_syntax.py b/fix_syntax.py deleted file mode 100644 index 2d591c9..0000000 --- a/fix_syntax.py +++ /dev/null @@ -1,18 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py") as f: - lines = f.readlines() - -new_block = [ - " if current_user.role.value == 'ADMIN':\n", - " query = select(User).where(User.id == user_id)\n", - " else:\n", - " query = select(User).where(\n", - " User.id == user_id,\n", - " User.tenant_id == current_user.tenant_id\n", - " )\n", -] - -lines[150:161] = new_block - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.writelines(lines) -print("Listo") diff --git a/fix_users.py b/fix_users.py deleted file mode 100644 index c048025..0000000 --- a/fix_users.py +++ /dev/null @@ -1,28 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - content = f.read() - -old1 = " User.tenant_id == current_user.tenant_id # " + "\u2705" + " Seguridad multi-tenant" -new1 = """ from app.models.user import UserRole as _UserRole - if current_user.role == _UserRole.ADMIN: - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - )""" - -if old1 in content: - content = content.replace(old1, new1) - print("OK bloque 1") -else: - print("SKIP bloque 1 - buscando alternativa") - old1b = " User.tenant_id == current_user.tenant_id\n )\n result = await db.execute(query)\n if not user:" - new1b = " User.tenant_id == current_user.tenant_id\n )\n result = await db.execute(query)\n if not user:" - print("Lineas con tenant_id encontradas:") - for i, line in enumerate(content.split("\n")): - if "tenant_id == current_user.tenant_id" in line: - print(f" Linea {i}: {line}") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.write(content) -print("Listo") diff --git a/fix_users2.py b/fix_users2.py deleted file mode 100644 index 61ba1b9..0000000 --- a/fix_users2.py +++ /dev/null @@ -1,60 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - content = f.read() - -from app.models.user import UserRole as _UserRole - -# Reemplazar el patron comun de query con filtro de tenant -# por una version que permite a ADMIN ver todos los tenants - -old_get_user = """ query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - user = result.scalar_one_or_none() - if not user:""" - -new_get_user = """ if current_user.role.value == "ADMIN": - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - user = result.scalar_one_or_none() - if not user:""" - -old_update_user = """ query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - if not db_user:""" - -new_update_user = """ if current_user.role.value == "ADMIN": - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - if not db_user:""" - -count = 0 -for old, new in [(old_get_user, new_get_user), (old_update_user, new_update_user)]: - occurrences = content.count(old) - if occurrences > 0: - content = content.replace(old, new) - count += occurrences - print(f"OK: {occurrences} ocurrencia(s) reemplazada(s)") - else: - print(f"SKIP: bloque no encontrado") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.write(content) - -print(f"Total: {count} reemplazos aplicados") diff --git a/fix_users3.py b/fix_users3.py deleted file mode 100644 index 4f8e7fb..0000000 --- a/fix_users3.py +++ /dev/null @@ -1,36 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - content = f.read() - -old1 = """ # Buscar usuario - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - - if not db_user:""" - -new1 = """ # Buscar usuario - ADMIN global puede editar cualquier tenant - if current_user.role.value == "ADMIN": - query = select(User).where(User.id == user_id) - else: - query = select(User).where( - User.id == user_id, - User.tenant_id == current_user.tenant_id - ) - result = await db.execute(query) - db_user = result.scalar_one_or_none() - - if not db_user:""" - -count = content.count(old1) -if count > 0: - content = content.replace(old1, new1) - print(f"OK: {count} bloques reemplazados") -else: - print("ERROR: bloque no encontrado") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.write(content) -print("Listo") diff --git a/fix_users4.py b/fix_users4.py deleted file mode 100644 index 4ee96b7..0000000 --- a/fix_users4.py +++ /dev/null @@ -1,38 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - lines = f.readlines() - -admin_check = [ - " # Buscar usuario - ADMIN global puede editar cualquier tenant\n", - " if current_user.role.value == \"ADMIN\":\n", - " query = select(User).where(User.id == user_id)\n", - " else:\n", - " query = select(User).where(\n", - " User.id == user_id,\n", - " User.tenant_id == current_user.tenant_id\n", - " )\n", -] - -# Reemplazar bloques en lineas 198, 305, 382 (0-indexed: 197, 304, 381) -replaced = 0 -new_lines = lines[:] -i = 0 -while i < len(new_lines): - if (new_lines[i].strip() == "# Buscar usuario" and - i+1 < len(new_lines) and "select(User).where(" in new_lines[i+1] and - i+2 < len(new_lines) and "User.id == user_id," in new_lines[i+2] and - i+3 < len(new_lines) and "User.tenant_id == current_user.tenant_id" in new_lines[i+3]): - - indent = " " - new_block = admin_check[:] - # Remove old 4 lines of query block (comment + query 4 lines) - new_lines[i:i+5] = new_block - replaced += 1 - i += len(new_block) - else: - i += 1 - -print(f"Reemplazos realizados: {replaced}") - -with open("/app/app/api/v1/endpoints/users.py", "w") as f: - f.writelines(new_lines) -print("Listo") diff --git a/frontend-client/src/hooks.server.ts b/frontend-client/src/hooks.server.ts index 69cdc94..df4947b 100644 --- a/frontend-client/src/hooks.server.ts +++ b/frontend-client/src/hooks.server.ts @@ -1,6 +1,6 @@ import type { Handle } from '@sveltejs/kit'; export const handle: Handle = async ({ event, resolve }) => { - // No restaurar sesión en la página de login + // No restaurar sesión en la página de login if (event.url.pathname === '/login') { event.locals.user = null; return resolve(event); @@ -17,7 +17,7 @@ export const handle: Handle = async ({ event, resolve }) => { headers: { 'Authorization': `Bearer ${token}`, 'X-App': 'client', - 'X-Tenant-Slug': 'aduanasoft' + 'X-Tenant-Slug': '' } }); if (response.ok) { diff --git a/frontend-client/src/lib/utils/api.ts b/frontend-client/src/lib/utils/api.ts index 2dd9d21..9892269 100644 --- a/frontend-client/src/lib/utils/api.ts +++ b/frontend-client/src/lib/utils/api.ts @@ -25,14 +25,12 @@ async function request(endpoint: string, options: RequestOptions = {}): Promi if (authState.token) { headers.set('Authorization', `Bearer ${authState.token}`); } - if (authState.user?.tenant_id && !headers.has('X-Tenant-ID')) { - headers.set('X-Tenant-ID', authState.user.tenant_id); - } + if (!headers.has('Content-Type')) { headers.set('Content-Type', 'application/json'); } headers.set('X-App', 'client'); - const slug = get(authStore)?.user?.tenant_slug || get(authStore)?.user?.tenant_id || ''; + const slug = get(auth)?.user?.tenant_slug || get(auth)?.user?.tenant_id || ''; headers.set('X-Tenant-Slug', slug); const response = await fetch(url, { @@ -67,11 +65,9 @@ async function downloadFile(endpoint: string, filename: string): Promise { if (authState.token) { headers.set('Authorization', `Bearer ${authState.token}`); } - if (authState.user?.tenant_id) { - headers.set('X-Tenant-ID', authState.user.tenant_id); } headers.set('X-App', 'client'); - const slug = get(authStore)?.user?.tenant_slug || get(authStore)?.user?.tenant_id || ''; + const slug = get(auth)?.user?.tenant_slug || get(auth)?.user?.tenant_id || ''; headers.set('X-Tenant-Slug', slug); const response = await fetch(`${API_BASE}${endpoint}`, { diff --git a/frontend-client/src/routes/login/+page.svelte b/frontend-client/src/routes/login/+page.svelte index 77dc87e..27e0516 100644 --- a/frontend-client/src/routes/login/+page.svelte +++ b/frontend-client/src/routes/login/+page.svelte @@ -38,7 +38,7 @@ totp_code: totpCode || undefined }); - toast.success('¡Bienvenido! Has iniciado sesión correctamente'); + toast.success('¡Bienvenido! Has iniciado sesión correctamente'); goto('/'); } catch (error: any) { console.error('Login error:', error); @@ -46,9 +46,9 @@ // Check if 2FA is required if (error.message.includes('two-factor') || error.message.includes('2FA')) { showTwoFactor = true; - errorMessage = 'Introduce el código de tu aplicación de autenticación'; + errorMessage = 'Introduce el código de tu aplicación de autenticación'; } else { - errorMessage = error.message || 'Error al iniciar sesión'; + errorMessage = error.message || 'Error al iniciar sesión'; toast.error(errorMessage); } } finally { @@ -96,8 +96,8 @@ de Servicios de TI

- Portal de atención a clientes. Genere tickets de soporte técnico para nuestros sistemas y - reciba asistencia especializada para garantizar la continuidad de su operación. + Portal de atención a clientes. Genere tickets de soporte técnico para nuestros sistemas y + reciba asistencia especializada para garantizar la continuidad de su operación.

@@ -135,7 +135,7 @@
Correo Electrónico
@@ -160,7 +160,7 @@
Contraseña
@@ -176,7 +176,7 @@ bind:value={password} on:keydown={handleKeyDown} class="block w-full pl-10 pr-10 py-3 bg-[#fff9c4]/0 hover:bg-gray-50 focus:bg-white border text-gray-900 border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:border-transparent transition-all duration-200 sm:text-sm" - placeholder="••••••••" + placeholder="••••••••" required disabled={isLoading} /> @@ -187,7 +187,7 @@ bind:value={password} on:keydown={handleKeyDown} class="block w-full pl-10 pr-10 py-3 bg-[#fff9c4]/0 hover:bg-gray-50 focus:bg-white border text-gray-900 border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:border-transparent transition-all duration-200 sm:text-sm" - placeholder="••••••••" + placeholder="••••••••" required disabled={isLoading} /> @@ -221,7 +221,7 @@ class="text-sm font-medium text-blue-600 hover:text-blue-500 bg-transparent border-none p-0 cursor-pointer" on:click={() => goto('/forgot-password')} > - Olvidé mi clave + Olvidé mi clave
@@ -229,9 +229,9 @@
Código de Verificación (2FA) -

Ingrese el código de 6 dígitos

+

Ingrese el código de 6 dígitos

@@ -268,7 +268,7 @@
- © 2026 Aduanasoft. Acceso exclusivo autorizado. + © 2026 Aduanasoft. Acceso exclusivo autorizado.
diff --git a/show_context.py b/show_context.py deleted file mode 100644 index 8be63fc..0000000 --- a/show_context.py +++ /dev/null @@ -1,11 +0,0 @@ -with open("/app/app/api/v1/endpoints/users.py", "r") as f: - lines = f.readlines() - -# Mostrar contexto alrededor de lineas con tenant_id -targets = [51, 92, 159, 200, 307, 384] -for t in targets: - print(f"\n=== Linea {t} ===") - start = max(0, t-5) - end = min(len(lines), t+5) - for i in range(start, end): - print(f"{i+1}: {lines[i].rstrip()}")