From 4420000148e3e4f2e1b75a5a8335c4dca3071e7d Mon Sep 17 00:00:00 2001 From: Min Zeya Phyo Date: Tue, 28 Jul 2026 02:16:23 +0800 Subject: [PATCH] feat(ntfy): dispatch gateway_online/gateway_offline from model --- app/models/gateway.rb | 21 +++++++++++++++ test/models/gateway_test.rb | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 test/models/gateway_test.rb diff --git a/app/models/gateway.rb b/app/models/gateway.rb index 1e30a62..d20acc4 100644 --- a/app/models/gateway.rb +++ b/app/models/gateway.rb @@ -1,4 +1,6 @@ class Gateway < ApplicationRecord + include NtfyDispatchable + # Normalize metadata to always be a Hash attribute :metadata, :jsonb, default: {} @@ -35,12 +37,31 @@ class Gateway < ApplicationRecord # Update heartbeat timestamp and status def heartbeat! + was_offline = status == "offline" update!(status: "online", last_heartbeat_at: Time.current) + + if was_offline + self.class.dispatch_ntfy("gateway_online", + title: "Gateway online", + message: "#{name} (#{device_id}) came back online", + priority: 3, + tags: ["white_check_mark"], + click: nil) + end end # Mark gateway as offline def mark_offline! + was_online = status == "online" update!(status: "offline") + + if was_online + self.class.dispatch_ntfy("gateway_offline", + title: "Gateway offline", + message: "#{name} (#{device_id}) went offline", + priority: 4, + tags: ["rotating_light"]) + end end # Increment message counters diff --git a/test/models/gateway_test.rb b/test/models/gateway_test.rb new file mode 100644 index 0000000..b74276d --- /dev/null +++ b/test/models/gateway_test.rb @@ -0,0 +1,51 @@ +require "test_helper" + +class GatewayTest < ActiveSupport::TestCase + include ActiveJob::TestHelper + + setup do + ActiveJob::Base.queue_adapter = :test + @admin = AdminUser.create!( + name: "GW Admin", email: "gw@example.com", + password: "password123", + ntfy_topic: "gw-topic", ntfy_token: "tk_gw", + ntfy_enabled: true, ntfy_server_url: "https://ntfy.example.com" + ) + stub_request(:post, "https://ntfy.example.com/gw-topic").to_return(status: 200) + end + + test "heartbeat! dispatches gateway_online notification when transitioning from offline" do + gateway = Gateway.create!( + device_id: "dev-online", name: "GW", + api_key_digest: "x" * 64, status: "offline" + ) + + assert_enqueued_jobs 1 do + gateway.heartbeat! + end + end + + test "heartbeat! does not dispatch if already online" do + gateway = Gateway.create!( + device_id: "dev-stay", name: "GW", + api_key_digest: "y" * 64, status: "online", + last_heartbeat_at: 1.minute.ago + ) + + assert_enqueued_jobs 0 do + gateway.heartbeat! + end + end + + test "mark_offline! dispatches gateway_offline notification when transitioning from online" do + gateway = Gateway.create!( + device_id: "dev-off", name: "GW", + api_key_digest: "z" * 64, status: "online", + last_heartbeat_at: 1.minute.ago + ) + + assert_enqueued_jobs 1 do + gateway.mark_offline! + end + end +end