Actualizar server.js
This commit is contained in:
73
server.js
73
server.js
@@ -906,6 +906,79 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 📱 OTP PARA PORTAL DEL CLIENTE (ACCESO WEB)
|
||||
// ==========================================
|
||||
app.post("/public/auth/request-otp", async (req, res) => {
|
||||
try {
|
||||
const { phone, owner_id } = req.body;
|
||||
if (!phone || !owner_id) return res.status(400).json({ ok: false, error: "Faltan datos" });
|
||||
|
||||
const p = normalizePhone(phone);
|
||||
// Generamos un código aleatorio de 4 dígitos
|
||||
const code = String(Math.floor(1000 + Math.random() * 9000));
|
||||
const codeHash = await bcrypt.hash(code, 10);
|
||||
|
||||
// Lo guardamos en la tabla de login_codes (ponemos user_id NULL porque es un cliente, no un operario)
|
||||
await pool.query(`
|
||||
INSERT INTO login_codes (user_id, phone, code_hash, purpose, expires_at)
|
||||
VALUES (NULL, $1, $2, 'client_portal', NOW() + INTERVAL '15 minutes')
|
||||
`, [p, codeHash]);
|
||||
|
||||
const msg = `👋 *Asistencia Técnica*\n\nTu código seguro de acceso al portal es: *${code}*\n\nCaduca en 15 minutos.`;
|
||||
|
||||
// Enviamos el WhatsApp usando la instancia de la empresa correspondiente
|
||||
sendWhatsAppAuto(p, msg, `cliente_${owner_id}`, false).catch(console.error);
|
||||
|
||||
res.json({ ok: true });
|
||||
} catch (e) {
|
||||
console.error("Error solicitando OTP cliente:", e);
|
||||
res.status(500).json({ ok: false });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/public/auth/verify-otp", async (req, res) => {
|
||||
try {
|
||||
const { phone, code, owner_id } = req.body;
|
||||
const p = normalizePhone(phone);
|
||||
|
||||
// 1. Buscamos si el código existe, es de cliente, y no está caducado
|
||||
const q = await pool.query(`
|
||||
SELECT id, code_hash FROM login_codes
|
||||
WHERE phone = $1 AND purpose = 'client_portal' AND consumed_at IS NULL AND expires_at > NOW()
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
`, [p]);
|
||||
|
||||
if (q.rowCount === 0) return res.status(400).json({ ok: false, error: "Código inválido o caducado" });
|
||||
|
||||
// 2. Comprobamos que el código de 4 dígitos coincide
|
||||
const valid = await bcrypt.compare(String(code), q.rows[0].code_hash);
|
||||
if (!valid) return res.status(400).json({ ok: false, error: "Código incorrecto" });
|
||||
|
||||
// 3. Quemamos el código para que no se pueda usar 2 veces
|
||||
await pool.query("UPDATE login_codes SET consumed_at = NOW() WHERE id = $1", [q.rows[0].id]);
|
||||
|
||||
// 4. Magia: Buscamos si este cliente ya nos ha llamado antes para pre-rellenar su formulario
|
||||
const cleanPhoneForSearch = String(phone).replace(/\D/g, "");
|
||||
const clientQ = await pool.query(
|
||||
"SELECT full_name, addresses FROM clients WHERE phone LIKE $1 AND owner_id = $2 LIMIT 1",
|
||||
[`%${cleanPhoneForSearch}%`, owner_id]
|
||||
);
|
||||
|
||||
let clientData = null;
|
||||
let exists = false;
|
||||
if (clientQ.rowCount > 0) {
|
||||
clientData = clientQ.rows[0];
|
||||
exists = true;
|
||||
}
|
||||
|
||||
res.json({ ok: true, exists, client: clientData });
|
||||
} catch (e) {
|
||||
console.error("Error verificando OTP cliente:", e);
|
||||
res.status(500).json({ ok: false });
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🌐 EMBUDO PÚBLICO DE ENTRADA DE CLIENTES
|
||||
// ==========================================
|
||||
|
||||
Reference in New Issue
Block a user