push_subscription.rb 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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
  20. validates :endpoint, presence: true
  21. validates :key_p256dh, presence: true
  22. validates :key_auth, presence: true
  23. def push(notification)
  24. I18n.with_locale(associated_user&.locale || I18n.default_locale) do
  25. push_payload(payload_for_notification(notification), 48.hours.seconds)
  26. end
  27. end
  28. def pushable?(notification)
  29. data&.key?('alerts') && ActiveModel::Type::Boolean.new.cast(data['alerts'][notification.type.to_s])
  30. end
  31. def associated_user
  32. return @associated_user if defined?(@associated_user)
  33. @associated_user = if user_id.nil?
  34. session_activation.user
  35. else
  36. user
  37. end
  38. end
  39. def associated_access_token
  40. return @associated_access_token if defined?(@associated_access_token)
  41. @associated_access_token = if access_token_id.nil?
  42. find_or_create_access_token.token
  43. else
  44. access_token.token
  45. end
  46. end
  47. class << self
  48. def unsubscribe_for(application_id, resource_owner)
  49. access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id, revoked_at: nil)
  50. .pluck(:id)
  51. where(access_token_id: access_token_ids).delete_all
  52. end
  53. end
  54. private
  55. def push_payload(message, ttl = 5.minutes.seconds)
  56. Webpush.payload_send(
  57. message: Oj.dump(message),
  58. endpoint: endpoint,
  59. p256dh: key_p256dh,
  60. auth: key_auth,
  61. ttl: ttl,
  62. ssl_timeout: 10,
  63. open_timeout: 10,
  64. read_timeout: 10,
  65. vapid: {
  66. subject: "mailto:#{::Setting.site_contact_email}",
  67. private_key: Rails.configuration.x.vapid_private_key,
  68. public_key: Rails.configuration.x.vapid_public_key,
  69. }
  70. )
  71. end
  72. def payload_for_notification(notification)
  73. ActiveModelSerializers::SerializableResource.new(
  74. notification,
  75. serializer: Web::NotificationSerializer,
  76. scope: self,
  77. scope_name: :current_push_subscription
  78. ).as_json
  79. end
  80. def find_or_create_access_token
  81. Doorkeeper::AccessToken.find_or_create_for(
  82. application: Doorkeeper::Application.find_by(superapp: true),
  83. resource_owner: session_activation.user_id,
  84. scopes: Doorkeeper::OAuth::Scopes.from_string('read write follow push'),
  85. expires_in: Doorkeeper.configuration.access_token_expires_in,
  86. use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
  87. )
  88. end
  89. end