false, 'error' => 'unauthorized'], 401); } try { Database::requireTicketsTable(); } catch (RuntimeException $e) { json_out(['ok' => false, 'error' => 'tickets_table_missing', 'hint' => $e->getMessage()], 503); } $method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET'); if ($method === 'GET') { $ticketId = (int) ($_GET['ticket_id'] ?? 0); if ($ticketId <= 0) { json_out(['ok' => false, 'error' => 'invalid ticket_id'], 400); } $ticket = TicketRepository::getById($ticketId); if (!$ticket) { json_out(['ok' => false, 'error' => 'not found'], 404); } try { json_out(['ok' => true, 'comments' => TicketCommentRepository::listForTicket($ticketId)]); } catch (Throwable $e) { if (str_contains($e->getMessage(), 'ticket_comments') || str_contains($e->getMessage(), 'no such table')) { json_out(['ok' => false, 'error' => 'comments_table_missing', 'hint' => 'Run sql/migrations/004_ticket_workflow.sql'], 503); } throw $e; } } if ($method !== 'POST') { json_out(['ok' => false, 'error' => 'method not allowed'], 405); } $user = Auth::user(); $raw = file_get_contents('php://input'); $data = is_string($raw) && $raw !== '' ? json_decode($raw, true) : $_POST; if (!is_array($data)) { json_out(['ok' => false, 'error' => 'invalid json'], 400); } $ticketId = (int) ($data['ticket_id'] ?? 0); if ($ticketId <= 0) { json_out(['ok' => false, 'error' => 'invalid ticket_id'], 400); } $ticket = TicketRepository::getById($ticketId); if (!$ticket) { json_out(['ok' => false, 'error' => 'not found'], 404); } if (empty($ticket['can_edit']) && !Auth::canEditTags()) { json_out(['ok' => false, 'error' => 'forbidden'], 403); } try { $comment = TicketCommentRepository::add( $ticketId, (string) ($user['username'] ?? ''), (string) ($data['body'] ?? '') ); json_out(['ok' => true, 'comment' => $comment]); } catch (InvalidArgumentException $e) { json_out(['ok' => false, 'error' => $e->getMessage()], 400); } catch (Throwable $e) { if (str_contains($e->getMessage(), 'ticket_comments') || str_contains($e->getMessage(), 'no such table')) { json_out(['ok' => false, 'error' => 'comments_table_missing', 'hint' => 'Run sql/migrations/004_ticket_workflow.sql'], 503); } error_log('ticket_comments: ' . $e->getMessage()); json_out(['ok' => false, 'error' => 'save failed'], 500); }