diff options
Diffstat (limited to 'app/lib/activitypub/activity')
-rw-r--r-- | app/lib/activitypub/activity/create.rb | 122 | ||||
-rw-r--r-- | app/lib/activitypub/activity/flag.rb | 8 |
2 files changed, 95 insertions, 35 deletions
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 978289788..baa05e14c 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -2,7 +2,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity SUPPORTED_TYPES = %w(Note).freeze - CONVERTED_TYPES = %w(Image Video Article).freeze + CONVERTED_TYPES = %w(Image Video Article Page).freeze def perform return if delete_arrived_first?(object_uri) || unsupported_object_type? || invalid_origin?(@object['id']) @@ -22,12 +22,17 @@ class ActivityPub::Activity::Create < ActivityPub::Activity private def process_status - status_params = process_status_params + @tags = [] + @mentions = [] + @params = {} - ApplicationRecord.transaction do - @status = Status.create!(status_params) + process_status_params + process_tags + process_audience - process_tags(@status) + ApplicationRecord.transaction do + @status = Status.create!(@params) + attach_tags(@status) end resolve_thread(@status) @@ -42,62 +47,109 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end def process_status_params - { - uri: @object['id'], - url: object_url || @object['id'], - account: @account, - text: text_from_content || '', - language: detected_language, - spoiler_text: text_from_summary || '', - created_at: @object['published'], - override_timestamps: @options[:override_timestamps], - reply: @object['inReplyTo'].present?, - sensitive: @object['sensitive'] || false, - visibility: visibility_from_audience, - thread: replied_to_status, - conversation: conversation_from_uri(@object['conversation']), - media_attachment_ids: process_attachments.take(4).map(&:id), - } - end - - def process_tags(status) + @params = begin + { + uri: @object['id'], + url: object_url || @object['id'], + account: @account, + text: text_from_content || '', + language: detected_language, + spoiler_text: text_from_summary || '', + created_at: @object['published'], + override_timestamps: @options[:override_timestamps], + reply: @object['inReplyTo'].present?, + sensitive: @object['sensitive'] || false, + visibility: visibility_from_audience, + thread: replied_to_status, + conversation: conversation_from_uri(@object['conversation']), + media_attachment_ids: process_attachments.take(4).map(&:id), + } + end + end + + def process_audience + (as_array(@object['to']) + as_array(@object['cc'])).uniq.each do |audience| + next if audience == ActivityPub::TagManager::COLLECTIONS[:public] + + # 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 + # control anyway + account = account_from_uri(audience) + + next if account.nil? || @mentions.any? { |mention| mention.account_id == account.id } + + @mentions << Mention.new(account: account, silent: true) + + # If there is at least one silent mention, then the status can be considered + # as a limited-audience status, and not strictly a direct message, but only + # if we considered a direct message in the first place + next unless @params[:visibility] == :direct + + @params[:visibility] = :limited + end + + # If the payload was delivered to a specific inbox, the inbox owner must have + # access to it, unless they already have access to it anyway + return if @options[:delivered_to_account_id].nil? || @mentions.any? { |mention| mention.account_id == @options[:delivered_to_account_id] } + + @mentions << Mention.new(account_id: @options[:delivered_to_account_id], silent: true) + + return unless @params[:visibility] == :direct + + @params[:visibility] = :limited + end + + def attach_tags(status) + @tags.each do |tag| + status.tags << tag + TrendingTags.record_use!(tag, status.account, status.created_at) if status.public_visibility? + end + + @mentions.each do |mention| + mention.status = status + mention.save + end + end + + def process_tags return if @object['tag'].nil? as_array(@object['tag']).each do |tag| if equals_or_includes?(tag['type'], 'Hashtag') - process_hashtag tag, status + process_hashtag tag elsif equals_or_includes?(tag['type'], 'Mention') - process_mention tag, status + process_mention tag elsif equals_or_includes?(tag['type'], 'Emoji') - process_emoji tag, status + process_emoji tag end end end - def process_hashtag(tag, status) + def process_hashtag(tag) return if tag['name'].blank? hashtag = tag['name'].gsub(/\A#/, '').mb_chars.downcase - hashtag = Tag.where(name: hashtag).first_or_create(name: hashtag) + hashtag = Tag.where(name: hashtag).first_or_create!(name: hashtag) - return if status.tags.include?(hashtag) + return if @tags.include?(hashtag) - status.tags << hashtag - TrendingTags.record_use!(hashtag, status.account, status.created_at) if status.public_visibility? + @tags << hashtag rescue ActiveRecord::RecordInvalid nil end - def process_mention(tag, status) + def process_mention(tag) return if tag['href'].blank? account = account_from_uri(tag['href']) account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil? + return if account.nil? - account.mentions.create(status: status) + + @mentions << Mention.new(account: account, silent: false) end - def process_emoji(tag, _status) + def process_emoji(tag) return if skip_download? return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank? diff --git a/app/lib/activitypub/activity/flag.rb b/app/lib/activitypub/activity/flag.rb index 36d3c5730..92e59bb81 100644 --- a/app/lib/activitypub/activity/flag.rb +++ b/app/lib/activitypub/activity/flag.rb @@ -2,6 +2,8 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity def perform + return if skip_reports? + target_accounts = object_uris.map { |uri| account_from_uri(uri) }.compact.select(&:local?) target_statuses_by_account = object_uris.map { |uri| status_from_uri(uri) }.compact.select(&:local?).group_by(&:account_id) @@ -19,6 +21,12 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity end end + private + + def skip_reports? + DomainBlock.find_by(domain: @account.domain)&.reject_reports? + end + def object_uris @object_uris ||= Array(@object.is_a?(Array) ? @object.map { |item| value_or_id(item) } : value_or_id(@object)) end |