Actualizar server.js
This commit is contained in:
56
server.js
56
server.js
@@ -254,14 +254,9 @@ async function autoUpdateDB() {
|
|||||||
|
|
||||||
-- AÑADIDO: Columna para guardar la configuración de WhatsApp
|
-- AÑADIDO: Columna para guardar la configuración de WhatsApp
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='wa_settings') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='wa_settings') THEN
|
||||||
|
|
||||||
-- AÑADIDO: Columna para guardar la configuración de WhatsApp
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='wa_settings') THEN
|
|
||||||
ALTER TABLE users ADD COLUMN wa_settings JSONB DEFAULT '{}';
|
ALTER TABLE users ADD COLUMN wa_settings JSONB DEFAULT '{}';
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- AÑADIDO: Configuración del Portal del Cliente
|
-- AÑADIDO: Configuración del Portal del Cliente
|
||||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='company_logo') THEN
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='company_logo') THEN
|
||||||
ALTER TABLE users ADD COLUMN company_logo TEXT;
|
ALTER TABLE users ADD COLUMN company_logo TEXT;
|
||||||
@@ -290,8 +285,6 @@ async function autoUpdateDB() {
|
|||||||
ALTER TABLE service_statuses ADD COLUMN is_system BOOLEAN DEFAULT FALSE;
|
ALTER TABLE service_statuses ADD COLUMN is_system BOOLEAN DEFAULT FALSE;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
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;
|
||||||
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;
|
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;
|
||||||
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_phone') THEN ALTER TABLE services ADD COLUMN contact_phone TEXT; END IF;
|
||||||
@@ -894,8 +887,48 @@ app.delete("/agenda/blocks/:id", authMiddleware, async (req, res) => {
|
|||||||
|
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// ⚙️ MOTOR AUTOMÁTICO DE WHATSAPP
|
// ⚙️ MOTOR AUTOMÁTICO DE WHATSAPP Y APP SETTINGS (AÑADIDO PARA SOLUCIONAR ERROR 404)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
app.get("/whatsapp/status", authMiddleware, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const instanceName = `cliente_${req.user.accountId}`;
|
||||||
|
if (!EVOLUTION_BASE_URL || !EVOLUTION_API_KEY) return res.json({ ok: false, error: "Servidor Evolution no configurado" });
|
||||||
|
|
||||||
|
const baseUrl = EVOLUTION_BASE_URL.replace(/\/$/, "");
|
||||||
|
const headers = { "Content-Type": "application/json", "apikey": EVOLUTION_API_KEY.trim() };
|
||||||
|
|
||||||
|
// 1. Verificamos si la instancia existe en Evolution
|
||||||
|
let statusRes = await fetch(`${baseUrl}/instance/connectionState/${instanceName}`, { headers });
|
||||||
|
|
||||||
|
// 2. Si da 404, significa que nunca se ha creado. La creamos y pedimos el QR
|
||||||
|
if (statusRes.status === 404) {
|
||||||
|
await fetch(`${baseUrl}/instance/create`, {
|
||||||
|
method: 'POST', headers,
|
||||||
|
body: JSON.stringify({ instanceName: instanceName, qrcode: true, integration: "WHATSAPP-BAILEYS" })
|
||||||
|
});
|
||||||
|
// Esperamos un poco y volvemos a consultar
|
||||||
|
await new Promise(r => setTimeout(r, 2000));
|
||||||
|
statusRes = await fetch(`${baseUrl}/instance/connectionState/${instanceName}`, { headers });
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await statusRes.json();
|
||||||
|
|
||||||
|
// 3. Devolvemos el estado
|
||||||
|
if (data.instance?.state === 'open') {
|
||||||
|
return res.json({ ok: true, state: 'open', instanceName });
|
||||||
|
} else {
|
||||||
|
// Buscamos el QR
|
||||||
|
const qrRes = await fetch(`${baseUrl}/instance/connect/${instanceName}`, { headers });
|
||||||
|
const qrData = await qrRes.json();
|
||||||
|
return res.json({ ok: true, state: 'connecting', qr: qrData.base64 || qrData.code });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error consultando estado WA:", e);
|
||||||
|
res.status(500).json({ ok: false, error: "Error de conexión con el motor WA" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
app.get("/whatsapp/settings", authMiddleware, async (req, res) => {
|
app.get("/whatsapp/settings", authMiddleware, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const q = await pool.query("SELECT wa_settings FROM users WHERE id=$1", [req.user.accountId]);
|
const q = await pool.query("SELECT wa_settings FROM users WHERE id=$1", [req.user.accountId]);
|
||||||
@@ -1457,9 +1490,12 @@ app.post("/admin/users", authMiddleware, async (req, res) => { const client = aw
|
|||||||
app.put("/admin/users/:id", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const userId = req.params.id; const { fullName, email, phone, role, guilds, password, zones } = req.body; const p = normalizePhone(phone); await client.query('BEGIN'); if(password) { const hash = await bcrypt.hash(password, 10); await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, password_hash=$5, zones=$6 WHERE id=$7", [fullName, email, p, role, hash, JSON.stringify(zones || []), userId]); } else { await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, zones=$5 WHERE id=$6", [fullName, email, p, role, JSON.stringify(zones || []), userId]); } if (guilds && Array.isArray(guilds)) { await client.query("DELETE FROM user_guilds WHERE user_id=$1", [userId]); 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.put("/admin/users/:id", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const userId = req.params.id; const { fullName, email, phone, role, guilds, password, zones } = req.body; const p = normalizePhone(phone); await client.query('BEGIN'); if(password) { const hash = await bcrypt.hash(password, 10); await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, password_hash=$5, zones=$6 WHERE id=$7", [fullName, email, p, role, hash, JSON.stringify(zones || []), userId]); } else { await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, zones=$5 WHERE id=$6", [fullName, email, p, role, JSON.stringify(zones || []), userId]); } if (guilds && Array.isArray(guilds)) { await client.query("DELETE FROM user_guilds WHERE user_id=$1", [userId]); 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.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 }); } });
|
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 }); } });
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// 🏢 CONFIGURACIÓN EMPRESA (COLORES, LOGO, PORTAL)
|
||||||
|
// ==========================================
|
||||||
app.get("/config/company", authMiddleware, async (req, res) => {
|
app.get("/config/company", authMiddleware, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const q = await pool.query("SELECT company_slug, full_name, plan_tier, company_logo, portal_settings FROM users WHERE id=$1", [req.user.accountId]);
|
const q = await pool.query("SELECT company_slug, full_name, plan_tier, company_logo, portal_settings, app_settings FROM users WHERE id=$1", [req.user.accountId]);
|
||||||
res.json({ ok: true, config: q.rows[0] || {} });
|
res.json({ ok: true, config: q.rows[0] || {} });
|
||||||
} catch (e) { res.status(500).json({ ok: false }); }
|
} catch (e) { res.status(500).json({ ok: false }); }
|
||||||
});
|
});
|
||||||
@@ -1467,7 +1503,6 @@ app.get("/config/company", authMiddleware, async (req, res) => {
|
|||||||
app.post("/config/company", authMiddleware, async (req, res) => {
|
app.post("/config/company", authMiddleware, async (req, res) => {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
// Añadimos app_settings a la extracción de datos
|
|
||||||
const { slug, company_name, company_logo, portal_settings, app_settings } = req.body;
|
const { slug, company_name, company_logo, portal_settings, app_settings } = req.body;
|
||||||
|
|
||||||
let cleanSlug = null;
|
let cleanSlug = null;
|
||||||
@@ -1478,7 +1513,6 @@ app.post("/config/company", authMiddleware, async (req, res) => {
|
|||||||
if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Ese enlace ya está en uso por otra empresa" });
|
if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Ese enlace ya está en uso por otra empresa" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualizamos la consulta para incluir app_settings ($5)
|
|
||||||
await client.query(`
|
await client.query(`
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET company_slug = COALESCE($1, company_slug),
|
SET company_slug = COALESCE($1, company_slug),
|
||||||
|
|||||||
Reference in New Issue
Block a user