replies_controller.rb 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # frozen_string_literal: true
  2. class ActivityPub::RepliesController < ActivityPub::BaseController
  3. include SignatureVerification
  4. include Authorization
  5. include AccountOwnedConcern
  6. DESCENDANTS_LIMIT = 60
  7. before_action :require_account_signature!, if: :authorized_fetch_mode?
  8. before_action :set_status
  9. before_action :set_cache_headers
  10. before_action :set_replies
  11. def index
  12. expires_in 0, public: public_fetch_mode?
  13. render json: replies_collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json', skip_activities: true
  14. end
  15. private
  16. def pundit_user
  17. signed_request_account
  18. end
  19. def set_status
  20. @status = @account.statuses.find(params[:status_id])
  21. authorize @status, :show?
  22. rescue Mastodon::NotPermittedError
  23. not_found
  24. end
  25. def set_replies
  26. @replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses
  27. @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
  28. @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
  29. end
  30. def replies_collection_presenter
  31. page = ActivityPub::CollectionPresenter.new(
  32. id: account_status_replies_url(@account, @status, page_params),
  33. type: :unordered,
  34. part_of: account_status_replies_url(@account, @status),
  35. next: next_page,
  36. items: @replies.map { |status| status.local? ? status : status.uri }
  37. )
  38. return page if page_requested?
  39. ActivityPub::CollectionPresenter.new(
  40. id: account_status_replies_url(@account, @status),
  41. type: :unordered,
  42. first: page
  43. )
  44. end
  45. def page_requested?
  46. truthy_param?(:page)
  47. end
  48. def only_other_accounts?
  49. truthy_param?(:only_other_accounts)
  50. end
  51. def next_page
  52. if only_other_accounts?
  53. # Only consider remote accounts
  54. return nil if @replies.size < DESCENDANTS_LIMIT
  55. account_status_replies_url(
  56. @account,
  57. @status,
  58. page: true,
  59. min_id: @replies&.last&.id,
  60. only_other_accounts: true
  61. )
  62. else
  63. # For now, we're serving only self-replies, but next page might be other accounts
  64. next_only_other_accounts = @replies&.last&.account_id != @account.id || @replies.size < DESCENDANTS_LIMIT
  65. account_status_replies_url(
  66. @account,
  67. @status,
  68. page: true,
  69. min_id: next_only_other_accounts ? nil : @replies&.last&.id,
  70. only_other_accounts: next_only_other_accounts
  71. )
  72. end
  73. end
  74. def page_params
  75. params_slice(:only_other_accounts, :min_id).merge(page: true)
  76. end
  77. end