diff options
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/activitypub/process_status_update_service.rb | 42 | ||||
-rw-r--r-- | app/services/batched_remove_status_service.rb | 2 | ||||
-rw-r--r-- | app/services/fetch_oembed_service.rb | 4 | ||||
-rw-r--r-- | app/services/post_status_service.rb | 12 | ||||
-rw-r--r-- | app/services/suspend_account_service.rb | 14 | ||||
-rw-r--r-- | app/services/tag_search_service.rb | 18 | ||||
-rw-r--r-- | app/services/unsuspend_account_service.rb | 13 | ||||
-rw-r--r-- | app/services/verify_link_service.rb | 2 |
8 files changed, 69 insertions, 38 deletions
diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index fad19f87f..11b38ab92 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -45,6 +45,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService create_edits! end + download_media_files! queue_poll_notifications! next unless significant_changes? @@ -66,12 +67,12 @@ class ActivityPub::ProcessStatusUpdateService < BaseService def update_media_attachments! previous_media_attachments = @status.media_attachments.to_a previous_media_attachments_ids = @status.ordered_media_attachment_ids || previous_media_attachments.map(&:id) - next_media_attachments = [] + @next_media_attachments = [] as_array(@json['attachment']).each do |attachment| media_attachment_parser = ActivityPub::Parser::MediaAttachmentParser.new(attachment) - next if media_attachment_parser.remote_url.blank? || next_media_attachments.size > 4 + next if media_attachment_parser.remote_url.blank? || @next_media_attachments.size > 4 begin media_attachment = previous_media_attachments.find { |previous_media_attachment| previous_media_attachment.remote_url == media_attachment_parser.remote_url } @@ -87,34 +88,39 @@ class ActivityPub::ProcessStatusUpdateService < BaseService media_attachment.focus = media_attachment_parser.focus media_attachment.thumbnail_remote_url = media_attachment_parser.thumbnail_remote_url media_attachment.blurhash = media_attachment_parser.blurhash + media_attachment.status_id = @status.id + media_attachment.skip_download = unsupported_media_type?(media_attachment_parser.file_content_type) || skip_download? media_attachment.save! - next_media_attachments << media_attachment - - next if unsupported_media_type?(media_attachment_parser.file_content_type) || skip_download? - - begin - media_attachment.download_file! if media_attachment.remote_url_previously_changed? - media_attachment.download_thumbnail! if media_attachment.thumbnail_remote_url_previously_changed? - media_attachment.save - rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError - RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id) - end + @next_media_attachments << media_attachment rescue Addressable::URI::InvalidURIError => e Rails.logger.debug "Invalid URL in attachment: #{e}" end end - added_media_attachments = next_media_attachments - previous_media_attachments + added_media_attachments = @next_media_attachments - previous_media_attachments - MediaAttachment.where(id: added_media_attachments.map(&:id)).update_all(status_id: @status.id) - - @status.ordered_media_attachment_ids = next_media_attachments.map(&:id) - @status.media_attachments.reload + @status.ordered_media_attachment_ids = @next_media_attachments.map(&:id) @media_attachments_changed = true if @status.ordered_media_attachment_ids != previous_media_attachments_ids end + def download_media_files! + @next_media_attachments.each do |media_attachment| + next if media_attachment.skip_download + + media_attachment.download_file! if media_attachment.remote_url_previously_changed? + media_attachment.download_thumbnail! if media_attachment.thumbnail_remote_url_previously_changed? + media_attachment.save + rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id) + rescue Seahorse::Client::NetworkingError => e + Rails.logger.warn "Error storing media attachment: #{e}" + end + + @status.media_attachments.reload + end + def update_poll!(allow_significant_changes: true) previous_poll = @status.preloadable_poll @previous_expires_at = previous_poll&.expires_at diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb index 2b649ee22..e2c370057 100644 --- a/app/services/batched_remove_status_service.rb +++ b/app/services/batched_remove_status_service.rb @@ -20,7 +20,7 @@ class BatchedRemoveStatusService < BaseService ActiveRecord::Associations::Preloader.new.preload(statuses_with_account_conversations, [mentions: :account]) statuses_with_account_conversations.each do |status| - status.send(:unlink_from_conversations) + status.unlink_from_conversations! unpush_from_direct_timelines(status) end diff --git a/app/services/fetch_oembed_service.rb b/app/services/fetch_oembed_service.rb index 4cbaa04c6..7d0879c79 100644 --- a/app/services/fetch_oembed_service.rb +++ b/app/services/fetch_oembed_service.rb @@ -28,7 +28,7 @@ class FetchOEmbedService page = Nokogiri::HTML(html) if @format.nil? || @format == :json - @endpoint_url ||= page.at_xpath('//link[@type="application/json+oembed"]')&.attribute('href')&.value + @endpoint_url ||= page.at_xpath('//link[@type="application/json+oembed"]|//link[@type="text/json+oembed"]')&.attribute('href')&.value @format ||= :json if @endpoint_url end @@ -100,7 +100,7 @@ class FetchOEmbedService end def validate(oembed) - oembed if oembed[:version] == '1.0' && oembed[:type].present? + oembed if oembed[:version].to_s == '1.0' && oembed[:type].present? end def html diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 36592a531..bcda001f5 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -37,12 +37,15 @@ class PostStatusService < BaseService schedule_status! else process_status! - postprocess_status! - bump_potential_friendship! end redis.setex(idempotency_key, 3_600, @status.id) if idempotency_given? + unless scheduled? + postprocess_status! + bump_potential_friendship! + end + @status end @@ -75,9 +78,6 @@ class PostStatusService < BaseService ApplicationRecord.transaction do @status = @account.statuses.create!(status_attributes) end - - process_hashtags_service.call(@status) - process_mentions_service.call(@status) end def schedule_status! @@ -101,6 +101,8 @@ class PostStatusService < BaseService end def postprocess_status! + process_hashtags_service.call(@status) + process_mentions_service.call(@status) Trends.tags.register(@status) LinkCrawlWorker.perform_async(@status.id) DistributionWorker.perform_async(@status.id) diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index b8dc8d5e0..211544fea 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -3,10 +3,13 @@ class SuspendAccountService < BaseService include Payloadable + # Carry out the suspension of a recently-suspended account + # @param [Account] account Account to suspend def call(account) + return unless account.suspended? + @account = account - suspend! reject_remote_follows! distribute_update_actor! unmerge_from_home_timelines! @@ -16,10 +19,6 @@ class SuspendAccountService < BaseService private - def suspend! - @account.suspend! unless @account.suspended? - end - def reject_remote_follows! return if @account.local? || !@account.activitypub? @@ -76,10 +75,15 @@ class SuspendAccountService < BaseService styles.each do |style| case Paperclip::Attachment.default_options[:storage] when :s3 + # Prevent useless S3 calls if ACLs are disabled + next if ENV['S3_PERMISSION'] == '' + begin attachment.s3_object(style).acl.put(acl: 'private') rescue Aws::S3::Errors::NoSuchKey Rails.logger.warn "Tried to change acl on non-existent key #{attachment.s3_object(style).key}" + rescue Aws::S3::Errors::NotImplemented => e + Rails.logger.error "Error trying to change ACL on #{attachment.s3_object(style).key}: #{e.message}" end when :fog # Not supported diff --git a/app/services/tag_search_service.rb b/app/services/tag_search_service.rb index b78d65625..b66ccced9 100644 --- a/app/services/tag_search_service.rb +++ b/app/services/tag_search_service.rb @@ -76,11 +76,27 @@ class TagSearchService < BaseService definition = TagsIndex.query(query) definition = definition.filter(filter) if @options[:exclude_unreviewed] - definition.limit(@limit).offset(@offset).objects.compact + ensure_exact_match(definition.limit(@limit).offset(@offset).objects.compact) rescue Faraday::ConnectionFailed, Parslet::ParseFailed nil end + # Since the ElasticSearch Query doesn't guarantee the exact match will be the + # first result or that it will even be returned, patch the results accordingly + def ensure_exact_match(results) + return results unless @offset.nil? || @offset.zero? + + normalized_query = Tag.normalize(@query) + exact_match = results.find { |tag| tag.name.downcase == normalized_query } + exact_match ||= Tag.find_normalized(normalized_query) + unless exact_match.nil? + results.delete(exact_match) + results = [exact_match] + results + end + + results + end + def from_database Tag.search_for(@query, @limit, @offset, @options) end diff --git a/app/services/unsuspend_account_service.rb b/app/services/unsuspend_account_service.rb index 39d8a6ba7..70667308e 100644 --- a/app/services/unsuspend_account_service.rb +++ b/app/services/unsuspend_account_service.rb @@ -2,10 +2,12 @@ class UnsuspendAccountService < BaseService include Payloadable + + # Restores a recently-unsuspended account + # @param [Account] account Account to restore def call(account) @account = account - unsuspend! refresh_remote_account! return if @account.nil? || @account.suspended? @@ -18,10 +20,6 @@ class UnsuspendAccountService < BaseService private - def unsuspend! - @account.unsuspend! if @account.suspended? - end - def refresh_remote_account! return if @account.local? @@ -73,10 +71,15 @@ class UnsuspendAccountService < BaseService styles.each do |style| case Paperclip::Attachment.default_options[:storage] when :s3 + # Prevent useless S3 calls if ACLs are disabled + next if ENV['S3_PERMISSION'] == '' + begin attachment.s3_object(style).acl.put(acl: Paperclip::Attachment.default_options[:s3_permissions]) rescue Aws::S3::Errors::NoSuchKey Rails.logger.warn "Tried to change acl on non-existent key #{attachment.s3_object(style).key}" + rescue Aws::S3::Errors::NotImplemented => e + Rails.logger.error "Error trying to change ACL on #{attachment.s3_object(style).key}: #{e.message}" end when :fog # Not supported diff --git a/app/services/verify_link_service.rb b/app/services/verify_link_service.rb index 7496fe2d5..d049b52d1 100644 --- a/app/services/verify_link_service.rb +++ b/app/services/verify_link_service.rb @@ -26,7 +26,7 @@ class VerifyLinkService < BaseService def link_back_present? return false if @body.blank? - links = Nokogiri::HTML(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]') + links = Nokogiri::HTML5(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]') if links.any? { |link| link['href']&.downcase == @link_back.downcase } true |