diff --git a/db/migrate/20260121184815_add_session_to_action_push_native_devices.rb b/db/migrate/20260121184815_add_session_to_action_push_native_devices.rb new file mode 100644 index 000000000..e255f2eb3 --- /dev/null +++ b/db/migrate/20260121184815_add_session_to_action_push_native_devices.rb @@ -0,0 +1,5 @@ +class AddSessionToActionPushNativeDevices < ActiveRecord::Migration[8.2] + def change + add_reference :action_push_native_devices, :session, foreign_key: true, type: :uuid + end +end diff --git a/db/schema.rb b/db/schema.rb index 9ff5edb0c..c9da93d98 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -75,10 +75,12 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_18_120000) do t.uuid "owner_id" t.string "owner_type" t.string "platform", null: false + t.uuid "session_id" t.string "token", null: false t.datetime "updated_at", null: false t.index ["owner_type", "owner_id", "token"], name: "idx_on_owner_type_owner_id_token_95a4008c64", unique: true t.index ["owner_type", "owner_id"], name: "index_action_push_native_devices_on_owner" + t.index ["session_id"], name: "index_action_push_native_devices_on_session_id" end create_table "action_text_rich_texts", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| @@ -852,4 +854,6 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_18_120000) do t.index ["account_id"], name: "index_webhooks_on_account_id" t.index ["board_id", "subscribed_actions"], name: "index_webhooks_on_board_id_and_subscribed_actions", length: { subscribed_actions: 255 } end + + add_foreign_key "action_push_native_devices", "sessions" end diff --git a/saas/app/controllers/devices_controller.rb b/saas/app/controllers/devices_controller.rb index 6913da0c5..fc49b14b0 100644 --- a/saas/app/controllers/devices_controller.rb +++ b/saas/app/controllers/devices_controller.rb @@ -6,7 +6,7 @@ class DevicesController < ApplicationController end def create - ApplicationPushDevice.register(owner: Current.identity, **device_params) + ApplicationPushDevice.register(session: Current.session, **device_params) head :created end diff --git a/saas/app/models/application_push_device.rb b/saas/app/models/application_push_device.rb index 6547ec206..7d9aad4e7 100644 --- a/saas/app/models/application_push_device.rb +++ b/saas/app/models/application_push_device.rb @@ -1,7 +1,9 @@ class ApplicationPushDevice < ActionPushNative::Device - def self.register(owner:, token:, platform:, name: nil) - owner.devices.find_or_initialize_by(token: token).tap do |device| - device.update!(platform: platform.downcase, name: name) + belongs_to :session, optional: true + + def self.register(session:, token:, platform:, name: nil) + session.identity.devices.find_or_initialize_by(token: token).tap do |device| + device.update!(session: session, platform: platform.downcase, name: name) end end end diff --git a/saas/app/models/session/devices.rb b/saas/app/models/session/devices.rb new file mode 100644 index 000000000..c159ada72 --- /dev/null +++ b/saas/app/models/session/devices.rb @@ -0,0 +1,7 @@ +module Session::Devices + extend ActiveSupport::Concern + + included do + has_many :devices, class_name: "ApplicationPushDevice", dependent: :destroy + end +end diff --git a/saas/lib/fizzy/saas/engine.rb b/saas/lib/fizzy/saas/engine.rb index a582718b8..40be7fa22 100644 --- a/saas/lib/fizzy/saas/engine.rb +++ b/saas/lib/fizzy/saas/engine.rb @@ -155,6 +155,7 @@ module Fizzy ::Account.include Account::Billing, Account::Limited ::User.include User::NotifiesAccountOfEmailChange ::Identity.include Authorization::Identity, Identity::Devices + ::Session.include Session::Devices ::Signup.prepend Signup ApplicationController.include Authorization::Controller CardsController.include(Card::LimitedCreation) diff --git a/saas/test/models/session/devices_test.rb b/saas/test/models/session/devices_test.rb new file mode 100644 index 000000000..00874895d --- /dev/null +++ b/saas/test/models/session/devices_test.rb @@ -0,0 +1,40 @@ +require "test_helper" + +class Session::DevicesTest < ActiveSupport::TestCase + setup do + @session = sessions(:david) + @identity = @session.identity + end + + test "destroying session destroys associated devices" do + device = ApplicationPushDevice.register( + session: @session, + token: "test_token", + platform: "apple", + name: "Test iPhone" + ) + + assert_difference -> { ApplicationPushDevice.count }, -1 do + @session.destroy + end + + assert_nil ApplicationPushDevice.find_by(id: device.id) + end + + test "destroying session does not destroy devices from other sessions" do + other_session = sessions(:kevin) + + device = ApplicationPushDevice.register( + session: other_session, + token: "other_token", + platform: "apple", + name: "Other iPhone" + ) + + assert_no_difference -> { ApplicationPushDevice.count } do + @session.destroy + end + + assert ApplicationPushDevice.exists?(device.id) + end +end