Files
2026-07-05 23:33:52 +02:00

189 lines
6.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require('fs');
const path = require('path');
// Load environment variables if .env exists
try {
const dotenvPath = path.resolve(__dirname, '../.env');
if (fs.existsSync(dotenvPath)) {
require('dotenv').config({ path: dotenvPath });
}
} catch (err) {}
const port = process.env.PORT || 3000;
const baseUrl = `http://localhost:${port}`;
// Parse command line arguments
const args = process.argv.slice(2);
if (args.length < 2) {
console.log('\nUso: node scripts/bulk-injector.js <file-csv> <intervallo-secondi>\n');
console.log('Esempio: node scripts/bulk-injector.js tickets-sample.csv 5\n');
process.exit(1);
}
const csvPath = path.resolve(args[0]);
const intervalSeconds = parseFloat(args[1]);
if (!fs.existsSync(csvPath)) {
console.error(`Errore: il file CSV non esiste al percorso: ${csvPath}`);
process.exit(1);
}
if (isNaN(intervalSeconds) || intervalSeconds <= 0) {
console.error('Errore: specificare un intervallo in secondi valido (maggiore di 0)');
process.exit(1);
}
// Read and parse CSV
const content = fs.readFileSync(csvPath, 'utf-8');
const lines = content.split(/\r?\n/).map(line => line.trim()).filter(line => line.length > 0);
if (lines.length < 2) {
console.error('Errore: il file CSV deve contenere almeno l\'intestazione e una riga di dati.');
process.exit(1);
}
const headerLine = lines[0];
const delimiter = headerLine.includes(';') ? ';' : ',';
const headers = headerLine.split(delimiter).map(h => h.trim().replace(/^["']|["']$/g, ''));
const rows = [];
for (let i = 1; i < lines.length; i++) {
const cols = lines[i].split(delimiter).map(c => c.trim().replace(/^["']|["']$/g, ''));
const row = {};
headers.forEach((header, idx) => {
row[header] = cols[idx] || '';
});
rows.push(row);
}
// Start execution flow
async function start() {
console.log(`\n============================================================`);
console.log(`⚙️ OTRS Turbo - CSV Bulk Injector`);
console.log(`============================================================`);
console.log(`📂 File CSV caricato: ${path.basename(csvPath)} (${rows.length} righe)`);
console.log(`⏱️ Intervallo: ${intervalSeconds} secondi`);
console.log(`🌐 Server target: ${baseUrl}`);
// Fetch ticket types lookup
let ticketTypes = [];
try {
const typesRes = await fetch(`${baseUrl}/api/types`);
if (typesRes.ok) {
ticketTypes = await typesRes.json();
console.log(`📊 Tipi ticket caricati dal server: ${ticketTypes.length}`);
}
} catch (err) {
console.warn(`⚠️ Impossibile pre-caricare i tipi di ticket (verrà usato l'ID diretto): ${err.message}`);
}
console.log(`️ Premi Ctrl+C per arrestare il processo.`);
console.log(`============================================================\n`);
let currentIndex = 0;
async function injectNext() {
const row = rows[currentIndex];
console.log(`[${new Date().toLocaleTimeString()}] Invio riga ${currentIndex + 1}/${rows.length}: "${row.title || 'Senza titolo'}"...`);
// Determine type_id from CSV 'type' or 'type_id'
let type_id = undefined;
if (row.type) {
const parsedId = parseInt(row.type, 10);
if (!isNaN(parsedId)) {
type_id = parsedId;
} else {
const found = ticketTypes.find(t => t.name.toLowerCase() === row.type.toLowerCase());
if (found) {
type_id = found.id;
}
}
} else if (row.type_id) {
type_id = parseInt(row.type_id, 10);
}
// Build payload
const payload = {
title: row.title || 'Ticket da CSV',
queue_id: row.queue_id ? parseInt(row.queue_id, 10) : 1,
state_id: row.state_id ? parseInt(row.state_id, 10) : 1,
priority_id: row.priority_id ? parseInt(row.priority_id, 10) : 3,
type_id,
user_id: row.user_id ? parseInt(row.user_id, 10) : undefined,
responsible_user_id: row.responsible_user_id ? parseInt(row.responsible_user_id, 10) : undefined,
customer_id: row.customer_id || undefined,
customer_user_id: row.customer_user_id || undefined,
subject: row.subject || undefined,
body: row.body || undefined
};
try {
const response = await fetch(`${baseUrl}/api/tickets`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-agent-id': '1'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const resData = await response.json();
const ticketId = resData.id;
const tn = resData.tn;
console.log(` -> Successo: Creato Ticket #${tn} (ID: ${ticketId})`);
// Check for create_time retrodating
if (row.create_time) {
console.log(` -> Richiesta retrodatazione a: ${row.create_time}`);
// 1. Retrodate ticket
const ticketRetRes = await fetch(`${baseUrl}/api/tickets/${ticketId}/retrodata-ticket`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ create_time: row.create_time })
});
if (ticketRetRes.ok) {
console.log(` -> Ticket retrodatato.`);
} else {
console.error(` -> Errore retrodatazione ticket: ${await ticketRetRes.text()}`);
}
// 2. Fetch articles to retrodate
const detailRes = await fetch(`${baseUrl}/api/tickets/${ticketId}`);
if (detailRes.ok) {
const detail = await detailRes.json();
const articles = detail.articles || [];
for (const art of articles) {
const artRetRes = await fetch(`${baseUrl}/api/tickets/articles/${art.article_id}/retrodata-article`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ create_time: row.create_time })
});
if (artRetRes.ok) {
console.log(` -> Articolo ID ${art.article_id} retrodatato.`);
} else {
console.error(` -> Errore retrodatazione articolo ID ${art.article_id}: ${await artRetRes.text()}`);
}
}
}
}
} catch (err) {
console.error(` ❌ Errore iniezione riga: ${err.message}`);
}
// Cycle to next row
currentIndex = (currentIndex + 1) % rows.length;
}
// Start immediately and schedule next executions
injectNext();
setInterval(injectNext, intervalSeconds * 1000);
}
start();