diff options
author | Starfall <us@starfall.systems> | 2022-03-30 12:33:18 -0500 |
---|---|---|
committer | Starfall <us@starfall.systems> | 2022-03-30 12:33:18 -0500 |
commit | f7491de676298b8f78084c00f0026f8cf36d92fc (patch) | |
tree | 0ac29d1598efeb2a0de9bd1b54ae7590e88479da /app/services | |
parent | f37056e6c351a08d09c3986586cc7d27bdea85ab (diff) | |
parent | 363773d0e9ffa9f4efc564603327f225193a2bf1 (diff) |
Update to Mastodon 2.5.0
Merge remote-tracking branch 'glitch/main'
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/activitypub/process_status_update_service.rb | 22 | ||||
-rw-r--r-- | app/services/fetch_link_card_service.rb | 2 | ||||
-rw-r--r-- | app/services/notify_service.rb | 40 | ||||
-rw-r--r-- | app/services/update_status_service.rb | 28 |
4 files changed, 44 insertions, 48 deletions
diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 47a788c30..6dc14d8c2 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -4,6 +4,8 @@ class ActivityPub::ProcessStatusUpdateService < BaseService include JsonLdHelper def call(status, json) + raise ArgumentError, 'Status has unsaved changes' if status.changed? + @json = json @status_parser = ActivityPub::Parser::StatusParser.new(@json) @uri = @status_parser.uri @@ -17,16 +19,19 @@ class ActivityPub::ProcessStatusUpdateService < BaseService last_edit_date = status.edited_at.presence || status.created_at + # Since we rely on tracking of previous changes, ensure clean slate + status.clear_changes_information + # Only allow processing one create/update per status at a time RedisLock.acquire(lock_options) do |lock| if lock.acquired? Status.transaction do - create_previous_edit! + record_previous_edit! update_media_attachments! update_poll! update_immediate_attributes! update_metadata! - create_edit! + create_edits! end queue_poll_notifications! @@ -216,19 +221,14 @@ class ActivityPub::ProcessStatusUpdateService < BaseService { redis: Redis.current, key: "create:#{@uri}", autorelease: 15.minutes.seconds } end - def create_previous_edit! - # We only need to create a previous edit when no previous edits exist, e.g. - # when the status has never been edited. For other cases, we always create - # an edit, so the step can be skipped - - return if @status.edits.any? - - @status.snapshot!(at_time: @status.created_at, rate_limit: false) + def record_previous_edit! + @previous_edit = @status.build_snapshot(at_time: @status.created_at, rate_limit: false) if @status.edits.empty? end - def create_edit! + def create_edits! return unless significant_changes? + @previous_edit&.save! @status.snapshot!(account_id: @account.id, rate_limit: false) end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 239ab9b93..9c8b5ea20 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -134,7 +134,7 @@ class FetchLinkCardService < BaseService when 'video' @card.width = embed[:width].presence || 0 @card.height = embed[:height].presence || 0 - @card.html = Formatter.instance.sanitize(embed[:html], Sanitize::Config::MASTODON_OEMBED) + @card.html = Sanitize.fragment(embed[:html], Sanitize::Config::MASTODON_OEMBED) @card.image_remote_url = (url + embed[:thumbnail_url]).to_s if embed[:thumbnail_url].present? when 'rich' # Most providers rely on <script> tags, which is a no-no diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index b1f9fd755..a90f17cfd 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -48,47 +48,23 @@ class NotifyService < BaseService return false if @notification.target_status.in_reply_to_id.nil? # Using an SQL CTE to avoid unneeded back-and-forth with SQL server in case of long threads - !Status.count_by_sql([<<-SQL.squish, id: @notification.target_status.in_reply_to_id, recipient_id: @recipient.id, sender_id: @notification.from_account.id]).zero? - WITH RECURSIVE ancestors(id, in_reply_to_id, replying_to_sender, path) AS ( - SELECT - s.id, - s.in_reply_to_id, - (CASE - WHEN s.account_id = :recipient_id THEN - EXISTS ( - SELECT * - FROM mentions m - WHERE m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id - ) - ELSE - FALSE - END), - ARRAY[s.id] + !Status.count_by_sql([<<-SQL.squish, id: @notification.target_status.in_reply_to_id, recipient_id: @recipient.id, sender_id: @notification.from_account.id, depth_limit: 100]).zero? + WITH RECURSIVE ancestors(id, in_reply_to_id, mention_id, path, depth) AS ( + SELECT s.id, s.in_reply_to_id, m.id, ARRAY[s.id], 0 FROM statuses s + LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id WHERE s.id = :id UNION ALL - SELECT - s.id, - s.in_reply_to_id, - (CASE - WHEN s.account_id = :recipient_id THEN - EXISTS ( - SELECT * - FROM mentions m - WHERE m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id - ) - ELSE - FALSE - END), - st.path || s.id + SELECT s.id, s.in_reply_to_id, m.id, st.path || s.id, st.depth + 1 FROM ancestors st JOIN statuses s ON s.id = st.in_reply_to_id - WHERE st.replying_to_sender IS FALSE AND NOT s.id = ANY(path) + LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id + WHERE st.mention_id IS NULL AND NOT s.id = ANY(path) AND st.depth < :depth_limit ) SELECT COUNT(*) FROM ancestors st JOIN statuses s ON s.id = st.id - WHERE st.replying_to_sender IS TRUE AND s.visibility = 3 + WHERE st.mention_id IS NOT NULL AND s.visibility = 3 SQL end diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index f5155a2f5..cc4ec670d 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -4,6 +4,8 @@ class UpdateStatusService < BaseService include Redisable include LanguagesHelper + class NoChangesSubmittedError < StandardError; end + # @param [Status] status # @param [Integer] account_id # @param [Hash] options @@ -18,6 +20,8 @@ class UpdateStatusService < BaseService @status = status @options = options @account_id = account_id + @media_attachments_changed = false + @poll_changed = false Status.transaction do create_previous_edit! @@ -33,18 +37,24 @@ class UpdateStatusService < BaseService broadcast_updates! @status + rescue NoChangesSubmittedError + # For calls that result in no changes, swallow the error + # but get back to the original state + + @status.reload end private def update_media_attachments! - previous_media_attachments = @status.media_attachments.to_a + previous_media_attachments = @status.ordered_media_attachments.to_a next_media_attachments = validate_media! 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 = (@options[:media_ids] || []).map(&:to_i) & next_media_attachments.map(&:id) + @media_attachments_changed = previous_media_attachments.map(&:id) != @status.ordered_media_attachment_ids @status.media_attachments.reload end @@ -70,20 +80,23 @@ class UpdateStatusService < BaseService # If for some reasons the options were changed, it invalidates all previous # votes, so we need to remove them - poll_changed = true if @options[:poll][:options] != poll.options || ActiveModel::Type::Boolean.new.cast(@options[:poll][:multiple]) != poll.multiple + @poll_changed = true if @options[:poll][:options] != poll.options || ActiveModel::Type::Boolean.new.cast(@options[:poll][:multiple]) != poll.multiple poll.options = @options[:poll][:options] poll.hide_totals = @options[:poll][:hide_totals] || false poll.multiple = @options[:poll][:multiple] || false poll.expires_in = @options[:poll][:expires_in] - poll.reset_votes! if poll_changed + poll.reset_votes! if @poll_changed poll.save! @status.poll_id = poll.id elsif previous_poll.present? previous_poll.destroy + @poll_changed = true @status.poll_id = nil end + + @poll_changed = true if @previous_expires_at != @status.preloadable_poll&.expires_at end def update_immediate_attributes! @@ -92,8 +105,11 @@ class UpdateStatusService < BaseService @status.sensitive = @options[:sensitive] || @options[:spoiler_text].present? if @options.key?(:sensitive) || @options.key?(:spoiler_text) @status.language = valid_locale_cascade(@options[:language], @status.language, @status.account.user&.preferred_posting_language, I18n.default_locale) @status.content_type = @options[:content_type] || @status.content_type - @status.edited_at = Time.now.utc + # We raise here to rollback the entire transaction + raise NoChangesSubmittedError unless significant_changes? + + @status.edited_at = Time.now.utc @status.save! end @@ -139,4 +155,8 @@ class UpdateStatusService < BaseService def create_edit! @status.snapshot!(account_id: @account_id) end + + def significant_changes? + @status.changed? || @poll_changed || @media_attachments_changed + end end |