Add endpoint to remove web push subscription (#32626)
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
 | 
			
		||||
  before_action :require_user!
 | 
			
		||||
  before_action :require_user!, except: :destroy
 | 
			
		||||
  before_action :set_push_subscription, only: :update
 | 
			
		||||
  before_action :destroy_previous_subscriptions, only: :create, if: :prior_subscriptions?
 | 
			
		||||
  after_action :update_session_with_subscription, only: :create
 | 
			
		||||
@@ -17,6 +17,13 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
 | 
			
		||||
    render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy
 | 
			
		||||
    push_subscription = ::Web::PushSubscription.find_by_token_for(:unsubscribe, params[:id])
 | 
			
		||||
    push_subscription&.destroy
 | 
			
		||||
 | 
			
		||||
    head 200
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def active_session
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@ class Web::PushSubscription < ApplicationRecord
 | 
			
		||||
 | 
			
		||||
  delegate :locale, to: :associated_user
 | 
			
		||||
 | 
			
		||||
  generates_token_for :unsubscribe, expires_in: Web::PushNotificationWorker::TTL
 | 
			
		||||
 | 
			
		||||
  def pushable?(notification)
 | 
			
		||||
    policy_allows_notification?(notification) && alert_enabled_for_notification_type?(notification)
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,11 @@
 | 
			
		||||
 | 
			
		||||
class Web::PushNotificationWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
  include RoutingHelper
 | 
			
		||||
 | 
			
		||||
  sidekiq_options queue: 'push', retry: 5
 | 
			
		||||
 | 
			
		||||
  TTL     = 48.hours.to_s
 | 
			
		||||
  TTL     = 48.hours
 | 
			
		||||
  URGENCY = 'normal'
 | 
			
		||||
 | 
			
		||||
  def perform(subscription_id, notification_id)
 | 
			
		||||
@@ -23,12 +24,13 @@ class Web::PushNotificationWorker
 | 
			
		||||
 | 
			
		||||
      request.add_headers(
 | 
			
		||||
        'Content-Type' => 'application/octet-stream',
 | 
			
		||||
        'Ttl' => TTL,
 | 
			
		||||
        'Ttl' => TTL.to_s,
 | 
			
		||||
        'Urgency' => URGENCY,
 | 
			
		||||
        'Content-Encoding' => 'aesgcm',
 | 
			
		||||
        'Encryption' => "salt=#{Webpush.encode64(payload.fetch(:salt)).delete('=')}",
 | 
			
		||||
        'Crypto-Key' => "dh=#{Webpush.encode64(payload.fetch(:server_public_key)).delete('=')};#{web_push_request.crypto_key_header}",
 | 
			
		||||
        'Authorization' => web_push_request.authorization_header
 | 
			
		||||
        'Authorization' => web_push_request.authorization_header,
 | 
			
		||||
        'Unsubscribe-URL' => subscription_url
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      request.perform do |response|
 | 
			
		||||
@@ -72,4 +74,8 @@ class Web::PushNotificationWorker
 | 
			
		||||
  def request_pool
 | 
			
		||||
    RequestPool.current
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def subscription_url
 | 
			
		||||
    api_web_push_subscription_url(id: @subscription.generate_token_for(:unsubscribe))
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -346,7 +346,7 @@ namespace :api, format: false do
 | 
			
		||||
  namespace :web do
 | 
			
		||||
    resource :settings, only: [:update]
 | 
			
		||||
    resources :embeds, only: [:show]
 | 
			
		||||
    resources :push_subscriptions, only: [:create] do
 | 
			
		||||
    resources :push_subscriptions, only: [:create, :destroy] do
 | 
			
		||||
      member do
 | 
			
		||||
        put :update
 | 
			
		||||
      end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								spec/requests/api/web/push_subscriptions_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								spec/requests/api/web/push_subscriptions_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe 'API Web Push Subscriptions' do
 | 
			
		||||
  describe 'DELETE /api/web/push_subscriptions/:id' do
 | 
			
		||||
    subject { delete api_web_push_subscription_path(token) }
 | 
			
		||||
 | 
			
		||||
    context 'when the subscription exists' do
 | 
			
		||||
      let!(:web_push_subscription) do
 | 
			
		||||
        Fabricate(:web_push_subscription)
 | 
			
		||||
      end
 | 
			
		||||
      let(:token) do
 | 
			
		||||
        web_push_subscription.generate_token_for(:unsubscribe)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'deletes the subscription' do
 | 
			
		||||
        expect { subject }
 | 
			
		||||
          .to change(Web::PushSubscription, :count).by(-1)
 | 
			
		||||
 | 
			
		||||
        expect(response).to have_http_status(200)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when the subscription does not exist' do
 | 
			
		||||
      let(:web_push_subscription) do
 | 
			
		||||
        Fabricate(:web_push_subscription)
 | 
			
		||||
      end
 | 
			
		||||
      let(:token) do
 | 
			
		||||
        web_push_subscription.generate_token_for(:unsubscribe)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      before do
 | 
			
		||||
        token # memoize before destroying the record
 | 
			
		||||
        web_push_subscription.destroy!
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'does nothing' do
 | 
			
		||||
        subject
 | 
			
		||||
 | 
			
		||||
        expect(response).to have_http_status(200)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when the token is invalid' do
 | 
			
		||||
      let(:token) { 'invalid--invalid' }
 | 
			
		||||
 | 
			
		||||
      it 'does nothing' do
 | 
			
		||||
        subject
 | 
			
		||||
 | 
			
		||||
        expect(response).to have_http_status(200)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -61,6 +61,7 @@ RSpec.describe Web::PushNotificationWorker do
 | 
			
		||||
          'Ttl' => '172800',
 | 
			
		||||
          'Urgency' => 'normal',
 | 
			
		||||
          'Authorization' => 'WebPush jwt.encoded.payload',
 | 
			
		||||
          'Unsubscribe-URL' => %r{/api/web/push_subscriptions/},
 | 
			
		||||
        },
 | 
			
		||||
        body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr"
 | 
			
		||||
      )
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user