Redact ticket title for non-public tickets in create/status-change Matrix notifications (#46)
sendTicketNotification() and sendStatusChangeNotification() always sent the ticket title to the shared MATRIX_NOTIFY_USERS list regardless of visibility, unlike sendCommentNotification()/notifyWatchers() which already redact the comment/activity preview for non-public tickets. Creating or changing the status of a confidential ticket broadcast its title to a shared Matrix room, defeating the point of the Confidential visibility level. Added a shared redactedTitle() helper and threaded visibility through both functions (sendTicketNotification reads it from the existing $ticketData['visibility'] key; sendStatusChangeNotification takes a new optional parameter, wired up in both callers from the already-fetched ticket row). Verified end-to-end with a local HTTP server capturing the actual webhook payloads: public tickets pass the title through unchanged, confidential/internal tickets get the redacted placeholder. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015nCxwFFsy8ouMWzn56rPVP
This commit is contained in:
@@ -171,7 +171,8 @@ if ($currentStatus !== $newStatus) {
|
||||
$currentStatus,
|
||||
$newStatus,
|
||||
(string)$ticket['title'],
|
||||
$keyName
|
||||
$keyName,
|
||||
$ticket['visibility'] ?? 'public'
|
||||
);
|
||||
NotificationHelper::notifyWatchers(
|
||||
$conn,
|
||||
|
||||
@@ -267,7 +267,8 @@ try {
|
||||
$currentTicket['status'],
|
||||
$updateData['status'],
|
||||
$updateData['title'],
|
||||
$changedBy
|
||||
$changedBy,
|
||||
$currentTicket['visibility'] ?? 'public'
|
||||
);
|
||||
NotificationHelper::notifyWatchers(
|
||||
$this->conn,
|
||||
|
||||
@@ -40,20 +40,40 @@ class NotificationHelper
|
||||
return array_values(array_filter(array_map('trim', explode(',', $raw))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Redact a ticket title for the shared Matrix notify list when the
|
||||
* ticket isn't public, matching how sendCommentNotification() and
|
||||
* notifyWatchers() already redact comment/activity previews for the
|
||||
* same list.
|
||||
*/
|
||||
private static function redactedTitle(string $title, string $visibility): string
|
||||
{
|
||||
return $visibility === 'public' ? $title : '(restricted ticket — title hidden)';
|
||||
}
|
||||
|
||||
// ─── Public event methods ─────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* New ticket created (manual or automated/API).
|
||||
*
|
||||
* $ticketData['visibility'] ('public', 'internal', or 'confidential') is
|
||||
* used to redact the title sent to the shared MATRIX_NOTIFY_USERS list
|
||||
* for non-public tickets, same as sendCommentNotification()'s preview
|
||||
* redaction. Defaults to 'public' for callers (e.g. the hwmonDaemon
|
||||
* Bearer-API paths) that never set a non-default visibility.
|
||||
*/
|
||||
public static function sendTicketNotification($ticketId, array $ticketData, string $trigger = 'manual'): void
|
||||
{
|
||||
preg_match('/^\[([^\]]+)\]/', $ticketData['title'] ?? '', $m);
|
||||
$visibility = $ticketData['visibility'] ?? 'public';
|
||||
$title = $ticketData['title'] ?? 'Untitled';
|
||||
|
||||
preg_match('/^\[([^\]]+)\]/', $title, $m);
|
||||
$source = $m[1] ?? ($trigger === 'automated' ? 'Automated' : 'Manual');
|
||||
|
||||
self::fire([
|
||||
'event' => 'ticket_created',
|
||||
'ticket_id' => $ticketId,
|
||||
'title' => $ticketData['title'] ?? 'Untitled',
|
||||
'title' => self::redactedTitle($title, $visibility),
|
||||
'priority' => (int)($ticketData['priority'] ?? 4),
|
||||
'category' => $ticketData['category'] ?? 'General',
|
||||
'type' => $ticketData['type'] ?? 'Issue',
|
||||
@@ -73,13 +93,16 @@ class NotificationHelper
|
||||
* @param string $newStatus
|
||||
* @param string $ticketTitle
|
||||
* @param string|null $changedByDisplay Display name of the user who changed status
|
||||
* @param string $visibility Ticket visibility; non-public titles are
|
||||
* redacted before being sent to the shared
|
||||
* notify list, same as sendTicketNotification().
|
||||
*/
|
||||
public static function sendStatusChangeNotification($ticketId, string $oldStatus, string $newStatus, string $ticketTitle, ?string $changedByDisplay = null): void
|
||||
public static function sendStatusChangeNotification($ticketId, string $oldStatus, string $newStatus, string $ticketTitle, ?string $changedByDisplay = null, string $visibility = 'public'): void
|
||||
{
|
||||
self::fire([
|
||||
'event' => 'status_changed',
|
||||
'ticket_id' => $ticketId,
|
||||
'title' => $ticketTitle,
|
||||
'title' => self::redactedTitle($ticketTitle, $visibility),
|
||||
'old_status' => $oldStatus,
|
||||
'new_status' => $newStatus,
|
||||
'changed_by' => $changedByDisplay,
|
||||
|
||||
Reference in New Issue
Block a user