Login resuelto

This commit is contained in:
2026-02-27 09:16:08 -07:00
parent c146a6c3c3
commit 63925fe305
8 changed files with 109 additions and 11 deletions

View File

@@ -0,0 +1,49 @@
"""
Script para resetear contraseñas de todos los usuarios a valores conocidos.
Ejecutar con: python -m scripts.reset_passwords (desde /app en el contenedor)
"""
import asyncio
from sqlalchemy import select, update
from app.core.database import AsyncSessionLocal
from app.core.security import security
from app.models.user import User
# Mapa email -> nueva contraseña
PASSWORD_MAP = {
"admin@aduanasoft.com": "admin123",
"admin@test.com": "admin123",
"manager@aduanasoft.com": "manager123",
"agente@aduanasoft.com": "agente123",
"auditor1@test.com": "auditor123",
"admin-cliente@empresa-demo.com": "clienteadmin123",
"cliente@empresa-demo.com": "cliente123",
"test_user@aduanasoft.com": "test123",
}
async def reset_all_passwords():
async with AsyncSessionLocal() as db:
result = await db.execute(select(User))
users = result.scalars().all()
updated = 0
skipped = 0
for user in users:
if user.email in PASSWORD_MAP:
plain = PASSWORD_MAP[user.email]
user.password_hash = security.hash_password(plain)
user.email_verified = True
user.is_active = True
updated += 1
print(f"{user.email}{plain}")
else:
skipped += 1
print(f" ⚠️ {user.email} (sin contraseña definida, se omite)")
await db.commit()
print(f"\nResumen: {updated} actualizados, {skipped} omitidos")
print("\n📋 Credenciales listas:")
for email, pwd in PASSWORD_MAP.items():
print(f" {email} / {pwd}")
if __name__ == "__main__":
asyncio.run(reset_all_passwords())

View File

@@ -415,18 +415,19 @@ INSERT INTO tenants (name, slug, contact_email) VALUES
('Aduanasoft Demo', 'aduanasoft-demo', 'demo@aduanasoft.com'); ('Aduanasoft Demo', 'aduanasoft-demo', 'demo@aduanasoft.com');
-- Usuario admin por defecto (password: admin123) -- Usuario admin por defecto (password: admin123)
-- Hash generado con Argon2: $argon2id$v=19$m=65536,t=3,p=4$... -- Hash Argon2id generado con m=65536,t=3,p=4
INSERT INTO users (tenant_id, email, first_name, last_name, password_hash, role, is_active, email_verified) INSERT INTO users (tenant_id, email, first_name, last_name, password_hash, role, is_active, email_verified)
SELECT SELECT
id, id,
'admin@aduanasoft.com', 'admin@aduanasoft.com',
'Admin', 'Admin',
'Sistema', 'Sistema',
'$argon2id$v=19$m=65536,t=3,p=4$example_hash_here', '$argon2id$v=19$m=65536,t=3,p=4$wpjz/t+bM4bQmtM6B6A0pg$ELwnGUL4S1Y6tywp0LS6cre0bvWEoVuJ845spZ9Z9IQ',
'ADMIN', 'ADMIN',
true, true,
true true
FROM tenants WHERE slug = 'aduanasoft-demo'; FROM tenants WHERE slug = 'aduanasoft-demo'
ON CONFLICT (tenant_id, email) DO NOTHING;
-- Categorías por defecto -- Categorías por defecto
INSERT INTO ticket_categories (tenant_id, name, description, sla_response_hours, sla_resolution_hours) INSERT INTO ticket_categories (tenant_id, name, description, sla_response_hours, sla_resolution_hours)

View File

@@ -164,6 +164,8 @@ services:
- NODE_ENV=${ENVIRONMENT:-development} - NODE_ENV=${ENVIRONMENT:-development}
- PUBLIC_API_URL=http://backend:8000 - PUBLIC_API_URL=http://backend:8000
- PUBLIC_APP_NAME=ServiceManager Cliente - PUBLIC_APP_NAME=ServiceManager Cliente
- PORT=3000
- HMR_CLIENT_PORT=3000
volumes: volumes:
- ./frontend-client:/app - ./frontend-client:/app
- /app/node_modules - /app/node_modules
@@ -189,7 +191,8 @@ services:
- NODE_ENV=${ENVIRONMENT:-development} - NODE_ENV=${ENVIRONMENT:-development}
- PUBLIC_API_URL=http://backend:8000 - PUBLIC_API_URL=http://backend:8000
- PUBLIC_APP_NAME=ServiceManager Admin - PUBLIC_APP_NAME=ServiceManager Admin
- PORT=3000 # El contendor corre en 3000; docker mapea 3001:3000 al host - PORT=3000
- HMR_CLIENT_PORT=3001
volumes: volumes:
- ./frontend-internal:/app - ./frontend-internal:/app
- /app/node_modules - /app/node_modules

