Merge tag 'v2.6.5' into instance_only_statuses
This commit is contained in:
@ -5,9 +5,10 @@ class ActivityPub::FetchRemoteAccountService < BaseService
|
||||
|
||||
SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
|
||||
|
||||
# Should be called when uri has already been checked for locality
|
||||
# Does a WebFinger roundtrip on each call
|
||||
def call(uri, id: true, prefetched_body: nil, break_on_redirect: false)
|
||||
return ActivityPub::TagManager.instance.uri_to_resource(uri, Account) if ActivityPub::TagManager.instance.local_uri?(uri)
|
||||
|
||||
@json = if prefetched_body.nil?
|
||||
fetch_resource(uri, id)
|
||||
else
|
||||
|
||||
@ -232,7 +232,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||
updated = tag['updated']
|
||||
emoji = CustomEmoji.find_by(shortcode: shortcode, domain: @account.domain)
|
||||
|
||||
return unless emoji.nil? || image_url != emoji.image_remote_url || (updated && emoji.updated_at >= updated)
|
||||
return unless emoji.nil? || image_url != emoji.image_remote_url || (updated && updated >= emoji.updated_at)
|
||||
|
||||
emoji ||= CustomEmoji.new(domain: @account.domain, shortcode: shortcode, uri: uri)
|
||||
emoji.image_remote_url = image_url
|
||||
|
||||
@ -12,12 +12,12 @@ class BatchedRemoveStatusService < BaseService
|
||||
def call(statuses)
|
||||
statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a }
|
||||
|
||||
@mentions = statuses.map { |s| [s.id, s.active_mentions.includes(:account).to_a] }.to_h
|
||||
@tags = statuses.map { |s| [s.id, s.tags.pluck(:name)] }.to_h
|
||||
@mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a }
|
||||
@tags = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) }
|
||||
|
||||
@stream_entry_batches = []
|
||||
@salmon_batches = []
|
||||
@json_payloads = statuses.map { |s| [s.id, Oj.dump(event: :delete, payload: s.id.to_s)] }.to_h
|
||||
@json_payloads = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) }
|
||||
@activity_xml = {}
|
||||
|
||||
# Ensure that rendered XML reflects destroyed state
|
||||
|
||||
@ -18,6 +18,6 @@ module AuthorExtractor
|
||||
acct = "#{username}@#{domain}"
|
||||
end
|
||||
|
||||
ResolveAccountService.new.call(acct, update_profile)
|
||||
ResolveAccountService.new.call(acct, update_profile: update_profile)
|
||||
end
|
||||
end
|
||||
|
||||
@ -58,10 +58,8 @@ class FanOutOnWriteService < BaseService
|
||||
def deliver_to_mentioned_followers(status)
|
||||
Rails.logger.debug "Delivering status #{status.id} to limited followers"
|
||||
|
||||
status.mentions.includes(:account).each do |mention|
|
||||
mentioned_account = mention.account
|
||||
next if !mentioned_account.local? || !mentioned_account.following?(status.account) || FeedManager.instance.filter?(:home, status, mention.account_id)
|
||||
FeedManager.instance.push_to_home(mentioned_account, status)
|
||||
FeedInsertWorker.push_bulk(status.mentions.includes(:account).map(&:account).select { |mentioned_account| mentioned_account.local? && mentioned_account.following?(status.account) }) do |follower|
|
||||
[status.id, follower.id, :home]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ class FetchAtomService < BaseService
|
||||
|
||||
def perform_request(&block)
|
||||
accept = 'text/html'
|
||||
accept = 'application/activity+json, application/ld+json, application/atom+xml, ' + accept unless @unsupported_activity
|
||||
accept = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/atom+xml, ' + accept unless @unsupported_activity
|
||||
|
||||
Request.new(:get, @url).add_headers('Accept' => accept).perform(&block)
|
||||
end
|
||||
@ -39,7 +39,7 @@ class FetchAtomService < BaseService
|
||||
|
||||
if response.mime_type == 'application/atom+xml'
|
||||
[@url, { prefetched_body: response.body_with_limit }, :ostatus]
|
||||
elsif ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(response.mime_type)
|
||||
elsif ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
|
||||
body = response.body_with_limit
|
||||
json = body_to_json(body)
|
||||
if supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && json['inbox'].present?
|
||||
|
||||
@ -62,6 +62,7 @@ class FetchLinkCardService < BaseService
|
||||
|
||||
def attach_card
|
||||
@status.preview_cards << @card
|
||||
Rails.cache.delete(@status)
|
||||
end
|
||||
|
||||
def parse_urls
|
||||
@ -81,9 +82,15 @@ class FetchLinkCardService < BaseService
|
||||
uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme)
|
||||
end
|
||||
|
||||
def mention_link?(a)
|
||||
@status.mentions.any? do |mention|
|
||||
a['href'] == TagManager.instance.url_for(mention.account)
|
||||
end
|
||||
end
|
||||
|
||||
def skip_link?(a)
|
||||
# Avoid links for hashtags and mentions (microformats)
|
||||
a['rel']&.include?('tag') || a['class']&.include?('u-url')
|
||||
a['rel']&.include?('tag') || a['class']&.include?('u-url') || mention_link?(a)
|
||||
end
|
||||
|
||||
def attempt_oembed
|
||||
@ -129,14 +136,15 @@ class FetchLinkCardService < BaseService
|
||||
detector = CharlockHolmes::EncodingDetector.new
|
||||
detector.strip_tags = true
|
||||
|
||||
guess = detector.detect(@html, @html_charset)
|
||||
page = Nokogiri::HTML(@html, nil, guess&.fetch(:encoding, nil))
|
||||
guess = detector.detect(@html, @html_charset)
|
||||
page = Nokogiri::HTML(@html, nil, guess&.fetch(:encoding, nil))
|
||||
player_url = meta_property(page, 'twitter:player')
|
||||
|
||||
if meta_property(page, 'twitter:player')
|
||||
if player_url && !bad_url?(Addressable::URI.parse(player_url))
|
||||
@card.type = :video
|
||||
@card.width = meta_property(page, 'twitter:player:width') || 0
|
||||
@card.height = meta_property(page, 'twitter:player:height') || 0
|
||||
@card.html = content_tag(:iframe, nil, src: meta_property(page, 'twitter:player'),
|
||||
@card.html = content_tag(:iframe, nil, src: player_url,
|
||||
width: @card.width,
|
||||
height: @card.height,
|
||||
allowtransparency: 'true',
|
||||
|
||||
@ -7,9 +7,9 @@ class FollowService < BaseService
|
||||
# @param [Account] source_account From which to follow
|
||||
# @param [String, Account] uri User URI to follow in the form of username@domain (or account record)
|
||||
# @param [true, false, nil] reblogs Whether or not to show reblogs, defaults to true
|
||||
def call(source_account, uri, reblogs: nil)
|
||||
def call(source_account, target_account, reblogs: nil)
|
||||
reblogs = true if reblogs.nil?
|
||||
target_account = uri.is_a?(Account) ? uri : ResolveAccountService.new.call(uri)
|
||||
target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true)
|
||||
|
||||
raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
|
||||
raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account)
|
||||
@ -42,7 +42,7 @@ class FollowService < BaseService
|
||||
follow_request = FollowRequest.create!(account: source_account, target_account: target_account, show_reblogs: reblogs)
|
||||
|
||||
if target_account.local?
|
||||
NotifyService.new.call(target_account, follow_request)
|
||||
LocalNotificationWorker.perform_async(target_account.id, follow_request.id, follow_request.class.name)
|
||||
elsif target_account.ostatus?
|
||||
NotificationWorker.perform_async(build_follow_request_xml(follow_request), source_account.id, target_account.id)
|
||||
AfterRemoteFollowRequestWorker.perform_async(follow_request.id)
|
||||
@ -57,7 +57,7 @@ class FollowService < BaseService
|
||||
follow = source_account.follow!(target_account, reblogs: reblogs)
|
||||
|
||||
if target_account.local?
|
||||
NotifyService.new.call(target_account, follow)
|
||||
LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)
|
||||
else
|
||||
Pubsubhubbub::SubscribeWorker.perform_async(target_account.id) unless target_account.subscribed?
|
||||
NotificationWorker.perform_async(build_follow_xml(follow), source_account.id, target_account.id)
|
||||
|
||||
@ -31,7 +31,7 @@ class NotifyService < BaseService
|
||||
end
|
||||
|
||||
def blocked_reblog?
|
||||
@recipient.muting_reblogs?(@notification.from_account)
|
||||
false
|
||||
end
|
||||
|
||||
def blocked_follow_request?
|
||||
@ -51,8 +51,12 @@ class NotifyService < BaseService
|
||||
@recipient.user.settings.interactions['must_be_following'] && !following_sender?
|
||||
end
|
||||
|
||||
def message?
|
||||
@notification.type == :mention
|
||||
end
|
||||
|
||||
def direct_message?
|
||||
@notification.type == :mention && @notification.target_status.direct_visibility?
|
||||
message? && @notification.target_status.direct_visibility?
|
||||
end
|
||||
|
||||
def response_to_recipient?
|
||||
@ -66,7 +70,6 @@ class NotifyService < BaseService
|
||||
def optional_non_following_and_direct?
|
||||
direct_message? &&
|
||||
@recipient.user.settings.interactions['must_be_following_dm'] &&
|
||||
!from_staff? &&
|
||||
!following_sender? &&
|
||||
!response_to_recipient?
|
||||
end
|
||||
@ -86,6 +89,9 @@ class NotifyService < BaseService
|
||||
def blocked?
|
||||
blocked = @recipient.suspended? # Skip if the recipient account is suspended anyway
|
||||
blocked ||= from_self? # Skip for interactions with self
|
||||
|
||||
return blocked if message? && from_staff?
|
||||
|
||||
blocked ||= domain_blocking? # Skip for domain blocked accounts
|
||||
blocked ||= @recipient.blocking?(@notification.from_account) # Skip for blocked accounts
|
||||
blocked ||= @recipient.muting_notifications?(@notification.from_account)
|
||||
|
||||
@ -47,7 +47,7 @@ class ProcessMentionsService < BaseService
|
||||
mentioned_account = mention.account
|
||||
|
||||
if mentioned_account.local?
|
||||
LocalNotificationWorker.perform_async(mention.id)
|
||||
LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name)
|
||||
elsif mentioned_account.ostatus? && !@status.stream_entry.hidden?
|
||||
NotificationWorker.perform_async(ostatus_xml, @status.account_id, mentioned_account.id)
|
||||
elsif mentioned_account.activitypub?
|
||||
|
||||
@ -9,17 +9,27 @@ class ResolveAccountService < BaseService
|
||||
# Find or create a local account for a remote user.
|
||||
# When creating, look up the user's webfinger and fetch all
|
||||
# important information from their feed
|
||||
# @param [String] uri User URI in the form of username@domain
|
||||
# @param [String, Account] uri User URI in the form of username@domain
|
||||
# @param [Hash] options
|
||||
# @return [Account]
|
||||
def call(uri, update_profile = true, redirected = nil)
|
||||
@username, @domain = uri.split('@')
|
||||
@update_profile = update_profile
|
||||
def call(uri, options = {})
|
||||
@options = options
|
||||
|
||||
return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)
|
||||
if uri.is_a?(Account)
|
||||
@account = uri
|
||||
@username = @account.username
|
||||
@domain = @account.domain
|
||||
|
||||
@account = Account.find_remote(@username, @domain)
|
||||
return @account if @account.local? || !webfinger_update_due?
|
||||
else
|
||||
@username, @domain = uri.split('@')
|
||||
|
||||
return @account unless webfinger_update_due?
|
||||
return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)
|
||||
|
||||
@account = Account.find_remote(@username, @domain)
|
||||
|
||||
return @account unless webfinger_update_due?
|
||||
end
|
||||
|
||||
Rails.logger.debug "Looking up webfinger for #{uri}"
|
||||
|
||||
@ -30,8 +40,8 @@ class ResolveAccountService < BaseService
|
||||
if confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero?
|
||||
@username = confirmed_username
|
||||
@domain = confirmed_domain
|
||||
elsif redirected.nil?
|
||||
return call("#{confirmed_username}@#{confirmed_domain}", update_profile, true)
|
||||
elsif options[:redirected].nil?
|
||||
return call("#{confirmed_username}@#{confirmed_domain}", options.merge(redirected: true))
|
||||
else
|
||||
Rails.logger.debug 'Requested and returned acct URIs do not match'
|
||||
return
|
||||
@ -76,7 +86,7 @@ class ResolveAccountService < BaseService
|
||||
end
|
||||
|
||||
def webfinger_update_due?
|
||||
@account.nil? || @account.possibly_stale?
|
||||
@account.nil? || ((!@options[:skip_webfinger] || @account.ostatus?) && @account.possibly_stale?)
|
||||
end
|
||||
|
||||
def activitypub_ready?
|
||||
@ -93,7 +103,7 @@ class ResolveAccountService < BaseService
|
||||
end
|
||||
|
||||
def update_profile?
|
||||
@update_profile
|
||||
@options[:update_profile]
|
||||
end
|
||||
|
||||
def handle_activitypub
|
||||
|
||||
@ -20,7 +20,7 @@ class ResolveURLService < BaseService
|
||||
def process_url
|
||||
if equals_or_includes_any?(type, %w(Application Group Organization Person Service))
|
||||
FetchRemoteAccountService.new.call(atom_url, body, protocol)
|
||||
elsif equals_or_includes_any?(type, %w(Note Article Image Video))
|
||||
elsif equals_or_includes_any?(type, %w(Note Article Image Video Page))
|
||||
FetchRemoteStatusService.new.call(atom_url, body, protocol)
|
||||
end
|
||||
end
|
||||
|
||||
@ -25,7 +25,7 @@ class VerifyLinkService < BaseService
|
||||
end
|
||||
|
||||
def link_back_present?
|
||||
return false if @body.empty?
|
||||
return false if @body.blank?
|
||||
|
||||
links = Nokogiri::HTML(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user