← back to Ticket System

ticket-export.js

21 lines

#!/usr/bin/env node
// Export all tickets as CSV (stdout). Used by gdrive-sync.sh to keep the live
// Drive copy current. 15 cols incl. created/updated/last-action dates + idle.
const { execSync } = require('child_process');
const now = Date.now();
const q = s => { s = (s == null ? '' : String(s)).replace(/\r?\n/g, ' ').replace(/"/g, '""'); return /[",]/.test(s) ? `"${s}"` : s; };
const fmt = d => { if (!d) return ''; const x = new Date(d); return isNaN(x) ? '' : x.toISOString().slice(0, 16).replace('T', ' '); };
const tk = JSON.parse(execSync(`curl -s -u admin:DW2024! http://127.0.0.1:9794/api/tickets`, { encoding: 'utf8', maxBuffer: 1 << 26 }) || '[]');
const ord = { doing: 0, blocked: 1, open: 2, done: 3 };
tk.sort((a, b) => (ord[a.status] ?? 9) - (ord[b.status] ?? 9) || String(a.id).localeCompare(String(b.id), undefined, { numeric: true }));
const rows = [['ID', 'Short', 'Status', 'Project', 'Assignee', 'Created By', 'Title', 'Created', 'Updated', 'Last Action', 'Last By', 'Idle (h)', '# Actions', '# Comments', 'Last Action Text']];
for (const t of tk) {
  const acts = (t.actions || []).slice().sort((a, b) => +new Date(b.ts) - +new Date(a.ts));
  const last = acts[0] || null;
  const idle = last ? ((now - +new Date(last.ts)) / 3600000).toFixed(1) : '';
  rows.push([t.id, (String(t.id).match(/^(TK-\d+)/) || ['', t.id])[1], t.status, t.project || '', t.assignee || '', t.agent || '',
    t.title || '', fmt(t.created_at), fmt(t.updated_at), fmt(last?.ts), last?.agent || '', idle,
    (t.actions || []).length, (t.comments || []).length, (last?.text || '').slice(0, 180)].map(q).join(','));
}
process.stdout.write(rows.join('\n') + '\n');