V0.1
This commit is contained in:
104
server/routes/api/events.js
Normal file
104
server/routes/api/events.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
import db from '../../db.js';
|
||||
import { badRequest } from '../../lib/http.js';
|
||||
import { mapEvent } from '../../lib/mappers.js';
|
||||
import { computeRemoteDurationSeconds } from '../../teamviewer.js';
|
||||
|
||||
const EVENT_TYPES_USER = new Set(['NOTE', 'CALL', 'REMOTE', 'PART']);
|
||||
|
||||
export function registerEventRoutes(api) {
|
||||
api.post('/events', (req, res) => {
|
||||
const b = req.body || {};
|
||||
const ticketId = b.ticketId;
|
||||
const type = b.type;
|
||||
if (!ticketId || !type || !EVENT_TYPES_USER.has(type)) {
|
||||
return badRequest(res, 'Pflichtfelder fehlen oder ungültiger Typ.');
|
||||
}
|
||||
const t = db
|
||||
.prepare('SELECT 1 AS ok FROM tickets WHERE id = ?')
|
||||
.get(ticketId);
|
||||
if (!t) return res.status(404).json({ message: 'Nicht gefunden' });
|
||||
|
||||
const desc = b.description != null ? String(b.description).trim() : '';
|
||||
const callbackNumber =
|
||||
b.callbackNumber != null ? String(b.callbackNumber).trim() : '';
|
||||
const teamviewerId =
|
||||
b.teamviewerId != null ? String(b.teamviewerId).trim() : '';
|
||||
const articleNumber =
|
||||
b.articleNumber != null ? String(b.articleNumber).trim() : '';
|
||||
|
||||
let description = desc;
|
||||
let cb = callbackNumber || null;
|
||||
let tv = teamviewerId || null;
|
||||
let art = articleNumber || null;
|
||||
|
||||
if (type === 'NOTE') {
|
||||
if (!description) return badRequest(res, 'Beschreibung fehlt.');
|
||||
cb = null;
|
||||
tv = null;
|
||||
art = null;
|
||||
} else if (type === 'CALL') {
|
||||
// Rückrufnummer optional; nur Beschreibung ist Pflicht.
|
||||
if (!description) return badRequest(res, 'Beschreibung fehlt.');
|
||||
tv = null;
|
||||
art = null;
|
||||
} else if (type === 'REMOTE') {
|
||||
if (!description?.trim() && !tv) {
|
||||
return badRequest(res, 'Beschreibung oder TeamViewer-Gerät erforderlich.');
|
||||
}
|
||||
cb = null;
|
||||
art = null;
|
||||
} else if (type === 'PART') {
|
||||
if (!articleNumber) return badRequest(res, 'Artikelnummer fehlt.');
|
||||
description = desc;
|
||||
cb = null;
|
||||
tv = null;
|
||||
}
|
||||
|
||||
let remoteDurationSeconds = null;
|
||||
let teamviewerNotes = null;
|
||||
if (type === 'REMOTE') {
|
||||
remoteDurationSeconds = computeRemoteDurationSeconds(
|
||||
b.teamviewerStartDate,
|
||||
b.teamviewerEndDate,
|
||||
);
|
||||
const tn =
|
||||
b.teamviewerNotes != null ? String(b.teamviewerNotes).trim() : '';
|
||||
teamviewerNotes = tn || null;
|
||||
}
|
||||
|
||||
const eid = randomUUID();
|
||||
|
||||
db.exec('BEGIN');
|
||||
try {
|
||||
const row = db
|
||||
.prepare(
|
||||
`INSERT INTO events (id, ticket_id, type, description, callback_number, teamviewer_id, article_number, remote_duration_seconds, teamviewer_notes)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
||||
)
|
||||
.get(
|
||||
eid,
|
||||
ticketId,
|
||||
type,
|
||||
description,
|
||||
cb,
|
||||
tv,
|
||||
art,
|
||||
remoteDurationSeconds,
|
||||
teamviewerNotes,
|
||||
);
|
||||
|
||||
db.prepare(
|
||||
`UPDATE tickets SET updated_at = datetime('now'),
|
||||
sla_anchor_at = CASE WHEN status IN ('OPEN', 'WAITING') THEN datetime('now') ELSE sla_anchor_at END
|
||||
WHERE id = ?`,
|
||||
).run(ticketId);
|
||||
|
||||
db.exec('COMMIT');
|
||||
res.status(201).json(mapEvent(row));
|
||||
} catch (e) {
|
||||
db.exec('ROLLBACK');
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user