Actualizar server.js

This commit is contained in:
2026-02-08 11:42:30 +00:00
parent fce443c93e
commit 8c23d54452

View File

@@ -40,8 +40,8 @@ async function autoUpdateDB() {
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
full_name TEXT NOT NULL, full_name TEXT NOT NULL,
phone TEXT NOT NULL, -- ELIMINADO 'UNIQUE' EN DEFINICIÓN (Se gestiona abajo) phone TEXT NOT NULL,
email TEXT UNIQUE NOT NULL, email TEXT NOT NULL, -- MODIFICADO: YA NO ES UNIQUE GLOBALMENTE
dni TEXT, dni TEXT,
address TEXT, address TEXT,
password_hash TEXT NOT NULL, password_hash TEXT NOT NULL,
@@ -80,16 +80,10 @@ async function autoUpdateDB() {
); );
`); `);
// --- CORRECCIÓN MULTITENANT --- // Parches y correcciones de restricciones (Multitenancy)
// Eliminamos la restricción global de teléfono único si existe para permitir try { await client.query(`ALTER TABLE users DROP CONSTRAINT IF EXISTS users_phone_key`); } catch (e) {}
// que el mismo teléfono esté en varias empresas. try { await client.query(`ALTER TABLE users DROP CONSTRAINT IF EXISTS users_email_key`); } catch (e) {} // NUEVO: Elimina restricción global de email
try {
await client.query(`ALTER TABLE users DROP CONSTRAINT IF EXISTS users_phone_key`);
} catch (e) {
// Ignoramos si no existe o hay error menor
}
// Parches
await client.query(` await client.query(`
DO $$ BEGIN DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='role') THEN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='role') THEN
@@ -165,18 +159,16 @@ app.post("/auth/register", async (req, res) => {
const passwordHash = await bcrypt.hash(password, 10); const passwordHash = await bcrypt.hash(password, 10);
await client.query('BEGIN'); await client.query('BEGIN');
// Verificamos Email (Que debe ser único globalmente para login) const checkUser = await client.query("SELECT * FROM users WHERE email = $1 OR phone = $2", [email, p]);
const checkUser = await client.query("SELECT * FROM users WHERE email = $1", [email]);
let userId; let userId;
if (checkUser.rowCount > 0) { if (checkUser.rowCount > 0) {
const existing = checkUser.rows[0]; const existing = checkUser.rows[0];
// Si existe y ya está verificado, error.
if (existing.is_verified) { if (existing.is_verified) {
await client.query('ROLLBACK'); await client.query('ROLLBACK');
return res.status(409).json({ ok: false, error: "El email ya está registrado." }); return res.status(409).json({ ok: false, error: "Usuario ya registrado." });
} }
await client.query("UPDATE users SET full_name=$1, address=$2, dni=$3, password_hash=$4, phone=$5 WHERE id=$6", [fullName, address, dni, passwordHash, p, existing.id]); await client.query("UPDATE users SET full_name=$1, address=$2, dni=$3, password_hash=$4 WHERE id=$5", [fullName, address, dni, passwordHash, existing.id]);
userId = existing.id; userId = existing.id;
} else { } else {
const insert = await client.query( const insert = await client.query(
@@ -220,12 +212,23 @@ app.post("/auth/verify", async (req, res) => {
app.post("/auth/login", async (req, res) => { app.post("/auth/login", async (req, res) => {
try { try {
const { email, password } = req.body; const { email, password } = req.body;
// Buscamos TODOS los usuarios con ese email (puede haber varios en distintas empresas)
const q = await pool.query("SELECT * FROM users WHERE email=$1", [email]); const q = await pool.query("SELECT * FROM users WHERE email=$1", [email]);
if (q.rowCount === 0) return res.status(401).json({ ok: false, error: "Datos incorrectos" }); if (q.rowCount === 0) return res.status(401).json({ ok: false, error: "Datos incorrectos" });
const u = q.rows[0];
if (!(await bcrypt.compare(password, u.password_hash))) return res.status(401).json({ ok: false, error: "Datos incorrectos" }); // Probamos la contraseña con cada usuario encontrado
res.json({ ok: true, token: signToken(u) }); let user = null;
} catch(e) { res.status(500).json({ ok: false, error: "Error login" }); } for (const u of q.rows) {
if (await bcrypt.compare(password, u.password_hash)) {
user = u;
break; // ¡Encontrado el correcto!
}
}
if (!user) return res.status(401).json({ ok: false, error: "Datos incorrectos" });
res.json({ ok: true, token: signToken(user) });
} catch(e) { console.error(e); res.status(500).json({ ok: false, error: "Error login" }); }
}); });
// RECUPERAR CONTRASEÑA // RECUPERAR CONTRASEÑA
@@ -342,7 +345,6 @@ app.get("/admin/users", authMiddleware, async (req, res) => {
} catch (e) { res.status(500).json({ ok: false, error: "Error listar users" }); } } catch (e) { res.status(500).json({ ok: false, error: "Error listar users" }); }
}); });
// CREAR USUARIO (CORREGIDO MULTITENANT)
app.post("/admin/users", authMiddleware, async (req, res) => { app.post("/admin/users", authMiddleware, async (req, res) => {
const client = await pool.connect(); const client = await pool.connect();
try { try {
@@ -373,10 +375,8 @@ app.post("/admin/users", authMiddleware, async (req, res) => {
res.json({ ok: true, msg: "Usuario creado" }); res.json({ ok: true, msg: "Usuario creado" });
} catch (e) { } catch (e) {
await client.query('ROLLBACK'); await client.query('ROLLBACK');
// Mantenemos el check global de email único, pero permitimos teléfonos duplicados en distintas empresas // El DB ya no dará error 23505 por email/phone global porque eliminamos la restricción
if (e.code === '23505' && e.constraint.includes('email')) { console.error(e);
return res.status(400).json({ ok: false, error: "❌ El Email ya está usado en el sistema." });
}
res.status(500).json({ ok: false, error: "Error creando usuario" }); res.status(500).json({ ok: false, error: "Error creando usuario" });
} finally { client.release(); } } finally { client.release(); }
}); });