Give the replies collection an identifier and enable pagination (#10128)
				
					
				
			This commit is contained in:
		
							parent
							
								
									9d3c6f1849
								
							
						
					
					
						commit
						d8498b3983
					
				
					 4 changed files with 67 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -18,6 +18,7 @@ class StatusesController < ApplicationController
 | 
			
		|||
  before_action :redirect_to_original, only: [:show]
 | 
			
		||||
  before_action :set_referrer_policy_header, only: [:show]
 | 
			
		||||
  before_action :set_cache_headers
 | 
			
		||||
  before_action :set_replies, only: [:replies]
 | 
			
		||||
 | 
			
		||||
  content_security_policy only: :embed do |p|
 | 
			
		||||
    p.frame_ancestors(false)
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +64,37 @@ class StatusesController < ApplicationController
 | 
			
		|||
    render 'stream_entries/embed', layout: 'embedded'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def replies
 | 
			
		||||
    skip_session!
 | 
			
		||||
 | 
			
		||||
    render json: replies_collection_presenter,
 | 
			
		||||
           serializer: ActivityPub::CollectionSerializer,
 | 
			
		||||
           adapter: ActivityPub::Adapter,
 | 
			
		||||
           content_type: 'application/activity+json',
 | 
			
		||||
           skip_activities: true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def replies_collection_presenter
 | 
			
		||||
    page = ActivityPub::CollectionPresenter.new(
 | 
			
		||||
      id: replies_account_status_url(@account, @status, page_params),
 | 
			
		||||
      type: :unordered,
 | 
			
		||||
      part_of: replies_account_status_url(@account, @status),
 | 
			
		||||
      next: next_page,
 | 
			
		||||
      items: @replies.map { |status| status.local ? status : status.id }
 | 
			
		||||
    )
 | 
			
		||||
    if page_requested?
 | 
			
		||||
      page
 | 
			
		||||
    else
 | 
			
		||||
      ActivityPub::CollectionPresenter.new(
 | 
			
		||||
        id: replies_account_status_url(@account, @status),
 | 
			
		||||
        type: :unordered,
 | 
			
		||||
        first: page
 | 
			
		||||
      )
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create_descendant_thread(starting_depth, statuses)
 | 
			
		||||
    depth = starting_depth + statuses.size
 | 
			
		||||
    if depth < DESCENDANTS_DEPTH_LIMIT
 | 
			
		||||
| 
						 | 
				
			
			@ -174,4 +204,27 @@ class StatusesController < ApplicationController
 | 
			
		|||
    return if @status.public_visibility? || @status.unlisted_visibility?
 | 
			
		||||
    response.headers['Referrer-Policy'] = 'origin'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def page_requested?
 | 
			
		||||
    params[:page] == 'true'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_replies
 | 
			
		||||
    @replies = page_params[:other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses
 | 
			
		||||
    @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
 | 
			
		||||
    @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def next_page
 | 
			
		||||
    last_reply = @replies.last
 | 
			
		||||
    return if last_reply.nil?
 | 
			
		||||
    same_account = last_reply.account_id == @account.id
 | 
			
		||||
    return unless same_account || @replies.size == DESCENDANTS_LIMIT
 | 
			
		||||
    same_account = false unless @replies.size == DESCENDANTS_LIMIT
 | 
			
		||||
    replies_account_status_url(@account, @status, page: true, min_id: last_reply.id, other_accounts: !same_account)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def page_params
 | 
			
		||||
    { page: true, other_accounts: params[:other_accounts], min_id: params[:min_id] }.compact
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,12 @@ class ActivityPub::TagManager
 | 
			
		|||
    activity_account_status_url(target.account, target)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def replies_uri_for(target, page_params = nil)
 | 
			
		||||
    raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local?
 | 
			
		||||
 | 
			
		||||
    replies_account_status_url(target.account, target, page_params)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Primary audience of a status
 | 
			
		||||
  # Public statuses go out to primarily the public collection
 | 
			
		||||
  # Unlisted and private statuses go out primarily to the followers collection
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class ActivityPub::NoteSerializer < ActiveModel::Serializer
 | 
			
		|||
  has_many :media_attachments, key: :attachment
 | 
			
		||||
  has_many :virtual_tags, key: :tag
 | 
			
		||||
 | 
			
		||||
  has_one :replies, serializer: ActivityPub::CollectionSerializer
 | 
			
		||||
  has_one :replies, serializer: ActivityPub::CollectionSerializer, if: :local?
 | 
			
		||||
 | 
			
		||||
  def id
 | 
			
		||||
    ActivityPub::TagManager.instance.uri_for(object)
 | 
			
		||||
| 
						 | 
				
			
			@ -36,12 +36,16 @@ class ActivityPub::NoteSerializer < ActiveModel::Serializer
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def replies
 | 
			
		||||
    replies = object.self_replies(5).pluck(:id, :uri)
 | 
			
		||||
    last_id = replies.last&.first
 | 
			
		||||
    ActivityPub::CollectionPresenter.new(
 | 
			
		||||
      type: :unordered,
 | 
			
		||||
      id: ActivityPub::TagManager.instance.replies_uri_for(object),
 | 
			
		||||
      first: ActivityPub::CollectionPresenter.new(
 | 
			
		||||
        type: :unordered,
 | 
			
		||||
        page: true,
 | 
			
		||||
        items: object.self_replies(5).pluck(:uri)
 | 
			
		||||
        part_of: ActivityPub::TagManager.instance.replies_uri_for(object),
 | 
			
		||||
        items: replies.map(&:second),
 | 
			
		||||
        next: last_id ? ActivityPub::TagManager.instance.replies_uri_for(object, page: true, min_id: last_id) : nil
 | 
			
		||||
      )
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,6 +56,7 @@ Rails.application.routes.draw do
 | 
			
		|||
      member do
 | 
			
		||||
        get :activity
 | 
			
		||||
        get :embed
 | 
			
		||||
        get :replies
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue