Fix #329 - avatar errors no longer prevent remote accounts from being saved
(without avatar). Also improved search position of exact matches
This commit is contained in:
		@@ -50,15 +50,14 @@ class Account < ApplicationRecord
 | 
			
		||||
  # PuSH subscriptions
 | 
			
		||||
  has_many :subscriptions, dependent: :destroy
 | 
			
		||||
 | 
			
		||||
  pg_search_scope :search_for, against: { username: 'A', domain: 'B' }, using: { tsearch: { prefix: true } }
 | 
			
		||||
  pg_search_scope :search_for, against: { username: 'A', domain: 'B' },
 | 
			
		||||
                               using: { tsearch: { prefix: true } }
 | 
			
		||||
 | 
			
		||||
  scope :remote, -> { where.not(domain: nil) }
 | 
			
		||||
  scope :local, -> { where(domain: nil) }
 | 
			
		||||
  scope :without_followers, -> { where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) = 0') }
 | 
			
		||||
  scope :with_followers, -> { where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) > 0') }
 | 
			
		||||
  scope :expiring, -> (time) { where(subscription_expires_at: nil).or(where('subscription_expires_at < ?', time)).remote.with_followers }
 | 
			
		||||
 | 
			
		||||
  scope :with_counters, -> { select('accounts.*, (select count(f.id) from follows as f where f.target_account_id = accounts.id) as followers_count, (select count(f.id) from follows as f where f.account_id = accounts.id) as following_count, (select count(s.id) from statuses as s where s.account_id = accounts.id) as statuses_count') }
 | 
			
		||||
  scope :expiring, ->(time) { where(subscription_expires_at: nil).or(where('subscription_expires_at < ?', time)).remote.with_followers }
 | 
			
		||||
 | 
			
		||||
  def follow!(other_account)
 | 
			
		||||
    active_relationships.where(target_account: other_account).first_or_create!(target_account: other_account)
 | 
			
		||||
@@ -114,9 +113,15 @@ class Account < ApplicationRecord
 | 
			
		||||
    OStatus2::Subscription.new(remote_url, secret: secret, lease_seconds: 86_400 * 30, webhook: webhook_url, hub: hub_url)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def ping!(atom_url, hubs)
 | 
			
		||||
    return unless local? && !Rails.env.development?
 | 
			
		||||
    OStatus2::Publication.new(atom_url, hubs).publish
 | 
			
		||||
  def save_with_optional_avatar!
 | 
			
		||||
    save!
 | 
			
		||||
  rescue ActiveRecord::RecordInvalid => invalid
 | 
			
		||||
    if invalid.record.errors[:avatar_file_size] || invalid[:avatar_content_type]
 | 
			
		||||
      self.avatar = nil
 | 
			
		||||
      retry
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    raise invalid
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def avatar_remote_url=(url)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,8 @@ class Status < ApplicationRecord
 | 
			
		||||
 | 
			
		||||
  default_scope { order('id desc') }
 | 
			
		||||
 | 
			
		||||
  scope :with_counters, -> { select('statuses.*, (select count(r.id) from statuses as r where r.reblog_of_id = statuses.id) as reblogs_count, (select count(f.id) from favourites as f where f.status_id = statuses.id) as favourites_count') }
 | 
			
		||||
  scope :remote, -> { where.not(uri: nil) }
 | 
			
		||||
  scope :local, -> { where(uri: nil) }
 | 
			
		||||
 | 
			
		||||
  cache_associated :account, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,16 @@ class SearchService < BaseService
 | 
			
		||||
 | 
			
		||||
    username, domain = query.gsub(/\A@/, '').split('@')
 | 
			
		||||
 | 
			
		||||
    results = if domain.nil?
 | 
			
		||||
                Account.search_for(username)
 | 
			
		||||
              else
 | 
			
		||||
                Account.search_for("#{username} #{domain}")
 | 
			
		||||
              end
 | 
			
		||||
    if domain.nil?
 | 
			
		||||
      exact_match = Account.find_local(username)
 | 
			
		||||
      results     = Account.search_for(username)
 | 
			
		||||
    else
 | 
			
		||||
      exact_match = Account.find_remote(username, domain)
 | 
			
		||||
      results     = Account.search_for("#{username} #{domain}")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    results = results.limit(limit)
 | 
			
		||||
    results = results.limit(limit).to_a
 | 
			
		||||
    results = [exact_match] + results.reject { |a| a.id == exact_match.id } if exact_match
 | 
			
		||||
 | 
			
		||||
    if resolve && results.empty? && !domain.nil?
 | 
			
		||||
      results = [FollowRemoteAccountService.new.call("#{username}@#{domain}")]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								app/services/unsubscribe_service.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/services/unsubscribe_service.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class UnsubscribeService < BaseService
 | 
			
		||||
  def call(account)
 | 
			
		||||
    subscription = account.subscription(api_subscription_url(account.id))
 | 
			
		||||
    response = subscription.unsubscribe
 | 
			
		||||
 | 
			
		||||
    unless response.successful?
 | 
			
		||||
      Rails.logger.debug "PuSH unsubscribe for #{account.acct} failed: #{response.message}"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    account.secret = ''
 | 
			
		||||
    account.subscription_expires_at = nil
 | 
			
		||||
    account.save!
 | 
			
		||||
  rescue HTTP::Error, OpenSSL::SSL::SSLError
 | 
			
		||||
    Rails.logger.debug "PuSH subscription request for #{account.acct} could not be made due to HTTP or SSL error"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -15,7 +15,8 @@ class UpdateRemoteProfileService < BaseService
 | 
			
		||||
 | 
			
		||||
    old_hub_url     = account.hub_url
 | 
			
		||||
    account.hub_url = hub_link['href'] if !hub_link.nil? && !hub_link['href'].blank? && (hub_link['href'] != old_hub_url)
 | 
			
		||||
    account.save!
 | 
			
		||||
 | 
			
		||||
    account.save_with_optional_avatar!
 | 
			
		||||
 | 
			
		||||
    SubscribeService.new.call(account) if resubscribe && (account.hub_url != old_hub_url)
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ class HubPingWorker
 | 
			
		||||
 | 
			
		||||
  def perform(account_id)
 | 
			
		||||
    account = Account.find(account_id)
 | 
			
		||||
    account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url])
 | 
			
		||||
    return unless account.local?
 | 
			
		||||
    OStatus2::Publication.new(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url]).publish
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -11,18 +11,9 @@ namespace :mastodon do
 | 
			
		||||
  namespace :push do
 | 
			
		||||
    desc 'Unsubscribes from PuSH updates of feeds nobody follows locally'
 | 
			
		||||
    task clear: :environment do
 | 
			
		||||
      include RoutingHelper
 | 
			
		||||
 | 
			
		||||
      Account.remote.without_followers.where.not(subscription_expires_at: nil).find_each do |a|
 | 
			
		||||
        Rails.logger.debug "PuSH unsubscribing from #{a.acct}"
 | 
			
		||||
 | 
			
		||||
        begin
 | 
			
		||||
          a.subscription(api_subscription_url(a.id)).unsubscribe
 | 
			
		||||
        rescue HTTP::Error, OpenSSL::SSL::SSLError
 | 
			
		||||
          Rails.logger.debug "PuSH unsubscribing from #{a.acct} failed due to an HTTP or SSL error"
 | 
			
		||||
        ensure
 | 
			
		||||
          a.update!(secret: '', subscription_expires_at: nil)
 | 
			
		||||
        end
 | 
			
		||||
        UnsubscribeService.new.call(a)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user