From e9d8335bf3c37b9dc3009aefb2d3951c7bd22307 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sun, 8 Feb 2026 13:35:11 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 0b4f9bb..29f56b9 100644 --- a/server.js +++ b/server.js @@ -322,7 +322,7 @@ app.put("/services/:id/status", authMiddleware, async (req, res) => { } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } }); -// CREAR SERVICIO +// CREAR SERVICIO (MODIFICADO: Acepta status manual) app.post("/services", authMiddleware, async (req, res) => { const client = await pool.connect(); try { @@ -383,5 +383,37 @@ app.post("/services", authMiddleware, async (req, res) => { } catch (e) { await client.query('ROLLBACK'); console.error(e); res.status(500).json({ ok: false, error: e.message }); } finally { client.release(); } }); +// ADMIN USERS (MULTITENANT OK) +app.post("/admin/users", authMiddleware, async (req, res) => { + const client = await pool.connect(); + try { + const { fullName, email, password, role, guilds, phone } = req.body; + if (!email || !password || !fullName || !phone) return res.status(400).json({ ok: false, error: "Faltan datos" }); + const p = normalizePhone(phone); + const passwordHash = await bcrypt.hash(password, 10); + + const checkDup = await client.query("SELECT id FROM users WHERE (phone=$1 OR email=$2) AND owner_id=$3", [p, email, req.user.accountId]); + if (checkDup.rowCount > 0) return res.status(400).json({ ok: false, error: "Empleado ya existe en tu empresa" }); + + await client.query('BEGIN'); + const insert = await client.query("INSERT INTO users (full_name, email, password_hash, role, phone, is_verified, owner_id) VALUES ($1, $2, $3, $4, $5, TRUE, $6) RETURNING id", [fullName, email, passwordHash, role || 'operario', p, req.user.accountId]); + const userId = insert.rows[0].id; + if (guilds && Array.isArray(guilds)) { for (const gid of guilds) await client.query("INSERT INTO user_guilds (user_id, guild_id) VALUES ($1, $2)", [userId, gid]); } + await client.query('COMMIT'); + res.json({ ok: true }); + } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } +}); + +app.get("/admin/users", authMiddleware, async (req, res) => { + try { + const q = await pool.query(`SELECT u.id, u.full_name, u.email, u.phone, u.role, COALESCE(json_agg(g.id) FILTER (WHERE g.id IS NOT NULL), '[]') as guilds FROM users u LEFT JOIN user_guilds ug ON u.id=ug.user_id LEFT JOIN guilds g ON ug.guild_id=g.id WHERE u.owner_id=$1 GROUP BY u.id ORDER BY u.id DESC`, [req.user.accountId]); + res.json({ ok: true, users: q.rows }); + } catch (e) { res.status(500).json({ ok: false }); } +}); + +app.delete("/admin/users/:id", authMiddleware, async (req, res) => { + try { await pool.query("DELETE FROM users WHERE id=$1 AND owner_id=$2", [req.params.id, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } +}); + const port = process.env.PORT || 3000; autoUpdateDB().then(() => { app.listen(port, "0.0.0.0", () => console.log(`🚀 Server OK en puerto ${port}`)); }); \ No newline at end of file