feat: aggiunta tracciatura delle modifiche effettuate

This commit is contained in:
2026-07-07 21:51:58 +02:00
parent 3f6d2cc3a8
commit bf8b4c387e
10 changed files with 914 additions and 0 deletions
+123
View File
@@ -1,6 +1,23 @@
const express = require('express');
const router = express.Router();
const pool = require('../db');
const { logAttivita } = require('../activityDb');
// Helper: resolve agent name from DB (best-effort, non-blocking)
async function resolveAgentName(agentId) {
try {
const r = await pool.query(
`SELECT first_name, last_name, login FROM users WHERE id = $1`,
[agentId]
);
if (r.rows.length > 0) {
const u = r.rows[0];
return (u.first_name || '') + ' ' + (u.last_name || '') || u.login || `Agent #${agentId}`;
}
} catch (_) { /* ignore */ }
return `Agent #${agentId}`;
}
// Helper for OTRS CE GenericInterface REST API calls
async function otrsRequest(method, path, bodyData = {}) {
@@ -301,6 +318,7 @@ router.get('/:id', async (req, res) => {
// POST /api/tickets — Create new ticket
// ============================================================
router.post('/', async (req, res) => {
const operatorId = parseInt(req.headers['x-agent-id'], 10) || 1;
const client = await pool.connect();
try {
const {
@@ -528,6 +546,17 @@ router.post('/', async (req, res) => {
await client.query('COMMIT');
// Log activity
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Creazione Ticket',
azione: { ticket_id: ticketId, tn: ticketResult.rows[0].tn, title, queue_id, state_id, priority_id, customer_id, customer_user_id },
esito: 'successo',
});
});
res.status(201).json({
id: ticketId,
tn: ticketResult.rows[0].tn,
@@ -536,6 +565,9 @@ router.post('/', async (req, res) => {
} catch (err) {
await client.query('ROLLBACK');
console.error('Error creating ticket:', err);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({ agente_id: operatorId, agente_nome, titolo_azione: 'Creazione Ticket', azione: { error: err.message }, esito: 'errore' });
});
res.status(500).json({ error: err.message });
} finally {
client.release();
@@ -620,6 +652,16 @@ router.patch('/:id', async (req, res) => {
};
}
const result = await otrsRequest('PATCH', `/Ticket/${id}`, reqBody);
const isClosing = updates.ticket_state_id && current.ticket_state_id !== updates.ticket_state_id;
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: isClosing ? 'Chiusura Ticket' : 'Modifica Rapida Ticket',
azione: { ticket_id: id, ...updates },
esito: 'successo',
});
});
return res.json({ message: 'Ticket aggiornato! (via API REST)', result });
}
return res.json({ message: 'Nessuna modifica rilevata' });
@@ -819,10 +861,23 @@ router.patch('/:id', async (req, res) => {
}
await client.query('COMMIT');
const isClosingDB = updates.ticket_state_id && current.ticket_state_id !== updates.ticket_state_id;
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: isClosingDB ? 'Chiusura Ticket' : 'Modifica Rapida Ticket',
azione: { ticket_id: id, ...updates },
esito: 'successo',
});
});
res.json({ message: 'Ticket aggiornato! (via DB)' });
} catch (err) {
await client.query('ROLLBACK');
console.error('Error updating ticket:', err);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({ agente_id: operatorId, agente_nome, titolo_azione: 'Modifica Rapida Ticket', azione: { ticket_id: id, error: err.message }, esito: 'errore' });
});
res.status(500).json({ error: err.message });
} finally {
client.release();
@@ -902,6 +957,15 @@ router.post('/:id/articles', async (req, res) => {
}
const result = await otrsRequest('PATCH', `/Ticket/${id}`, payload);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Aggiunta Nota',
azione: { ticket_id: id, subject, time_unit, has_attachments: !!(attachments && attachments.length) },
esito: 'successo',
});
});
return res.status(201).json({
message: 'Nota aggiunta! (via API REST)',
article_id: result.ArticleID,
@@ -1065,6 +1129,16 @@ router.post('/:id/articles', async (req, res) => {
await client.query('COMMIT');
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Aggiunta Nota',
azione: { ticket_id: id, subject, time_unit, has_attachments: !!(attachments && attachments.length) },
esito: 'successo',
});
});
res.status(201).json({
article_id: articleId,
message: 'Nota aggiunta! (via DB)',
@@ -1072,6 +1146,9 @@ router.post('/:id/articles', async (req, res) => {
} catch (err) {
await client.query('ROLLBACK');
console.error('Error adding article:', err);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({ agente_id: operatorId, agente_nome, titolo_azione: 'Aggiunta Nota', azione: { ticket_id: id, error: err.message }, esito: 'errore' });
});
res.status(500).json({ error: err.message });
} finally {
client.release();
@@ -1123,6 +1200,15 @@ router.patch('/batch/update', async (req, res) => {
Ticket: ticketFields
});
}
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Azione Massiva',
azione: { ticket_ids, updates },
esito: 'successo',
});
});
return res.json({
message: `${ticket_ids.length} ticket aggiornati! (via API REST)`,
updated_count: ticket_ids.length,
@@ -1172,6 +1258,16 @@ router.patch('/batch/update', async (req, res) => {
await client.query('COMMIT');
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Azione Massiva',
azione: { ticket_ids, updates },
esito: 'successo',
});
});
res.json({
message: `${ticket_ids.length} ticket aggiornati! (via DB)`,
updated_count: ticket_ids.length,
@@ -1179,6 +1275,9 @@ router.patch('/batch/update', async (req, res) => {
} catch (err) {
await client.query('ROLLBACK');
console.error('Error batch updating tickets:', err);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({ agente_id: operatorId, agente_nome, titolo_azione: 'Azione Massiva', azione: { ticket_ids, error: err.message }, esito: 'errore' });
});
res.status(500).json({ error: err.message });
} finally {
client.release();
@@ -1382,10 +1481,22 @@ router.post('/merge', async (req, res) => {
}
await client.query('COMMIT');
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Unione Ticket',
azione: { target_id: targetId, source_ids: sourceIds },
esito: 'successo',
});
});
res.json({ message: 'Ticket uniti con successo!' });
} catch (err) {
await client.query('ROLLBACK');
console.error('Error merging tickets:', err);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({ agente_id: operatorId, agente_nome, titolo_azione: 'Unione Ticket', azione: { target_id: targetId, source_ids: sourceIds, error: err.message }, esito: 'errore' });
});
res.status(500).json({ error: err.message });
} finally {
client.release();
@@ -1446,10 +1557,22 @@ router.put('/articles/:articleId/time', async (req, res) => {
}
await client.query('COMMIT');
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({
agente_id: operatorId,
agente_nome,
titolo_azione: 'Modifica Tempo Articolo',
azione: { article_id: articleId, time_unit: parsedTime },
esito: 'successo',
});
});
res.json({ message: 'Tempo aggiornato con successo!' });
} catch (err) {
await client.query('ROLLBACK');
console.error('Error updating article time:', err);
resolveAgentName(operatorId).then(agente_nome => {
logAttivita({ agente_id: operatorId, agente_nome, titolo_azione: 'Modifica Tempo Articolo', azione: { article_id: articleId, error: err.message }, esito: 'errore' });
});
res.status(500).json({ error: err.message });
} finally {
client.release();