Login resuelto
This commit is contained in:
49
backend/scripts/reset_passwords.py
Normal file
49
backend/scripts/reset_passwords.py
Normal 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())
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user