View File

@@ -4,13 +4,25 @@
import Toast from '$lib/components/Toast.svelte'; import Toast from '$lib/components/Toast.svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { auth } from '$lib/stores/auth.js'; import { auth } from '$lib/stores/auth.js';
import { goto } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { browser } from '$app/environment';
import '../app.css'; import '../app.css';
let mounted = false;
onMount(() => { onMount(() => {
auth.init(); auth.init();
mounted = true;
}); });
// Guard reactivo global: redirige a /login si no está autenticado en rutas protegidas
$: if (browser && mounted && !$auth.isAuthenticated &&
!$page.url.pathname.startsWith('/login') &&
!$page.url.pathname.startsWith('/register')) {
goto('/login');
}
$: showHeader = !$page.url.pathname.startsWith('/login') && !$page.url.pathname.startsWith('/register'); $: showHeader = !$page.url.pathname.startsWith('/login') && !$page.url.pathname.startsWith('/register');
</script> </script>

View File

@@ -10,6 +10,16 @@ export default defineConfig({
usePolling: true, usePolling: true,
interval: 500 interval: 500
}, },
// HMR: el browser llega al contenedor en el mismo puerto 3000
hmr: {
host: 'localhost',
clientPort: parseInt(process.env.HMR_CLIENT_PORT || '3000')
},
// Permitir que Vite sirva archivos del filesystem del contenedor
fs: {
allow: ['/app', '.'],
strict: false
},
proxy: { proxy: {
'/api': { '/api': {
target: process.env.PUBLIC_API_URL || 'http://localhost:8000', target: process.env.PUBLIC_API_URL || 'http://localhost:8000',

View File

@@ -5,14 +5,24 @@
import { toast } from '$lib/stores/toast.js'; import { toast } from '$lib/stores/toast.js';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { auth } from '$lib/stores/auth.js'; import { auth } from '$lib/stores/auth.js';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { browser } from '$app/environment';
import '../app.css'; import '../app.css';
let sidebarOpen = false; let sidebarOpen = false;
let mounted = false;
onMount(() => { onMount(() => {
auth.init(); auth.init();
mounted = true;
}); });
// Guard reactivo global: redirige a /login si no está autenticado
$: if (browser && mounted && !$auth.isAuthenticated && $page.url.pathname !== '/login') {
goto('/login');
}
function toggleSidebar() { function toggleSidebar() {
sidebarOpen = !sidebarOpen; sidebarOpen = !sidebarOpen;
} }

View File

@@ -4,13 +4,23 @@ import { defineConfig } from 'vite';
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()], plugins: [sveltekit()],
server: { server: {
// Puerto: 3001 por defecto en local; Docker lo sobreescribe con PORT=3000 // Puerto: dentro del contenedor siempre 3000; Docker mapea 3001:3000 al host
port: parseInt(process.env.PORT || '3001'), port: parseInt(process.env.PORT || '3001'),
host: '0.0.0.0', host: '0.0.0.0',
watch: { watch: {
usePolling: true, usePolling: true,
interval: 500 interval: 500
}, },
// HMR: el browser llega al contenedor a través del puerto 3001 del host
hmr: {
host: 'localhost',
clientPort: parseInt(process.env.HMR_CLIENT_PORT || '3001')
},
// Permitir que Vite sirva archivos del filesystem del contenedor
fs: {
allow: ['/app', '.'],
strict: false
},
proxy: { proxy: {
'/api': { '/api': {
target: process.env.PUBLIC_API_URL || 'http://localhost:8000', target: process.env.PUBLIC_API_URL || 'http://localhost:8000',

View File

@@ -216,15 +216,18 @@ async def main():
if user_data["email"] in existing_emails: if user_data["email"] in existing_emails:
print(f" ⏭ Ya existe: {user_data['email']}") print(f" ⏭ Ya existe: {user_data['email']}")
continue continue
pwd = user_data.pop("password") # Usar copia para no mutar el dict original (permite re-ejecutar el script)
ud = user_data.copy()
pwd = ud.pop("password")
hashed_pwd = security.hash_password(pwd) hashed_pwd = security.hash_password(pwd)
user = User( user = User(
tenant_id=tenant_id, tenant_id=tenant_id,
password_hash=hashed_pwd, password_hash=hashed_pwd,
**user_data, email_verified=True, # Marcar como verificado para permitir login
**ud,
) )
session.add(user) session.add(user)
print(f"{user_data['email']} [{user_data['role'].value}] pwd={pwd}") print(f"{ud['email']} [{ud['role'].value}] pwd={pwd}")
created_users += 1 created_users += 1
await session.commit() await session.commit()