189 lines
6.4 KiB
JavaScript
189 lines
6.4 KiB
JavaScript
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();
|