remove users, chats, etc
This commit is contained in:
244
scripts/reset-tenant-data.mjs
Normal file
244
scripts/reset-tenant-data.mjs
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/**
|
||||||
|
* Script para resetear datos de conversación de un tenant
|
||||||
|
*
|
||||||
|
* Uso:
|
||||||
|
* node scripts/reset-tenant-data.mjs --tenant-key piaf
|
||||||
|
* node scripts/reset-tenant-data.mjs --tenant-key piaf --keep-audit
|
||||||
|
* node scripts/reset-tenant-data.mjs --tenant-key piaf --yes # Sin confirmación
|
||||||
|
*
|
||||||
|
* Tablas que se limpian (en orden):
|
||||||
|
* 1. human_takeovers
|
||||||
|
* 2. wa_messages
|
||||||
|
* 3. conversation_runs
|
||||||
|
* 4. wa_conversation_state
|
||||||
|
* 5. wa_identity_map
|
||||||
|
* 6. audit_log (opcional, se borra por defecto)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "dotenv/config";
|
||||||
|
import readline from "readline";
|
||||||
|
import { pool } from "../src/modules/shared/db/pool.js";
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Args parsing
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function parseArgs() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const out = {
|
||||||
|
tenantKey: null,
|
||||||
|
keepAudit: false,
|
||||||
|
yes: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
const a = args[i];
|
||||||
|
if (a === "--tenant-key") out.tenantKey = args[++i];
|
||||||
|
else if (a === "--keep-audit") out.keepAudit = true;
|
||||||
|
else if (a === "--yes" || a === "-y") out.yes = true;
|
||||||
|
else if (a === "--help" || a === "-h") {
|
||||||
|
printHelp();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out.tenantKey) {
|
||||||
|
console.error("Error: --tenant-key es requerido\n");
|
||||||
|
printHelp();
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printHelp() {
|
||||||
|
console.log(`
|
||||||
|
Uso: node scripts/reset-tenant-data.mjs [opciones]
|
||||||
|
|
||||||
|
Opciones:
|
||||||
|
--tenant-key <key> Clave del tenant (requerido)
|
||||||
|
--keep-audit No borrar audit_log
|
||||||
|
--yes, -y Confirmar automáticamente (sin prompt)
|
||||||
|
--help, -h Mostrar esta ayuda
|
||||||
|
|
||||||
|
Ejemplos:
|
||||||
|
node scripts/reset-tenant-data.mjs --tenant-key piaf
|
||||||
|
node scripts/reset-tenant-data.mjs --tenant-key piaf --keep-audit
|
||||||
|
node scripts/reset-tenant-data.mjs --tenant-key piaf --yes
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Confirmación interactiva
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function askConfirmation(message) {
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
rl.question(message, (answer) => {
|
||||||
|
rl.close();
|
||||||
|
resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes" || answer.toLowerCase() === "si");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Reset de datos
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function getTenantByKey(tenantKey) {
|
||||||
|
const { rows } = await pool.query(
|
||||||
|
`SELECT id, key, name FROM tenants WHERE key = $1`,
|
||||||
|
[tenantKey]
|
||||||
|
);
|
||||||
|
return rows[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getStats(tenantId) {
|
||||||
|
const queries = [
|
||||||
|
{ name: "human_takeovers", sql: `SELECT COUNT(*) as count FROM human_takeovers WHERE tenant_id = $1` },
|
||||||
|
{ name: "wa_messages", sql: `SELECT COUNT(*) as count FROM wa_messages WHERE tenant_id = $1` },
|
||||||
|
{ name: "conversation_runs", sql: `SELECT COUNT(*) as count FROM conversation_runs WHERE tenant_id = $1` },
|
||||||
|
{ name: "wa_conversation_state", sql: `SELECT COUNT(*) as count FROM wa_conversation_state WHERE tenant_id = $1` },
|
||||||
|
{ name: "wa_identity_map", sql: `SELECT COUNT(*) as count FROM wa_identity_map WHERE tenant_id = $1` },
|
||||||
|
{ name: "audit_log", sql: `SELECT COUNT(*) as count FROM audit_log WHERE tenant_id = $1` },
|
||||||
|
];
|
||||||
|
|
||||||
|
const stats = {};
|
||||||
|
for (const q of queries) {
|
||||||
|
const { rows } = await pool.query(q.sql, [tenantId]);
|
||||||
|
stats[q.name] = parseInt(rows[0].count, 10);
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resetTenantData({ tenantId, keepAudit = false }) {
|
||||||
|
const client = await pool.connect();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.query("BEGIN");
|
||||||
|
|
||||||
|
// 1. human_takeovers
|
||||||
|
const r1 = await client.query(
|
||||||
|
`DELETE FROM human_takeovers WHERE tenant_id = $1`,
|
||||||
|
[tenantId]
|
||||||
|
);
|
||||||
|
console.log(` - human_takeovers: ${r1.rowCount} registros eliminados`);
|
||||||
|
|
||||||
|
// 2. wa_messages
|
||||||
|
const r2 = await client.query(
|
||||||
|
`DELETE FROM wa_messages WHERE tenant_id = $1`,
|
||||||
|
[tenantId]
|
||||||
|
);
|
||||||
|
console.log(` - wa_messages: ${r2.rowCount} registros eliminados`);
|
||||||
|
|
||||||
|
// 3. conversation_runs
|
||||||
|
const r3 = await client.query(
|
||||||
|
`DELETE FROM conversation_runs WHERE tenant_id = $1`,
|
||||||
|
[tenantId]
|
||||||
|
);
|
||||||
|
console.log(` - conversation_runs: ${r3.rowCount} registros eliminados`);
|
||||||
|
|
||||||
|
// 4. wa_conversation_state
|
||||||
|
const r4 = await client.query(
|
||||||
|
`DELETE FROM wa_conversation_state WHERE tenant_id = $1`,
|
||||||
|
[tenantId]
|
||||||
|
);
|
||||||
|
console.log(` - wa_conversation_state: ${r4.rowCount} registros eliminados`);
|
||||||
|
|
||||||
|
// 5. wa_identity_map
|
||||||
|
const r5 = await client.query(
|
||||||
|
`DELETE FROM wa_identity_map WHERE tenant_id = $1`,
|
||||||
|
[tenantId]
|
||||||
|
);
|
||||||
|
console.log(` - wa_identity_map: ${r5.rowCount} registros eliminados`);
|
||||||
|
|
||||||
|
// 6. audit_log (opcional)
|
||||||
|
if (!keepAudit) {
|
||||||
|
const r6 = await client.query(
|
||||||
|
`DELETE FROM audit_log WHERE tenant_id = $1`,
|
||||||
|
[tenantId]
|
||||||
|
);
|
||||||
|
console.log(` - audit_log: ${r6.rowCount} registros eliminados`);
|
||||||
|
} else {
|
||||||
|
console.log(` - audit_log: conservado (--keep-audit)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.query("COMMIT");
|
||||||
|
|
||||||
|
return { ok: true };
|
||||||
|
} catch (err) {
|
||||||
|
await client.query("ROLLBACK");
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
client.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Main
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = parseArgs();
|
||||||
|
|
||||||
|
console.log("\n🔄 Reset de datos de tenant\n");
|
||||||
|
|
||||||
|
// Buscar tenant
|
||||||
|
const tenant = await getTenantByKey(args.tenantKey);
|
||||||
|
if (!tenant) {
|
||||||
|
console.error(`Error: No se encontró tenant con key "${args.tenantKey}"`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Tenant: ${tenant.name} (${tenant.key})`);
|
||||||
|
console.log(`ID: ${tenant.id}\n`);
|
||||||
|
|
||||||
|
// Mostrar estadísticas
|
||||||
|
console.log("Registros actuales:");
|
||||||
|
const stats = await getStats(tenant.id);
|
||||||
|
for (const [table, count] of Object.entries(stats)) {
|
||||||
|
console.log(` - ${table}: ${count}`);
|
||||||
|
}
|
||||||
|
console.log("");
|
||||||
|
|
||||||
|
const total = Object.values(stats).reduce((a, b) => a + b, 0);
|
||||||
|
if (total === 0) {
|
||||||
|
console.log("No hay datos para eliminar.");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirmación
|
||||||
|
if (!args.yes) {
|
||||||
|
const confirm = await askConfirmation(
|
||||||
|
`⚠️ Se eliminarán ${total} registros. ¿Continuar? (y/N): `
|
||||||
|
);
|
||||||
|
if (!confirm) {
|
||||||
|
console.log("Operación cancelada.");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\nEliminando datos...\n");
|
||||||
|
|
||||||
|
// Ejecutar reset
|
||||||
|
await resetTenantData({
|
||||||
|
tenantId: tenant.id,
|
||||||
|
keepAudit: args.keepAudit
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\n✅ Reset completado exitosamente.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("\n❌ Error:", err.message);
|
||||||
|
process.exit(1);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
pool.end();
|
||||||
|
});
|
||||||
@@ -100,12 +100,8 @@ export async function upsertSettings({ tenantId, settings }) {
|
|||||||
pickup_hours_end || null,
|
pickup_hours_end || null,
|
||||||
];
|
];
|
||||||
|
|
||||||
console.log("[settingsRepo] upsertSettings params:", params);
|
|
||||||
|
|
||||||
const { rows } = await pool.query(sql, params);
|
const { rows } = await pool.query(sql, params);
|
||||||
|
|
||||||
console.log("[settingsRepo] upsertSettings result:", rows[0]);
|
|
||||||
|
|
||||||
return rows[0];
|
return rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ export async function handleGetSettings({ tenantId }) {
|
|||||||
* Guarda la configuración del tenant
|
* Guarda la configuración del tenant
|
||||||
*/
|
*/
|
||||||
export async function handleSaveSettings({ tenantId, settings }) {
|
export async function handleSaveSettings({ tenantId, settings }) {
|
||||||
console.log("[settings] handleSaveSettings", { tenantId, settings });
|
|
||||||
|
|
||||||
// Validaciones básicas
|
// Validaciones básicas
|
||||||
if (!settings.store_name?.trim()) {
|
if (!settings.store_name?.trim()) {
|
||||||
throw new Error("store_name is required");
|
throw new Error("store_name is required");
|
||||||
|
|||||||
Reference in New Issue
Block a user