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)
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
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
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
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)
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