about summary refs log tree commit diff
path: root/app/services/post_status_service.rb
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2023-02-13 19:35:35 +0100
committerClaire <claire.github-309c@sitedethib.com>2023-02-13 19:35:35 +0100
commitce84d163ccaa1f38f9fe5dc829a5da80495632c2 (patch)
tree1242ecad08be2afc048d652dedf07115adbd115b /app/services/post_status_service.rb
parentee4250545236e4330c46b43f4abfe94ad323d4d4 (diff)
parentd6930b3847405dc9f8c1a54fb74d488a3c9a775e (diff)
Merge branch 'main' into glitch-soc/merge-upstream
Conflicts:
- `.prettierignore`:
  Upstream added a line at the end, glitch-soc had extra entries at the end.
  Added upstream's new line before glitch-soc's.
- `Gemfile.lock`:
  Upstream updated dependencies while glitch-soc has an extra one (hcaptcha).
  Updated dependencies like upstream did.
- `app/controllers/api/v1/statuses_controller.rb`:
  Not a real conflict, upstream added a parameter (`allowed_mentions`) where
  glitch-soc already had an extra one (`content_type`).
  Added upstream's new parameter.
- `app/javascript/styles/fonts/roboto-mono.scss`:
  A lot of lines were changed upstream due to code style changes, and a lot
  of those lines had path changes to accomodate glitch-soc's theming system.
  Applied upstream's style changes.
- `app/javascript/styles/fonts/roboto.scss`:
  A lot of lines were changed upstream due to code style changes, and a lot
  of those lines had path changes to accomodate glitch-soc's theming system.
  Applied upstream's style changes.
Diffstat (limited to 'app/services/post_status_service.rb')
-rw-r--r--app/services/post_status_service.rb28
1 files changed, 25 insertions, 3 deletions
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index bcda001f5..77527f2db 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -6,6 +6,15 @@ class PostStatusService < BaseService
 
   MIN_SCHEDULE_OFFSET = 5.minutes.freeze
 
+  class UnexpectedMentionsError < StandardError
+    attr_reader :accounts
+
+    def initialize(message, accounts)
+      super(message)
+      @accounts = accounts
+    end
+  end
+
   # Post a text status update, fetch and notify remote users mentioned
   # @param [Account] account Account from which to post
   # @param [Hash] options
@@ -21,6 +30,7 @@ class PostStatusService < BaseService
   # @option [Doorkeeper::Application] :application
   # @option [String] :idempotency Optional idempotency key
   # @option [Boolean] :with_rate_limit
+  # @option [Enumerable] :allowed_mentions Optional array of expected mentioned account IDs, raises `UnexpectedMentionsError` if unexpected accounts end up in mentions
   # @return [Status]
   def call(account, options = {})
     @account     = account
@@ -72,14 +82,27 @@ class PostStatusService < BaseService
   end
 
   def process_status!
+    @status = @account.statuses.new(status_attributes)
+    process_mentions_service.call(@status, save_records: false)
+    safeguard_mentions!(@status)
+
     # The following transaction block is needed to wrap the UPDATEs to
     # the media attachments when the status is created
-
     ApplicationRecord.transaction do
-      @status = @account.statuses.create!(status_attributes)
+      @status.save!
     end
   end
 
+  def safeguard_mentions!(status)
+    return if @options[:allowed_mentions].nil?
+    expected_account_ids = @options[:allowed_mentions].map(&:to_i)
+
+    unexpected_accounts = status.mentions.map(&:account).to_a.reject { |mentioned_account| expected_account_ids.include?(mentioned_account.id) }
+    return if unexpected_accounts.empty?
+
+    raise UnexpectedMentionsError.new('Post would be sent to unexpected accounts', unexpected_accounts)
+  end
+
   def schedule_status!
     status_for_validation = @account.statuses.build(status_attributes)
 
@@ -102,7 +125,6 @@ class PostStatusService < BaseService
 
   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)