Add delay to profile updates to debounce them (#34137)
This commit is contained in:
		@@ -14,7 +14,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
 | 
			
		||||
    @account = current_account
 | 
			
		||||
    UpdateAccountService.new.call(@account, account_params, raise_error: true)
 | 
			
		||||
    current_user.update(user_params) if user_params
 | 
			
		||||
    ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
    ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
    render json: @account, serializer: REST::CredentialAccountSerializer
 | 
			
		||||
  rescue ActiveRecord::RecordInvalid => e
 | 
			
		||||
    render json: ValidationErrorFormatter.new(e).as_json, status: 422
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ class Api::V1::Profile::AvatarsController < Api::BaseController
 | 
			
		||||
  def destroy
 | 
			
		||||
    @account = current_account
 | 
			
		||||
    UpdateAccountService.new.call(@account, { avatar: nil }, raise_error: true)
 | 
			
		||||
    ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
    ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
    render json: @account, serializer: REST::CredentialAccountSerializer
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ class Api::V1::Profile::HeadersController < Api::BaseController
 | 
			
		||||
  def destroy
 | 
			
		||||
    @account = current_account
 | 
			
		||||
    UpdateAccountService.new.call(@account, { header: nil }, raise_error: true)
 | 
			
		||||
    ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
    ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
    render json: @account, serializer: REST::CredentialAccountSerializer
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ module Settings
 | 
			
		||||
    def destroy
 | 
			
		||||
      if valid_picture?
 | 
			
		||||
        if UpdateAccountService.new.call(@account, { @picture => nil, "#{@picture}_remote_url" => '' })
 | 
			
		||||
          ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
          ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
          redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg'), status: 303
 | 
			
		||||
        else
 | 
			
		||||
          redirect_to settings_profile_path
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ class Settings::PrivacyController < Settings::BaseController
 | 
			
		||||
  def update
 | 
			
		||||
    if UpdateAccountService.new.call(@account, account_params.except(:settings))
 | 
			
		||||
      current_user.update!(settings_attributes: account_params[:settings])
 | 
			
		||||
      ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
      ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
      redirect_to settings_privacy_path, notice: I18n.t('generic.changes_saved_msg')
 | 
			
		||||
    else
 | 
			
		||||
      render :show
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ class Settings::ProfilesController < Settings::BaseController
 | 
			
		||||
 | 
			
		||||
  def update
 | 
			
		||||
    if UpdateAccountService.new.call(@account, account_params)
 | 
			
		||||
      ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
      ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
      redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg')
 | 
			
		||||
    else
 | 
			
		||||
      @account.build_fields
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ class Settings::VerificationsController < Settings::BaseController
 | 
			
		||||
 | 
			
		||||
  def update
 | 
			
		||||
    if UpdateAccountService.new.call(@account, account_params)
 | 
			
		||||
      ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
 | 
			
		||||
      ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
 | 
			
		||||
      redirect_to settings_verification_path, notice: I18n.t('generic.changes_saved_msg')
 | 
			
		||||
    else
 | 
			
		||||
      render :show
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class ActivityPub::UpdateDistributionWorker < ActivityPub::RawDistributionWorker
 | 
			
		||||
  DEBOUNCE_DELAY = 5.seconds
 | 
			
		||||
 | 
			
		||||
  sidekiq_options queue: 'push', lock: :until_executed, lock_ttl: 1.day.to_i
 | 
			
		||||
 | 
			
		||||
  # Distribute an profile update to servers that might have a copy
 | 
			
		||||
 
 | 
			
		||||
@@ -53,8 +53,6 @@ RSpec.describe 'credentials API' do
 | 
			
		||||
      patch '/api/v1/accounts/update_credentials', headers: headers, params: params
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    before { allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) }
 | 
			
		||||
 | 
			
		||||
    let(:params) do
 | 
			
		||||
      {
 | 
			
		||||
        avatar: fixture_file_upload('avatar.gif', 'image/gif'),
 | 
			
		||||
@@ -113,7 +111,7 @@ RSpec.describe 'credentials API' do
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      expect(ActivityPub::UpdateDistributionWorker)
 | 
			
		||||
        .to have_received(:perform_async).with(user.account_id)
 | 
			
		||||
        .to have_enqueued_sidekiq_job(user.account_id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def expect_account_updates
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,6 @@ RSpec.describe 'Deleting profile images' do
 | 
			
		||||
  let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
 | 
			
		||||
 | 
			
		||||
  describe 'DELETE /api/v1/profile' do
 | 
			
		||||
    before do
 | 
			
		||||
      allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when deleting an avatar' do
 | 
			
		||||
      context 'with wrong scope' do
 | 
			
		||||
        before do
 | 
			
		||||
@@ -38,7 +34,8 @@ RSpec.describe 'Deleting profile images' do
 | 
			
		||||
        account.reload
 | 
			
		||||
        expect(account.avatar).to_not exist
 | 
			
		||||
        expect(account.header).to exist
 | 
			
		||||
        expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
 | 
			
		||||
        expect(ActivityPub::UpdateDistributionWorker)
 | 
			
		||||
          .to have_enqueued_sidekiq_job(account.id)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +58,8 @@ RSpec.describe 'Deleting profile images' do
 | 
			
		||||
        account.reload
 | 
			
		||||
        expect(account.avatar).to exist
 | 
			
		||||
        expect(account.header).to_not exist
 | 
			
		||||
        expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id)
 | 
			
		||||
        expect(ActivityPub::UpdateDistributionWorker)
 | 
			
		||||
          .to have_enqueued_sidekiq_job(account.id)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,6 @@ RSpec.describe 'Settings Privacy' do
 | 
			
		||||
    before { user.account.update(discoverable: false) }
 | 
			
		||||
 | 
			
		||||
    context 'with a successful update' do
 | 
			
		||||
      before { allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) }
 | 
			
		||||
 | 
			
		||||
      it 'updates user profile information' do
 | 
			
		||||
        # View settings page
 | 
			
		||||
        visit settings_privacy_path
 | 
			
		||||
