Add conversation-based forwarding for limited visibility statuses through bearcaps

This commit is contained in:
Eugen Rochko 2020-08-26 03:16:47 +02:00
parent 52157fdcba
commit 7cd4ed7d42
26 changed files with 430 additions and 78 deletions

View file

@ -90,6 +90,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
fetch_replies(@status)
check_for_spam
distribute(@status)
forward_for_conversation
forward_for_reply
end
@ -114,7 +115,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
sensitive: @object['sensitive'] || false,
visibility: visibility_from_audience,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
conversation: conversation_from_context,
media_attachment_ids: process_attachments.take(4).map(&:id),
poll: process_poll,
}
@ -122,8 +123,10 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end
def process_audience
conversation_uri = value_or_id(@object['context'])
(audience_to + audience_cc).uniq.each do |audience|
next if audience == ActivityPub::TagManager::COLLECTIONS[:public]
next if audience == ActivityPub::TagManager::COLLECTIONS[:public] || audience == conversation_uri
# Unlike with tags, there is no point in resolving accounts we don't already
# know here, because silent mentions would only be used for local access
@ -340,15 +343,45 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
ActivityPub::FetchRepliesWorker.perform_async(status.id, uri) unless uri.nil?
end
def conversation_from_uri(uri)
return nil if uri.nil?
return Conversation.find_by(id: OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Conversation')) if OStatus::TagManager.instance.local_id?(uri)
def conversation_from_context
atom_uri = @object['conversation']
begin
Conversation.find_or_create_by!(uri: uri)
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
retry
conversation = begin
if atom_uri.present? && OStatus::TagManager.instance.local_id?(atom_uri)
Conversation.find_by(id: OStatus::TagManager.instance.unique_tag_to_local_id(atom_uri, 'Conversation'))
elsif atom_uri.present? && @object['context'].present?
Conversation.find_by(uri: atom_uri)
elsif atom_uri.present?
begin
Conversation.find_or_create_by!(uri: atom_uri)
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
retry
end
end
end
return conversation if @object['context'].nil?
uri = value_or_id(@object['context'])
conversation ||= ActivityPub::TagManager.instance.uri_to_resource(uri, Conversation)
return conversation if (conversation.present? && conversation.uri == uri) || !uri.start_with?('https://')
conversation_json = begin
if @object['context'].is_a?(Hash) && !invalid_origin?(uri)
@object['context']
else
fetch_resource(uri, true)
end
end
return conversation if conversation_json.blank?
conversation ||= Conversation.new
conversation.uri = uri
conversation.inbox_url = conversation_json['inbox']
conversation.save! if conversation.changed?
conversation
end
def visibility_from_audience
@ -492,6 +525,12 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
SpamCheck.perform(@status)
end
def forward_for_conversation
return unless audience_to.include?(value_or_id(@object['context'])) && @json['signature'].present? && @status.conversation.local?
ActivityPub::ForwardDistributionWorker.perform_async(@status.conversation_id, Oj.dump(@json))
end
def forward_for_reply
return unless @status.distributable? && @json['signature'].present? && reply_to_local?

View file

@ -21,8 +21,11 @@ class ActivityPub::TagManager
when :person
target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target)
when :note, :comment, :activity
return activity_account_status_url(target.account, target) if target.reblog?
short_account_status_url(target.account, target)
if target.reblog?
activity_account_status_url(target.account, target)
else
short_account_status_url(target.account, target)
end
end
end
@ -33,10 +36,15 @@ class ActivityPub::TagManager
when :person
target.instance_actor? ? instance_actor_url : account_url(target)
when :note, :comment, :activity
return activity_account_status_url(target.account, target) if target.reblog?
account_status_url(target.account, target)
if target.reblog?
activity_account_status_url(target.account, target)
else
account_status_url(target.account, target)
end
when :emoji
emoji_url(target)
when :conversation
context_url(target)
end
end
@ -66,7 +74,9 @@ class ActivityPub::TagManager
[COLLECTIONS[:public]]
when 'unlisted', 'private'
[account_followers_url(status.account)]
when 'direct', 'limited'
when 'limited'
status.conversation_id.present? ? [uri_for(status.conversation)] : []
when 'direct'
if status.account.silenced?
# Only notify followers if the account is locally silenced
account_ids = status.active_mentions.pluck(:account_id)
@ -104,7 +114,7 @@ class ActivityPub::TagManager
cc << COLLECTIONS[:public]
end
unless status.direct_visibility? || status.limited_visibility?
unless status.direct_visibility?
if status.account.silenced?
# Only notify followers if the account is locally silenced
account_ids = status.active_mentions.pluck(:account_id)