From eceeb4aa3b9ac56ee637125131e5493acb94d5c2 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 20 Nov 2025 10:56:43 -0800 Subject: [PATCH 1/6] return if there is no item for the audit notification --- app/Notifications/AuditNotification.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Notifications/AuditNotification.php b/app/Notifications/AuditNotification.php index abcd69c9b678..a01aca711457 100644 --- a/app/Notifications/AuditNotification.php +++ b/app/Notifications/AuditNotification.php @@ -84,6 +84,11 @@ public static function toMicrosoftTeams($params) $location = $params['location'] ?? ''; $setting = Setting::getSettings(); + //if somehow a notification triggers without an item, bail out. + if(!$item || !is_object($item)){ + return null; + } + if(!Str::contains($setting->webhook_endpoint, 'workflows')) { return MicrosoftTeamsMessage::create() ->to($setting->webhook_endpoint) From e598ef6e054b58156f411dd10d18bb5a6018b7ed Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 20 Nov 2025 13:51:14 -0800 Subject: [PATCH 2/6] adds tests, webhook enable settings --- app/Notifications/AuditNotification.php | 8 ++- resources/lang/en-US/general.php | 1 + .../Webhooks/NotificationTests.php | 60 +++++++++++++++++++ tests/Support/Settings.php | 7 +++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 tests/Feature/Notifications/Webhooks/NotificationTests.php diff --git a/app/Notifications/AuditNotification.php b/app/Notifications/AuditNotification.php index a01aca711457..fecb66f350d7 100644 --- a/app/Notifications/AuditNotification.php +++ b/app/Notifications/AuditNotification.php @@ -33,6 +33,10 @@ public function __construct($params) // $this->settings = Setting::getSettings(); $this->params = $params; + $item = $params['item']; + if (!$item || !is_object($item)) { + throw new \InvalidArgumentException('Notification requires a valid item.'); + } } /** @@ -93,12 +97,12 @@ public static function toMicrosoftTeams($params) return MicrosoftTeamsMessage::create() ->to($setting->webhook_endpoint) ->type('success') - ->title(class_basename(get_class($params['item'])) .' '.trans('general.audited')) + ->title(class_basename($item).' '.trans('general.audited')) ->addStartGroupToSection('activityText') ->fact(trans('mail.asset'), $item) ->fact(trans('general.administrator'), $admin_user->present()->viewUrl() . '|' . $admin_user->display_name); } - $message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->display_name; + $message = class_basename(get_class($params['item'])) . trans('general.audited_by').' '.$admin_user->display_name; $details = [ trans('mail.asset') => htmlspecialchars_decode($item->display_name), trans('mail.notes') => $note ?: '', diff --git a/resources/lang/en-US/general.php b/resources/lang/en-US/general.php index 29be666fe7fd..87b8cc111ee6 100644 --- a/resources/lang/en-US/general.php +++ b/resources/lang/en-US/general.php @@ -39,6 +39,7 @@ 'accept_items' => 'Accept Items', 'audit' => 'Audit', 'audited' => 'Audited', + 'audited_by' => 'Audited By', 'audits' => 'Audits', 'audit_report' => 'Audit Log', 'assets' => 'Assets', diff --git a/tests/Feature/Notifications/Webhooks/NotificationTests.php b/tests/Feature/Notifications/Webhooks/NotificationTests.php new file mode 100644 index 000000000000..b7a23ab32f2b --- /dev/null +++ b/tests/Feature/Notifications/Webhooks/NotificationTests.php @@ -0,0 +1,60 @@ + null, + ]); + $this->fail('Expected Error was not thrown'); + } catch (\Throwable $e) { + $this->assertInstanceOf(\InvalidArgumentException::class, $e); + $this->assertSame('Notification requires a valid item.', $e->getMessage()); + } + } + + public function testAuditNotificationFires() + { + $webhook_options = [ + 'enableSlackWebhook', + 'enableMicrosoftTeamsWebhook', + ]; + + Notification::fake(); + + foreach($webhook_options as $option) { + + $this->settings->{$option}(); + + $user = User::factory()->create(); + $item = Asset::factory()->create(); + + try { + $user->notify(new \App\Notifications\AuditNotification([ + 'item' => $item, + ])); + } catch (\InvalidArgumentException $e) { + $this->fail("AuditNotification threw for [{$option}]: {$e->getMessage()}"); + } + } + Notification::assertSentTimes(AuditNotification::class, count($webhook_options)); + } +} diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 8ff8ba6945ed..bb255bc67ccb 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -93,6 +93,13 @@ public function enableSlackWebhook(): Settings 'webhook_channel' => '#it', ]); } + public function enableMicrosoftTeamsWebhook(): Settings + { + return $this->update([ + 'webhook_selected' => 'microsoft', + 'webhook_endpoint' => 'https://defaultd07ceb04416641fca1b9d3e0ac7600.84.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/1babbc7a3cdd4cf99c0fbed4367cf147/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=sVXmAYF5luz3oOEjvN-G7mJqEEvFjBSETuAG8c3Qmkg', + ]); + } public function disableSlackWebhook(): Settings { From 24d7ae4a2f99ed9c9ed010b6aab23d69acc93ec3 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 20 Nov 2025 14:22:08 -0800 Subject: [PATCH 3/6] added google chat to audit notifications" --- app/Notifications/AuditNotification.php | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/app/Notifications/AuditNotification.php b/app/Notifications/AuditNotification.php index fecb66f350d7..af94cefddcb3 100644 --- a/app/Notifications/AuditNotification.php +++ b/app/Notifications/AuditNotification.php @@ -10,6 +10,11 @@ use Illuminate\Notifications\Notification; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; +use NotificationChannels\GoogleChat\Card; +use NotificationChannels\GoogleChat\GoogleChatChannel; +use NotificationChannels\GoogleChat\GoogleChatMessage; +use NotificationChannels\GoogleChat\Section; +use NotificationChannels\GoogleChat\Widgets\KeyValue; use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel; use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage; use Symfony\Component\Mime\Email; @@ -55,6 +60,10 @@ public function via() $notifyBy[] = MicrosoftTeamsChannel::class; } + if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) { + Log::debug('using google webhook'); + $notifyBy[] = GoogleChatChannel::class; + } return $notifyBy; } @@ -110,4 +119,35 @@ public static function toMicrosoftTeams($params) ]; return [$message, $details]; } + public function toGoogleChat() + { + $item = $this->params['item'] ?? null; + $admin_user = $this->params['admin'] ?? null; + $note = $this->params['note'] ?? ''; + $setting = $this->settings ?? Setting::getSettings(); + + $title = '' . class_basename($item) . ' ' . trans('general.audited') . ''; + $subtitle = htmlspecialchars_decode($item->display_name ?? ''); + \Log::debug('Google Chat audit payload', [ + 'title' => $title, + 'subtitle' => $subtitle, + 'admin' => $admin_user->display_name, + 'note' => $note, + ]); + return GoogleChatMessage::create() + ->to($setting->webhook_endpoint) + ->card( + Card::create() + ->header($title, $subtitle) + ->section( + Section::create( + KeyValue::create( + trans('general.audited_by'), + $admin_user?->display_name ?? '', + $note ?? '' + )->onClick(route('hardware.show', $item->id)) + ) + ) + ); + } } From 1116da389e02b362d0616e22a2060fcb6b07e543 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 20 Nov 2025 14:24:03 -0800 Subject: [PATCH 4/6] add google chat to audit notification test --- .../Notifications/Webhooks/NotificationTests.php | 1 + tests/Support/Settings.php | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/Feature/Notifications/Webhooks/NotificationTests.php b/tests/Feature/Notifications/Webhooks/NotificationTests.php index b7a23ab32f2b..09f3e8553c99 100644 --- a/tests/Feature/Notifications/Webhooks/NotificationTests.php +++ b/tests/Feature/Notifications/Webhooks/NotificationTests.php @@ -36,6 +36,7 @@ public function testAuditNotificationFires() $webhook_options = [ 'enableSlackWebhook', 'enableMicrosoftTeamsWebhook', + 'enableGoogleChatWebhook' ]; Notification::fake(); diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index bb255bc67ccb..1c5a68cd6379 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -98,7 +98,16 @@ public function enableMicrosoftTeamsWebhook(): Settings return $this->update([ 'webhook_selected' => 'microsoft', 'webhook_endpoint' => 'https://defaultd07ceb04416641fca1b9d3e0ac7600.84.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/1babbc7a3cdd4cf99c0fbed4367cf147/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=sVXmAYF5luz3oOEjvN-G7mJqEEvFjBSETuAG8c3Qmkg', - ]); + ]); + } + + public function enableGoogleChatWebhook(): Settings + { + return $this->update([ + 'webhook_selected' => 'google', + 'webhook_botname' => 'SnipeBot5000', + 'webhook_endpoint' => 'https://chat.googleapis.com/v1/spaces/AAAATQckuT4/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=bZDaFDK4lO78HhHmC8BEWI6aAKkgqX2gFv2gHVAc8VQ', + ]); } public function disableSlackWebhook(): Settings From cd42760b687dece0f960e6baa033643f4800c2bd Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 20 Nov 2025 14:25:13 -0800 Subject: [PATCH 5/6] notes --- tests/Feature/Notifications/Webhooks/NotificationTests.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/Notifications/Webhooks/NotificationTests.php b/tests/Feature/Notifications/Webhooks/NotificationTests.php index 09f3e8553c99..4537673f3013 100644 --- a/tests/Feature/Notifications/Webhooks/NotificationTests.php +++ b/tests/Feature/Notifications/Webhooks/NotificationTests.php @@ -40,7 +40,7 @@ public function testAuditNotificationFires() ]; Notification::fake(); - + //tests every webhook option foreach($webhook_options as $option) { $this->settings->{$option}(); From 48270cb9b4af7abf35e207b8c5564db14be87e82 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Fri, 21 Nov 2025 10:11:28 -0800 Subject: [PATCH 6/6] url trim --- tests/Support/Settings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 1c5a68cd6379..4ea8ddb8aaac 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -97,7 +97,7 @@ public function enableMicrosoftTeamsWebhook(): Settings { return $this->update([ 'webhook_selected' => 'microsoft', - 'webhook_endpoint' => 'https://defaultd07ceb04416641fca1b9d3e0ac7600.84.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/1babbc7a3cdd4cf99c0fbed4367cf147/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=sVXmAYF5luz3oOEjvN-G7mJqEEvFjBSETuAG8c3Qmkg', + 'webhook_endpoint' => 'https://defaultd07ceb04416641fca1b9d3e0ac7600.84.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/1babbc7a3cdd4cf99c0fbed4367cf147/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=sVXmAYF5luz3oOEjvN-G7mJqEEvFjBTuAG8c3Qmkg', ]); } @@ -106,7 +106,7 @@ public function enableGoogleChatWebhook(): Settings return $this->update([ 'webhook_selected' => 'google', 'webhook_botname' => 'SnipeBot5000', - 'webhook_endpoint' => 'https://chat.googleapis.com/v1/spaces/AAAATQckuT4/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=bZDaFDK4lO78HhHmC8BEWI6aAKkgqX2gFv2gHVAc8VQ', + 'webhook_endpoint' => 'https://chat.googleapis.com/v1/spaces/AAAATQckuT4/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=bZDaFDK4lO78HhHmC8BEWI6aAKkgqX2gFv2gHVAc8', ]); }