Files
administracionHospital/server/index.js
T
snlavaise 76e01bfd79 feat: agregar sistema de autenticación con usuarios y roles
- Agregar Login con autenticación por DNI y contraseña
- Crear tabla de usuarios con roles (admin, médico, enfermero)
- Implementar gestión de usuarios (CRUD) para administradores
- Agregar control de permisos basado en roles en el menú
- Persistir estado de sesión en backend
- Inicializar usuario admin por defecto (DNI: 12345678, pass: admin123)
- Corregir inicialización de arrays en el store para evitar errores al cargar estado
2026-04-23 01:09:29 -03:00

236 lines
6.9 KiB
JavaScript

import express from 'express';
import cors from 'cors';
import { getValue, setValue, getUsuarioByDni, getUsuarioById, getAllUsuarios, createUsuario, updateUsuario, deleteUsuario, verifyPassword, hashPassword } from './db.js';
const app = express();
app.use(cors());
app.use(express.json({ limit: '5mb' }));
const PORT = process.env.PORT || 4001;
const STORAGE_KEY = 'hospital-data-v1';
app.get('/api/state', async (req, res) => {
try {
const v = await getValue(STORAGE_KEY);
if (!v) return res.json(null);
res.json(JSON.parse(v));
} catch (err) {
console.error(err);
res.status(500).json({ error: 'failed to read state' });
}
});
app.put('/api/state', async (req, res) => {
try {
const body = req.body;
await setValue(STORAGE_KEY, JSON.stringify(body));
res.json({ ok: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'failed to save state' });
}
});
app.listen(PORT, () => {
console.log(`API server listening on http://localhost:${PORT}`);
});
// Crear usuario admin inicial si no existe
async function initAdminUser() {
try {
const adminExists = await getUsuarioByDni('12345678');
if (!adminExists) {
const passwordHash = await hashPassword('admin123');
const adminUser = {
id: generateUUID(),
apellido: 'Admin',
nombre: 'Sistema',
dni: '12345678',
fechaNacimiento: '1970-01-01',
email: 'admin@hospital.gob.ar',
rol: 'admin',
matriculaProfesional: null,
passwordHash,
areaId: null,
fechaCreacion: new Date().toISOString().split('T')[0]
};
await createUsuario(adminUser);
console.log('Usuario admin creado: DNI 12345678, Password admin123');
}
} catch (err) {
console.error('Error creating admin user:', err);
}
}
initAdminUser();
// === AUTENTICACIÓN ===
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
app.post('/api/auth/login', async (req, res) => {
try {
const { dni, password } = req.body;
if (!dni || !password) {
return res.status(400).json({ error: 'DNI y contraseña requeridos' });
}
const usuario = await getUsuarioByDni(dni);
if (!usuario) {
return res.status(401).json({ error: 'Usuario no encontrado' });
}
const validPassword = await verifyPassword(dni, password);
if (!validPassword) {
return res.status(401).json({ error: 'Contraseña incorrecta' });
}
const { passwordHash, ...userWithoutPassword } = usuario;
res.json(userWithoutPassword);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error en autenticación' });
}
});
app.post('/api/auth/change-password', async (req, res) => {
try {
const { dni, oldPassword, newPassword } = req.body;
if (!dni || !oldPassword || !newPassword) {
return res.status(400).json({ error: 'Todos los campos son requeridos' });
}
const validPassword = await verifyPassword(dni, oldPassword);
if (!validPassword) {
return res.status(401).json({ error: 'Contraseña actual incorrecta' });
}
const newHash = await hashPassword(newPassword);
await updateUsuarioByDni(dni, { passwordHash: newHash });
res.json({ ok: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error al cambiar contraseña' });
}
});
app.put('/api/auth/update-email', async (req, res) => {
try {
const { dni, newEmail } = req.body;
if (!dni || !newEmail) {
return res.status(400).json({ error: 'DNI y email son requeridos' });
}
await updateUsuarioByDni(dni, { email: newEmail });
res.json({ ok: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error al actualizar email' });
}
});
// === GESTIÓN DE USUARIOS (ADMIN) ===
app.get('/api/usuarios', async (req, res) => {
try {
const usuarios = await getAllUsuarios();
const usuariosSinPassword = usuarios.map(({ passwordHash, ...u }) => u);
res.json(usuariosSinPassword);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error al obtener usuarios' });
}
});
app.post('/api/usuarios', async (req, res) => {
try {
const { apellido, nombre, dni, fechaNacimiento, email, rol, matriculaProfesional, password, areaId } = req.body;
if (!apellido || !nombre || !dni || !fechaNacimiento || !email || !rol || !password) {
return res.status(400).json({ error: 'Todos los campos obligatorios deben estar presentes' });
}
const existente = await getUsuarioByDni(dni);
if (existente) {
return res.status(400).json({ error: 'Ya existe un usuario con ese DNI' });
}
const passwordHash = await hashPassword(password);
const usuario = {
id: generateUUID(),
apellido,
nombre,
dni,
fechaNacimiento,
email,
rol,
matriculaProfesional: matriculaProfesional || null,
passwordHash,
areaId: areaId || null,
fechaCreacion: new Date().toISOString().split('T')[0]
};
await createUsuario(usuario);
res.json({ ...usuario, passwordHash: undefined });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error al crear usuario' });
}
});
app.put('/api/usuarios/:id', async (req, res) => {
try {
const { id } = req.params;
const { apellido, nombre, fechaNacimiento, email, rol, matriculaProfesional, areaId, password } = req.body;
const usuario = await getUsuarioById(id);
if (!usuario) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
const datos = {};
if (apellido !== undefined) datos.apellido = apellido;
if (nombre !== undefined) datos.nombre = nombre;
if (fechaNacimiento !== undefined) datos.fechaNacimiento = fechaNacimiento;
if (email !== undefined) datos.email = email;
if (rol !== undefined) datos.rol = rol;
if (matriculaProfesional !== undefined) datos.matriculaProfesional = matriculaProfesional;
if (areaId !== undefined) datos.areaId = areaId;
if (password) {
datos.passwordHash = await hashPassword(password);
}
await updateUsuario(id, datos);
res.json({ ok: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error al actualizar usuario' });
}
});
app.delete('/api/usuarios/:id', async (req, res) => {
try {
const { id } = req.params;
await deleteUsuario(id);
res.json({ ok: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Error al eliminar usuario' });
}
});
// Helper para actualizar por DNI
async function updateUsuarioByDni(dni, datos) {
const { getUsuarioByDni, updateUsuario } = await import('./db.js');
const usuario = await getUsuarioByDni(dni);
if (usuario) {
await updateUsuario(usuario.id, datos);
}
}