- 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
236 lines
6.9 KiB
JavaScript
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);
|
|
}
|
|
}
|