push_subscription.rb 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. # frozen_string_literal: true
  2. # == Schema Information
  3. #
  4. # Table name: web_push_subscriptions
  5. #
  6. # id :bigint(8) not null, primary key
  7. # endpoint :string not null
  8. # key_p256dh :string not null
  9. # key_auth :string not null
  10. # data :json
  11. # created_at :datetime not null
  12. # updated_at :datetime not null
  13. # access_token_id :bigint(8)
  14. # user_id :bigint(8)
  15. #
  16. class Web::PushSubscription < ApplicationRecord
  17. belongs_to :user, optional: true
  18. belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', optional: true
  19. has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription, dependent: nil
  20. validates :endpoint, presence: true, url: true
  21. validates :key_p256dh, presence: true
  22. validates :key_auth, presence: true
  23. validates_with WebPushKeyValidator
  24. delegate :locale, to: :associated_user
  25. generates_token_for :unsubscribe, expires_in: Web::PushNotificationWorker::TTL
  26. def pushable?(notification)
  27. policy_allows_notification?(notification) && alert_enabled_for_notification_type?(notification)
  28. end
  29. def associated_user
  30. return @associated_user if defined?(@associated_user)
  31. @associated_user = if user_id.nil?
  32. session_activation.user
  33. else
  34. user
  35. end
  36. end
  37. def associated_access_token
  38. return @associated_access_token if defined?(@associated_access_token)
  39. @associated_access_token = if access_token_id.nil?
  40. find_or_create_access_token.token
  41. else
  42. access_token.token
  43. end
  44. end
  45. class << self
  46. def unsubscribe_for(application_id, resource_owner)
  47. access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id).not_revoked.pluck(:id)
  48. where(access_token_id: access_token_ids).delete_all
  49. end
  50. end
  51. private
  52. def find_or_create_access_token
  53. Doorkeeper::AccessToken.find_or_create_for(
  54. application: Doorkeeper::Application.find_by(superapp: true),
  55. resource_owner: user_id || session_activation.user_id,
  56. scopes: Doorkeeper::OAuth::Scopes.from_string('read write follow push'),
  57. expires_in: Doorkeeper.configuration.access_token_expires_in,
  58. use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
  59. )
  60. end
  61. def alert_enabled_for_notification_type?(notification)
  62. truthy?(data&.dig('alerts', notification.type.to_s))
  63. end
  64. def policy_allows_notification?(notification)
  65. case data&.dig('policy')
  66. when nil, 'all'
  67. true
  68. when 'none'
  69. false
  70. when 'followed'
  71. notification.account.following?(notification.from_account)
  72. when 'follower'
  73. notification.from_account.following?(notification.account)
  74. end
  75. end
  76. def truthy?(val)
  77. ActiveModel::Type::Boolean.new.cast(val)
  78. end
  79. end