94 lines
4.2 KiB
PHP
94 lines
4.2 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
require_once __DIR__ . '/common.php';
|
||
|
||
api_require_method('GET');
|
||
$staff = api_require_staff();
|
||
$number = trim((string) ($_GET['number'] ?? ''));
|
||
if ($number === '') {
|
||
api_error(422, 'TICKET_NUMBER_REQUIRED', 'Eine Ticketnummer ist erforderlich.');
|
||
}
|
||
$pdo = get_db();
|
||
$ticket = api_find_ticket($pdo, $staff, $number);
|
||
|
||
// Generelle Ticket-Sperre (nicht Live-Chat-spezifisch, siehe ticket_locked_by_other()
|
||
// in includes/functions.php): wird von einem anderen Mitarbeiter (Web oder App) gerade
|
||
// frisch bearbeitet, wird das Ticket hier – anders als beim milderen Live-Chat-Lock
|
||
// weiter unten – gar nicht erst geladen, genau wie im Web-Backend (ticket_view.php).
|
||
if ($ticket['source'] !== 'chat') {
|
||
$lockedByName = ticket_locked_by_other($ticket, (int) $staff['id'], $pdo);
|
||
if ($lockedByName) {
|
||
api_error(409, 'TICKET_LOCKED', "Dieses Ticket wird gerade von \"$lockedByName\" bearbeitet und kann nicht gleichzeitig geöffnet werden.");
|
||
}
|
||
ticket_acquire_lock((int) $ticket['id'], (int) $staff['id'], $pdo);
|
||
}
|
||
|
||
$threadStmt = $pdo->prepare(
|
||
'SELECT tt.*, s.name AS staff_name, u.name AS user_name
|
||
FROM ticket_threads tt
|
||
LEFT JOIN staff s ON s.id = tt.staff_id
|
||
LEFT JOIN users u ON u.id = tt.user_id
|
||
WHERE tt.ticket_id = ?
|
||
ORDER BY tt.created_at ASC, tt.id ASC'
|
||
);
|
||
$threadStmt->execute([$ticket['id']]);
|
||
$attachmentStmt = $pdo->prepare(
|
||
'SELECT id, original_name, filesize FROM ticket_attachments WHERE thread_id = ? ORDER BY id'
|
||
);
|
||
$commentStmt = $pdo->prepare(
|
||
'SELECT tc.id, tc.message, tc.created_at, s.id AS staff_id, s.name AS staff_name
|
||
FROM ticket_thread_comments tc
|
||
JOIN staff s ON s.id = tc.staff_id
|
||
WHERE tc.thread_id = ? ORDER BY tc.created_at, tc.id'
|
||
);
|
||
$threads = [];
|
||
foreach ($threadStmt->fetchAll() as $row) {
|
||
$attachmentStmt->execute([$row['id']]);
|
||
$commentStmt->execute([$row['id']]);
|
||
$threads[] = [
|
||
'id' => (int) $row['id'],
|
||
'authorType' => $row['author_type'],
|
||
'authorName' => $row['staff_name'] ?: $row['user_name'] ?: $ticket['requester_name'],
|
||
'message' => api_plain_text($row['message']),
|
||
'isInternalNote' => (bool) $row['is_internal_note'],
|
||
'createdAt' => $row['created_at'],
|
||
'attachments' => array_map(fn(array $item) => [
|
||
'id' => (int) $item['id'],
|
||
'name' => $item['original_name'],
|
||
'size' => (int) $item['filesize'],
|
||
], $attachmentStmt->fetchAll()),
|
||
'comments' => array_map(fn(array $item) => [
|
||
'id' => (int) $item['id'],
|
||
'message' => api_plain_text($item['message']),
|
||
'staff' => ['id' => (int) $item['staff_id'], 'name' => $item['staff_name']],
|
||
'createdAt' => $item['created_at'],
|
||
], $commentStmt->fetchAll()),
|
||
];
|
||
}
|
||
|
||
// Live-Chat-Sperre: wie im Web-Backend (staff/live_chat.php) "besitzt" der Mitarbeiter,
|
||
// der den Chat gerade ansieht, ihn für ein paar Minuten – verhindert, dass App und Web
|
||
// gleichzeitig unbemerkt im selben Chat antworten. Nur für Live-Chat-Tickets relevant,
|
||
// normale Tickets bleiben unangetastet. Lesen bleibt für alle möglich, nur das
|
||
// Schreiben wird in api_add_ticket_message() serverseitig blockiert.
|
||
$lockedByOtherName = null;
|
||
if ($ticket['source'] === 'chat' && $ticket['status'] !== 'closed') {
|
||
$lockedByOtherName = live_chat_locked_by_other($ticket, (int) $staff['id'], $pdo);
|
||
if (!$lockedByOtherName) {
|
||
live_chat_acquire_lock((int) $ticket['id'], (int) $staff['id'], $pdo);
|
||
}
|
||
}
|
||
|
||
$summary = api_ticket_summary($ticket);
|
||
$summary['source'] = $ticket['source'];
|
||
$summary['firstResponseDueAt'] = $ticket['first_response_due_at'];
|
||
$summary['resolutionDueAt'] = $ticket['resolution_due_at'];
|
||
$summary['lockedByOtherName'] = $lockedByOtherName;
|
||
$summary['threads'] = $threads;
|
||
// Rechte für GENAU dieses Ticket: gelten pro Abteilung (Rolle des Mitarbeiters in der Abteilung des Tickets)
|
||
$summary['permissions'] = [];
|
||
foreach (['reply_ticket', 'post_note', 'close_ticket', 'assign_ticket', 'transfer_ticket', 'delete_ticket'] as $__perm) {
|
||
$summary['permissions'][$__perm] = has_permission($staff, $__perm, (int) $ticket['department_id']);
|
||
}
|
||
api_json(['ticket' => $summary]);
|