]> cat aescling's git repositories - mastodon.git/blob - app/controllers/statuses_controller.rb
Add animate custom emoji param to embed pages (#8507)
[mastodon.git] / app / controllers / statuses_controller.rb
1 # frozen_string_literal: true
2
3 class StatusesController < ApplicationController
4 include SignatureAuthentication
5 include Authorization
6
7 ANCESTORS_LIMIT = 40
8 DESCENDANTS_LIMIT = 60
9 DESCENDANTS_DEPTH_LIMIT = 20
10
11 layout 'public'
12
13 before_action :set_account
14 before_action :set_status
15 before_action :set_instance_presenter
16 before_action :set_link_headers
17 before_action :check_account_suspension
18 before_action :redirect_to_original, only: [:show]
19 before_action :set_referrer_policy_header, only: [:show]
20 before_action :set_cache_headers
21
22 def show
23 respond_to do |format|
24 format.html do
25 @body_classes = 'with-modals'
26
27 set_ancestors
28 set_descendants
29
30 render 'stream_entries/show'
31 end
32
33 format.json do
34 skip_session! unless @stream_entry.hidden?
35
36 render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
37 ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)
38 end
39 end
40 end
41 end
42
43 def activity
44 skip_session!
45
46 render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
47 ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter)
48 end
49 end
50
51 def embed
52 raise ActiveRecord::RecordNotFound if @status.hidden?
53
54 skip_session!
55 expires_in 180, public: true
56 response.headers['X-Frame-Options'] = 'ALLOWALL'
57 @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay])
58
59 render 'stream_entries/embed', layout: 'embedded'
60 end
61
62 private
63
64 def create_descendant_thread(depth, statuses)
65 if depth < DESCENDANTS_DEPTH_LIMIT
66 { statuses: statuses }
67 else
68 next_status = statuses.pop
69 { statuses: statuses, next_status: next_status }
70 end
71 end
72
73 def set_account
74 @account = Account.find_local!(params[:account_username])
75 end
76
77 def set_ancestors
78 @ancestors = @status.reply? ? cache_collection(@status.ancestors(ANCESTORS_LIMIT, current_account), Status) : []
79 @next_ancestor = @ancestors.size < ANCESTORS_LIMIT ? nil : @ancestors.shift
80 end
81
82 def set_descendants
83 @max_descendant_thread_id = params[:max_descendant_thread_id]&.to_i
84 @since_descendant_thread_id = params[:since_descendant_thread_id]&.to_i
85
86 descendants = cache_collection(
87 @status.descendants(
88 DESCENDANTS_LIMIT,
89 current_account,
90 @max_descendant_thread_id,
91 @since_descendant_thread_id,
92 DESCENDANTS_DEPTH_LIMIT
93 ),
94 Status
95 )
96
97 @descendant_threads = []
98
99 if descendants.present?
100 statuses = [descendants.first]
101 depth = 1
102
103 descendants.drop(1).each_with_index do |descendant, index|
104 if descendants[index].id == descendant.in_reply_to_id
105 depth += 1
106 statuses << descendant
107 else
108 @descendant_threads << create_descendant_thread(depth, statuses)
109
110 @descendant_threads.reverse_each do |descendant_thread|
111 statuses = descendant_thread[:statuses]
112
113 index = statuses.find_index do |thread_status|
114 thread_status.id == descendant.in_reply_to_id
115 end
116
117 if index.present?
118 depth += index - statuses.size
119 break
120 end
121
122 depth -= statuses.size
123 end
124
125 statuses = [descendant]
126 end
127 end
128
129 @descendant_threads << create_descendant_thread(depth, statuses)
130 end
131
132 @max_descendant_thread_id = @descendant_threads.pop[:statuses].first.id if descendants.size >= DESCENDANTS_LIMIT
133 end
134
135 def set_link_headers
136 response.headers['Link'] = LinkHeader.new(
137 [
138 [account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],
139 [ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]],
140 ]
141 )
142 end
143
144 def set_status
145 @status = @account.statuses.find(params[:id])
146 @stream_entry = @status.stream_entry
147 @type = @stream_entry.activity_type.downcase
148
149 authorize @status, :show?
150 rescue Mastodon::NotPermittedError
151 # Reraise in order to get a 404
152 raise ActiveRecord::RecordNotFound
153 end
154
155 def set_instance_presenter
156 @instance_presenter = InstancePresenter.new
157 end
158
159 def check_account_suspension
160 gone if @account.suspended?
161 end
162
163 def redirect_to_original
164 redirect_to ::TagManager.instance.url_for(@status.reblog) if @status.reblog?
165 end
166
167 def set_referrer_policy_header
168 return if @status.public_visibility? || @status.unlisted_visibility?
169 response.headers['Referrer-Policy'] = 'origin'
170 end
171 end
This page took 0.106413 seconds and 4 git commands to generate.