2018-02-28 05:54:55 +00:00
# frozen_string_literal: true
class ReportService < BaseService
2019-06-04 21:11:18 +00:00
include Payloadable
2018-02-28 05:54:55 +00:00
def call ( source_account , target_account , options = { } )
@source_account = source_account
@target_account = target_account
2022-03-02 17:57:08 +00:00
@status_ids = options . delete ( :status_ids ) . presence || [ ]
@comment = options . delete ( :comment ) . presence || ''
2022-11-08 16:28:02 +00:00
@category = options [ :rule_ids ] . present? ? 'violation' : ( options . delete ( :category ) . presence || 'other' )
2022-03-02 17:57:08 +00:00
@rule_ids = options . delete ( :rule_ids ) . presence
2018-02-28 05:54:55 +00:00
@options = options
2023-11-30 15:43:26 +00:00
raise ActiveRecord :: RecordNotFound if @target_account . unavailable?
2021-04-16 20:01:05 +00:00
2018-02-28 05:54:55 +00:00
create_report!
notify_staff!
2023-07-10 16:26:56 +00:00
if forward?
forward_to_origin!
forward_to_replied_to!
end
2018-02-28 05:54:55 +00:00
@report
end
private
def create_report!
@report = @source_account . reports . create! (
target_account : @target_account ,
2022-03-02 17:57:08 +00:00
status_ids : reported_status_ids ,
2019-03-17 14:34:56 +00:00
comment : @comment ,
2020-12-15 03:30:15 +00:00
uri : @options [ :uri ] ,
2023-07-10 16:26:56 +00:00
forwarded : forward_to_origin? ,
2022-02-09 23:10:16 +00:00
category : @category ,
rule_ids : @rule_ids
2018-02-28 05:54:55 +00:00
)
end
def notify_staff!
2018-09-01 22:11:58 +00:00
return if @report . unresolved_siblings?
2023-11-06 15:53:29 +00:00
User . those_who_can ( :manage_reports ) . includes ( :account ) . find_each do | u |
2022-06-27 07:30:15 +00:00
LocalNotificationWorker . perform_async ( u . account_id , @report . id , 'Report' , 'admin.report' )
2023-07-08 18:03:38 +00:00
AdminMailer . with ( recipient : u . account ) . new_report ( @report ) . deliver_later if u . allows_report_emails?
2018-02-28 05:54:55 +00:00
end
end
def forward_to_origin!
2023-07-10 16:26:56 +00:00
return unless forward_to_origin?
2023-07-08 18:00:02 +00:00
# Send report to the server where the account originates from
ActivityPub :: DeliveryWorker . perform_async ( payload , some_local_account . id , @target_account . inbox_url )
2023-07-10 16:26:56 +00:00
end
2023-07-08 18:00:02 +00:00
2023-07-10 16:26:56 +00:00
def forward_to_replied_to!
2023-07-08 18:00:02 +00:00
# Send report to servers to which the account was replying to, so they also have a chance to act
2023-10-10 14:00:50 +00:00
inbox_urls = Account . remote . where ( domain : forward_to_domains ) . where ( id : Status . where ( id : reported_status_ids ) . where . not ( in_reply_to_account_id : nil ) . select ( :in_reply_to_account_id ) ) . inboxes - [ @target_account . inbox_url , @target_account . shared_inbox_url ]
2023-07-08 18:00:02 +00:00
inbox_urls . each do | inbox_url |
ActivityPub :: DeliveryWorker . perform_async ( payload , some_local_account . id , inbox_url )
end
2018-02-28 05:54:55 +00:00
end
2022-02-09 23:10:16 +00:00
def forward?
! @target_account . local? && ActiveModel :: Type :: Boolean . new . cast ( @options [ :forward ] )
end
2023-07-10 16:26:56 +00:00
def forward_to_origin?
forward? && forward_to_domains . include? ( @target_account . domain )
end
def forward_to_domains
@forward_to_domains || = ( @options [ :forward_to_domains ] || [ @target_account . domain ] ) . filter_map { | domain | TagManager . instance . normalize_domain ( domain & . strip ) } . uniq
end
2022-03-02 17:57:08 +00:00
def reported_status_ids
2022-07-04 09:08:30 +00:00
return AccountStatusesFilter . new ( @target_account , @source_account ) . results . with_discarded . find ( Array ( @status_ids ) ) . pluck ( :id ) if @source_account . local?
# If the account making reports is remote, it is likely anonymized so we have to relax the requirements for attaching statuses.
domain = @source_account . domain . to_s . downcase
2024-05-28 14:11:31 +00:00
has_followers = @target_account . followers . with_domain ( domain ) . exists?
2022-07-04 09:08:30 +00:00
visibility = has_followers ? % i ( public unlisted private ) : % i ( public unlisted )
scope = @target_account . statuses . with_discarded
scope . merge! ( scope . where ( visibility : visibility ) . or ( scope . where ( 'EXISTS (SELECT 1 FROM mentions m JOIN accounts a ON m.account_id = a.id WHERE lower(a.domain) = ?)' , domain ) ) )
# Allow missing posts to not drop reports that include e.g. a deleted post
scope . where ( id : Array ( @status_ids ) ) . pluck ( :id )
2022-03-02 17:57:08 +00:00
end
2018-02-28 05:54:55 +00:00
def payload
2019-06-04 21:11:18 +00:00
Oj . dump ( serialize_payload ( @report , ActivityPub :: FlagSerializer , account : some_local_account ) )
2018-02-28 05:54:55 +00:00
end
def some_local_account
2019-01-05 06:17:12 +00:00
@some_local_account || = Account . representative
2018-02-28 05:54:55 +00:00
end
end