Actualizar server.js
This commit is contained in:
126
server.js
126
server.js
@@ -29,14 +29,14 @@ const pool = new Pool({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// 🧠 AUTO-ACTUALIZACIÓN DB (REPARADOR DEEP)
|
// 🧠 AUTO-ACTUALIZACIÓN DB
|
||||||
// ==========================================
|
// ==========================================
|
||||||
async function autoUpdateDB() {
|
async function autoUpdateDB() {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
console.log("🔄 Verificando salud de la base de datos...");
|
console.log("🔄 Verificando salud de la base de datos...");
|
||||||
|
|
||||||
// 1. DEFINICIÓN BASE (Para instalaciones nuevas)
|
// 1. CREAR TABLAS (Si no existen)
|
||||||
await client.query(`
|
await client.query(`
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
@@ -137,89 +137,43 @@ async function autoUpdateDB() {
|
|||||||
);
|
);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// 2. PARCHE DE REPARACIÓN MANUAL (AQUÍ ESTÁ LA SOLUCIÓN)
|
// 2. PARCHE DE REPARACIÓN
|
||||||
// Este bloque fuerza la creación de columnas si no existen
|
|
||||||
await client.query(`
|
await client.query(`
|
||||||
DO $$
|
DO $$
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Client ID
|
-- Client ID
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_id') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_id') THEN ALTER TABLE services ADD COLUMN client_id INT REFERENCES clients(id) ON DELETE SET NULL; END IF;
|
||||||
ALTER TABLE services ADD COLUMN client_id INT REFERENCES clients(id) ON DELETE SET NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Status ID
|
-- Status ID
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='status_id') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='status_id') THEN ALTER TABLE services ADD COLUMN status_id INT REFERENCES service_statuses(id) ON DELETE SET NULL; END IF;
|
||||||
ALTER TABLE services ADD COLUMN status_id INT REFERENCES service_statuses(id) ON DELETE SET NULL;
|
-- Guild & Assigned
|
||||||
END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='guild_id') THEN ALTER TABLE services ADD COLUMN guild_id INT REFERENCES guilds(id) ON DELETE SET NULL; END IF;
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='assigned_to') THEN ALTER TABLE services ADD COLUMN assigned_to INT REFERENCES users(id) ON DELETE SET NULL; END IF;
|
||||||
-- Guild ID & Assigned To
|
-- Contact
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='guild_id') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_phone') THEN ALTER TABLE services ADD COLUMN contact_phone TEXT; END IF;
|
||||||
ALTER TABLE services ADD COLUMN guild_id INT REFERENCES guilds(id) ON DELETE SET NULL;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_name') THEN ALTER TABLE services ADD COLUMN contact_name TEXT; END IF;
|
||||||
END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='address') THEN ALTER TABLE services ADD COLUMN address TEXT; END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='assigned_to') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='email') THEN ALTER TABLE services ADD COLUMN email TEXT; END IF;
|
||||||
ALTER TABLE services ADD COLUMN assigned_to INT REFERENCES users(id) ON DELETE SET NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Contact Info
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_phone') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN contact_phone TEXT;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_name') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN contact_name TEXT;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='address') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN address TEXT;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='email') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN email TEXT;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Details
|
-- Details
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='title') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='title') THEN ALTER TABLE services ADD COLUMN title TEXT; END IF;
|
||||||
ALTER TABLE services ADD COLUMN title TEXT;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='description') THEN ALTER TABLE services ADD COLUMN description TEXT; END IF;
|
||||||
END IF;
|
-- Schedule
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='description') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_date') THEN ALTER TABLE services ADD COLUMN scheduled_date DATE DEFAULT CURRENT_DATE; END IF;
|
||||||
ALTER TABLE services ADD COLUMN description TEXT;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_time') THEN ALTER TABLE services ADD COLUMN scheduled_time TIME DEFAULT CURRENT_TIME; END IF;
|
||||||
END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='duration_minutes') THEN ALTER TABLE services ADD COLUMN duration_minutes INT DEFAULT 30; END IF;
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_urgent') THEN ALTER TABLE services ADD COLUMN is_urgent BOOLEAN DEFAULT FALSE; END IF;
|
||||||
-- Scheduling
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_date') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN scheduled_date DATE DEFAULT CURRENT_DATE;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_time') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN scheduled_time TIME DEFAULT CURRENT_TIME;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='duration_minutes') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN duration_minutes INT DEFAULT 30;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_urgent') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN is_urgent BOOLEAN DEFAULT FALSE;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Company & Notes
|
-- Company & Notes
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_id') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_id') THEN ALTER TABLE services ADD COLUMN company_id INT REFERENCES companies(id) ON DELETE SET NULL; END IF;
|
||||||
ALTER TABLE services ADD COLUMN company_id INT REFERENCES companies(id) ON DELETE SET NULL;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_company') THEN ALTER TABLE services ADD COLUMN is_company BOOLEAN DEFAULT FALSE; END IF;
|
||||||
END IF;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_ref') THEN ALTER TABLE services ADD COLUMN company_ref TEXT; END IF;
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_company') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='internal_notes') THEN ALTER TABLE services ADD COLUMN internal_notes TEXT; END IF;
|
||||||
ALTER TABLE services ADD COLUMN is_company BOOLEAN DEFAULT FALSE;
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_notes') THEN ALTER TABLE services ADD COLUMN client_notes TEXT; END IF;
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_ref') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN company_ref TEXT;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='internal_notes') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN internal_notes TEXT;
|
|
||||||
END IF;
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_notes') THEN
|
|
||||||
ALTER TABLE services ADD COLUMN client_notes TEXT;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Clean up old constraints
|
|
||||||
BEGIN ALTER TABLE users DROP CONSTRAINT IF EXISTS users_phone_key; EXCEPTION WHEN OTHERS THEN NULL; END;
|
BEGIN ALTER TABLE users DROP CONSTRAINT IF EXISTS users_phone_key; EXCEPTION WHEN OTHERS THEN NULL; END;
|
||||||
BEGIN ALTER TABLE users DROP CONSTRAINT IF EXISTS users_email_key; EXCEPTION WHEN OTHERS THEN NULL; END;
|
BEGIN ALTER TABLE users DROP CONSTRAINT IF EXISTS users_email_key; EXCEPTION WHEN OTHERS THEN NULL; END;
|
||||||
END $$;
|
END $$;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
console.log("✅ DB Sincronizada y Reparada Exitosamente.");
|
console.log("✅ DB Sincronizada y Reparada.");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("❌ Error DB:", e);
|
console.error("❌ Error DB:", e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -301,7 +255,6 @@ app.get("/clients/search", authMiddleware, async (req, res) => {
|
|||||||
app.get("/companies", authMiddleware, async (req, res) => { try { const q = await pool.query("SELECT * FROM companies WHERE owner_id=$1 ORDER BY name ASC", [req.user.accountId]); res.json({ ok: true, companies: q.rows }); } catch (e) { res.status(500).json({ ok: false }); } });
|
app.get("/companies", authMiddleware, async (req, res) => { try { const q = await pool.query("SELECT * FROM companies WHERE owner_id=$1 ORDER BY name ASC", [req.user.accountId]); res.json({ ok: true, companies: q.rows }); } catch (e) { res.status(500).json({ ok: false }); } });
|
||||||
app.post("/companies", authMiddleware, async (req, res) => { try { const { name } = req.body; await pool.query("INSERT INTO companies (name, owner_id) VALUES ($1, $2)", [name, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } });
|
app.post("/companies", authMiddleware, async (req, res) => { try { const { name } = req.body; await pool.query("INSERT INTO companies (name, owner_id) VALUES ($1, $2)", [name, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } });
|
||||||
|
|
||||||
// OBTENER OPERARIOS POR GREMIO
|
|
||||||
app.get("/operators", authMiddleware, async (req, res) => {
|
app.get("/operators", authMiddleware, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { guild_id } = req.query;
|
const { guild_id } = req.query;
|
||||||
@@ -353,11 +306,19 @@ app.put("/services/:id/status", authMiddleware, async (req, res) => {
|
|||||||
} catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); }
|
} catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// CREAR SERVICIO (SANITIZADO)
|
||||||
app.post("/services", authMiddleware, async (req, res) => {
|
app.post("/services", authMiddleware, async (req, res) => {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
const { phone, name, address, email, description, scheduled_date, scheduled_time, duration, is_urgent, is_company, company_id, company_ref, internal_notes, client_notes, status_id, guild_id, assigned_to } = req.body;
|
const { phone, name, address, email, description, scheduled_date, scheduled_time, duration, is_urgent, is_company, company_id, company_ref, internal_notes, client_notes, status_id, guild_id, assigned_to } = req.body;
|
||||||
const p = normalizePhone(phone);
|
const p = normalizePhone(phone);
|
||||||
|
|
||||||
|
// SANITIZAR ENTEROS (Evitar error invalid input syntax for type integer: "")
|
||||||
|
const safeDuration = (duration === "" || duration === null) ? 30 : duration;
|
||||||
|
const safeCompanyId = (company_id === "" || company_id === null) ? null : company_id;
|
||||||
|
const safeGuildId = (guild_id === "" || guild_id === null) ? null : guild_id;
|
||||||
|
const safeAssignedTo = (assigned_to === "" || assigned_to === null) ? null : assigned_to;
|
||||||
|
|
||||||
await client.query('BEGIN');
|
await client.query('BEGIN');
|
||||||
|
|
||||||
let finalStatus = status_id;
|
let finalStatus = status_id;
|
||||||
@@ -387,9 +348,9 @@ app.post("/services", authMiddleware, async (req, res) => {
|
|||||||
RETURNING id
|
RETURNING id
|
||||||
`, [
|
`, [
|
||||||
req.user.accountId, clientId, finalStatus, p, name, address, email,
|
req.user.accountId, clientId, finalStatus, p, name, address, email,
|
||||||
description, scheduled_date || 'NOW()', scheduled_time || 'NOW()', duration || 30, is_urgent || false,
|
description, scheduled_date || 'NOW()', scheduled_time || 'NOW()', safeDuration, is_urgent || false,
|
||||||
is_company || false, company_id || null, company_ref, internal_notes, client_notes, name + " - Svc",
|
is_company || false, safeCompanyId, company_ref, internal_notes, client_notes, name + " - Svc",
|
||||||
guild_id || null, assigned_to || null
|
safeGuildId, safeAssignedTo
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await client.query("INSERT INTO service_logs (service_id, user_id, new_status_id, comment) VALUES ($1, $2, $3, 'Servicio Creado')", [insert.rows[0].id, req.user.sub, finalStatus]);
|
await client.query("INSERT INTO service_logs (service_id, user_id, new_status_id, comment) VALUES ($1, $2, $3, 'Servicio Creado')", [insert.rows[0].id, req.user.sub, finalStatus]);
|
||||||
@@ -399,6 +360,7 @@ 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(); }
|
} catch (e) { await client.query('ROLLBACK'); console.error(e); res.status(500).json({ ok: false, error: e.message }); } finally { client.release(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// EDITAR SERVICIO (SANITIZADO)
|
||||||
app.put("/services/:id", authMiddleware, async (req, res) => {
|
app.put("/services/:id", authMiddleware, async (req, res) => {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
@@ -410,6 +372,12 @@ app.put("/services/:id", authMiddleware, async (req, res) => {
|
|||||||
guild_id, assigned_to
|
guild_id, assigned_to
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
|
// SANITIZAR ENTEROS
|
||||||
|
const safeDuration = (duration === "" || duration === null) ? 30 : duration;
|
||||||
|
const safeCompanyId = (company_id === "" || company_id === null) ? null : company_id;
|
||||||
|
const safeGuildId = (guild_id === "" || guild_id === null) ? null : guild_id;
|
||||||
|
const safeAssignedTo = (assigned_to === "" || assigned_to === null) ? null : assigned_to;
|
||||||
|
|
||||||
await client.query('BEGIN');
|
await client.query('BEGIN');
|
||||||
await client.query(`
|
await client.query(`
|
||||||
UPDATE services SET
|
UPDATE services SET
|
||||||
@@ -421,10 +389,10 @@ app.put("/services/:id", authMiddleware, async (req, res) => {
|
|||||||
WHERE id=$16 AND owner_id=$17
|
WHERE id=$16 AND owner_id=$17
|
||||||
`, [
|
`, [
|
||||||
name, address, email, description,
|
name, address, email, description,
|
||||||
scheduled_date, scheduled_time, duration, is_urgent,
|
scheduled_date, scheduled_time, safeDuration, is_urgent,
|
||||||
is_company, company_id, company_ref,
|
is_company, safeCompanyId, company_ref,
|
||||||
internal_notes, client_notes,
|
internal_notes, client_notes,
|
||||||
guild_id, assigned_to,
|
safeGuildId, safeAssignedTo,
|
||||||
req.params.id, req.user.accountId
|
req.params.id, req.user.accountId
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user