@@ -29,14 +27,13 @@ RSpec.describe 'Settings Privacy' do
 | 
			
		||||
          .to have_content(I18n.t('privacy.title'))
 | 
			
		||||
          .and have_content(success_message)
 | 
			
		||||
        expect(ActivityPub::UpdateDistributionWorker)
 | 
			
		||||
          .to have_received(:perform_async).with(user.account.id)
 | 
			
		||||
          .to have_enqueued_sidekiq_job(user.account.id)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'with a failed update' do
 | 
			
		||||
      before do
 | 
			
		||||
        allow(UpdateAccountService).to receive(:new).and_return(failing_update_service)
 | 
			
		||||
        allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'updates user profile information' do
 | 
			
		||||
@@ -54,7 +51,7 @@ RSpec.describe 'Settings Privacy' do
 | 
			
		||||
        expect(page)
 | 
			
		||||
          .to have_content(I18n.t('privacy.title'))
 | 
			
		||||
        expect(ActivityPub::UpdateDistributionWorker)
 | 
			
		||||
          .to_not have_received(:perform_async)
 | 
			
		||||
          .to_not have_enqueued_sidekiq_job(anything)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ RSpec.describe 'Settings profile page' do
 | 
			
		||||
  let(:account) { user.account }
 | 
			
		||||
 | 
			
		||||
  before do
 | 
			
		||||
    allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
 | 
			
		||||
    sign_in user
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@@ -24,7 +23,7 @@ RSpec.describe 'Settings profile page' do
 | 
			
		||||
      .to change { account.reload.display_name }.to('New name')
 | 
			
		||||
      .and(change { account.reload.avatar.instance.avatar_file_name }.from(nil).to(be_present))
 | 
			
		||||
    expect(ActivityPub::UpdateDistributionWorker)
 | 
			
		||||
      .to have_received(:perform_async).with(account.id)
 | 
			
		||||
      .to have_enqueued_sidekiq_job(account.id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def display_name_field
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user