summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2019-07-08 12:03:45 +0200
committerGitHub <noreply@github.com>2019-07-08 12:03:45 +0200
commit63c7fe8e4892b22e80c015bf0ecb04496318623b (patch)
treec724cb6e1006dbd1d5cccd3719d096ff62124644
parentf14776475d285bb7d2831a20192c1611c733f410 (diff)
Refactor controllers for statuses, accounts, and more (#11249)
-rw-r--r--app/controllers/about_controller.rb16
-rw-r--r--app/controllers/accounts_controller.rb15
-rw-r--r--app/controllers/activitypub/collections_controller.rb16
-rw-r--r--app/controllers/activitypub/inboxes_controller.rb7
-rw-r--r--app/controllers/activitypub/outboxes_controller.rb6
-rw-r--r--app/controllers/activitypub/replies_controller.rb68
-rw-r--r--app/controllers/api/proofs_controller.rb17
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/concerns/account_controller_concern.rb34
-rw-r--r--app/controllers/concerns/account_owned_concern.rb33
-rw-r--r--app/controllers/concerns/status_controller_concern.rb87
-rw-r--r--app/controllers/custom_css_controller.rb1
-rw-r--r--app/controllers/emojis_controller.rb5
-rw-r--r--app/controllers/follower_accounts_controller.rb2
-rw-r--r--app/controllers/following_accounts_controller.rb2
-rw-r--r--app/controllers/home_controller.rb2
-rw-r--r--app/controllers/intents_controller.rb1
-rw-r--r--app/controllers/manifests_controller.rb1
-rw-r--r--app/controllers/media_controller.rb1
-rw-r--r--app/controllers/public_timelines_controller.rb14
-rw-r--r--app/controllers/remote_follow_controller.rb12
-rw-r--r--app/controllers/statuses_controller.rb164
-rw-r--r--app/controllers/tags_controller.rb18
-rw-r--r--app/controllers/well_known/host_meta_controller.rb2
-rw-r--r--app/controllers/well_known/webfinger_controller.rb9
-rw-r--r--app/lib/activitypub/activity/announce.rb2
-rw-r--r--app/lib/activitypub/activity/create.rb2
-rw-r--r--app/lib/activitypub/activity/delete.rb2
-rw-r--r--app/lib/activitypub/tag_manager.rb2
-rw-r--r--app/models/status.rb9
-rw-r--r--app/serializers/activitypub/activity_serializer.rb3
-rw-r--r--app/serializers/activitypub/actor_serializer.rb2
-rw-r--r--app/serializers/activitypub/collection_serializer.rb2
-rw-r--r--app/serializers/activitypub/emoji_serializer.rb2
-rw-r--r--app/serializers/activitypub/note_serializer.rb2
-rw-r--r--app/services/process_hashtags_service.rb2
-rw-r--r--app/views/statuses/_simple_status.html.haml4
-rw-r--r--config/routes.rb3
-rw-r--r--spec/controllers/concerns/account_controller_concern_spec.rb2
-rw-r--r--spec/controllers/statuses_controller_spec.rb4
-rw-r--r--spec/requests/link_headers_spec.rb8
41 files changed, 299 insertions, 289 deletions
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index 52a51fd62ec..761c7f5cdf1 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -3,11 +3,11 @@
class AboutController < ApplicationController
layout 'public'
- before_action :set_instance_presenter, only: [:show, :more, :terms]
+ before_action :set_body_classes, only: :show
+ before_action :set_instance_presenter
+ before_action :set_expires_in
- def show
- @hide_navbar = true
- end
+ def show; end
def more; end
@@ -27,4 +27,12 @@ class AboutController < ApplicationController
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
+
+ def set_body_classes
+ @hide_navbar = true
+ end
+
+ def set_expires_in
+ expires_in 0, public: true
+ end
end
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 0657073780e..3184a73cb1d 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -6,13 +6,13 @@ class AccountsController < ApplicationController
include AccountControllerConcern
before_action :set_cache_headers
+ before_action :set_body_classes
def show
respond_to do |format|
format.html do
- mark_cacheable! unless user_signed_in?
+ expires_in 0, public: true unless user_signed_in?
- @body_classes = 'with-modals'
@pinned_statuses = []
@endorsed_accounts = @account.endorsed_accounts.to_a.sample(4)
@@ -32,22 +32,25 @@ class AccountsController < ApplicationController
end
format.rss do
- mark_cacheable!
+ expires_in 0, public: true
@statuses = cache_collection(default_statuses.without_reblogs.without_replies.limit(PAGE_SIZE), Status)
render xml: RSS::AccountSerializer.render(@account, @statuses)
end
format.json do
- render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do
- ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)
- end
+ expires_in 3.minutes, public: true
+ render json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter
end
end
end
private
+ def set_body_classes
+ @body_classes = 'with-modals'
+ end
+
def show_pinned_statuses?
[replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none?
end
diff --git a/app/controllers/activitypub/collections_controller.rb b/app/controllers/activitypub/collections_controller.rb
index 012c3c53885..dd2f111b03d 100644
--- a/app/controllers/activitypub/collections_controller.rb
+++ b/app/controllers/activitypub/collections_controller.rb
@@ -2,29 +2,19 @@
class ActivityPub::CollectionsController < Api::BaseController
include SignatureVerification
+ include AccountOwnedConcern
- before_action :set_account
before_action :set_size
before_action :set_statuses
before_action :set_cache_headers
def show
- render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do
- ActiveModelSerializers::SerializableResource.new(
- collection_presenter,
- serializer: ActivityPub::CollectionSerializer,
- adapter: ActivityPub::Adapter,
- skip_activities: true
- )
- end
+ expires_in 3.minutes, public: true
+ render json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, skip_activities: true
end
private
- def set_account
- @account = Account.find_local!(params[:account_username])
- end
-
def set_statuses
@statuses = scope_for_collection
@statuses = cache_collection(@statuses, Status)
diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb
index e2cd8eaedb2..9be0676e14a 100644
--- a/app/controllers/activitypub/inboxes_controller.rb
+++ b/app/controllers/activitypub/inboxes_controller.rb
@@ -3,8 +3,7 @@
class ActivityPub::InboxesController < Api::BaseController
include SignatureVerification
include JsonLdHelper
-
- before_action :set_account
+ include AccountOwnedConcern
def create
if unknown_deleted_account?
@@ -27,8 +26,8 @@ class ActivityPub::InboxesController < Api::BaseController
false
end
- def set_account
- @account = Account.find_local!(params[:account_username]) if params[:account_username]
+ def account_required?
+ params[:account_username].present?
end
def body
diff --git a/app/controllers/activitypub/outboxes_controller.rb b/app/controllers/activitypub/outboxes_controller.rb
index 5147afbf782..4c0b769f0f2 100644
--- a/app/controllers/activitypub/outboxes_controller.rb
+++ b/app/controllers/activitypub/outboxes_controller.rb
@@ -4,8 +4,8 @@ class ActivityPub::OutboxesController < Api::BaseController
LIMIT = 20
include SignatureVerification
+ include AccountOwnedConcern
- before_action :set_account
before_action :set_statuses
before_action :set_cache_headers
@@ -17,10 +17,6 @@ class ActivityPub::OutboxesController < Api::BaseController
private
- def set_account
- @account = Account.find_local!(params[:account_username])
- end
-
def outbox_presenter
if page_requested?
ActivityPub::CollectionPresenter.new(
diff --git a/app/controllers/activitypub/replies_controller.rb b/app/controllers/activitypub/replies_controller.rb
new file mode 100644
index 00000000000..99b7b310f48
--- /dev/null
+++ b/app/controllers/activitypub/replies_controller.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+class ActivityPub::RepliesController < Api::BaseController
+ include SignatureAuthentication
+ include Authorization
+ include AccountOwnedConcern
+
+ DESCENDANTS_LIMIT = 60
+
+ before_action :set_status
+ before_action :set_cache_headers
+ before_action :set_replies
+
+ def index
+ render json: replies_collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json', skip_activities: true
+ end
+
+ private
+
+ def set_status
+ @status = @account.statuses.find(params[:status_id])
+ authorize @status, :show?
+ rescue Mastodon::NotPermittedError
+ raise ActiveRecord::RecordNotFound
+ 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 replies_collection_presenter
+ page = ActivityPub::CollectionPresenter.new(
+ id: account_status_replies_url(@account, @status, page_params),
+ type: :unordered,
+ part_of: account_status_replies_url(@account, @status),
+ next: next_page,
+ items: @replies.map { |status| status.local ? status : status.id }
+ )
+
+ return page if page_requested?
+
+ ActivityPub::CollectionPresenter.new(
+ id: account_status_replies_url(@account, @status),
+ type: :unordered,
+ first: page
+ )
+ end
+
+ def page_requested?
+ params[:page] == 'true'
+ end
+
+ def next_page
+ account_status_replies_url(
+ @account,
+ @status,
+ page: true,
+ min_id: @replies&.last&.id,
+ other_accounts: !(@replies&.last&.account_id == @account.id && @replies.size == DESCENDANTS_LIMIT)
+ )
+ end
+
+ def page_params
+ params_slice(:other_accounts, :min_id).merge(page: true)
+ end
+end
diff --git a/app/controllers/api/proofs_controller.rb b/app/controllers/api/proofs_controller.rb
index a84ad2014fe..a98599eee66 100644
--- a/app/controllers/api/proofs_controller.rb
+++ b/app/controllers/api/proofs_controller.rb
@@ -1,10 +1,9 @@
# frozen_string_literal: true
class Api::ProofsController < Api::BaseController
- before_action :set_account
+ include AccountOwnedConcern
+
before_action :set_provider
- before_action :check_account_approval
- before_action :check_account_suspension
def index
render json: @account, serializer: @provider.serializer_class
@@ -16,15 +15,7 @@ class Api::ProofsController < Api::BaseController
@provider = ProofProvider.find(params[:provider]) || raise(ActiveRecord::RecordNotFound)
end
- def set_account
- @account = Account.find_local!(params[:username])
- end
-
- def check_account_approval
- not_found if @account.user_pending?
- end
-
- def check_account_suspension
- gone if @account.suspended?
+ def username_param
+ params[:username]
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index bd8000db0fd..cc8b8e4da65 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -154,8 +154,4 @@ class ApplicationController < ActionController::Base
def set_cache_headers
response.headers['Vary'] = 'Accept'
end
-
- def mark_cacheable!
- expires_in 0, public: true
- end
end
diff --git a/app/controllers/concerns/account_controller_concern.rb b/app/controllers/concerns/account_controller_concern.rb
index 1c422096c63..287a930da41 100644
--- a/app/controllers/concerns/account_controller_concern.rb
+++ b/app/controllers/concerns/account_controller_concern.rb
@@ -3,24 +3,19 @@
module AccountControllerConcern
extend ActiveSupport::Concern
+ include AccountOwnedConcern
+
FOLLOW_PER_PAGE = 12
included do
layout 'public'
- before_action :set_account
- before_action :check_account_approval
- before_action :check_account_suspension
before_action :set_instance_presenter
before_action :set_link_headers
end
private
- def set_account
- @account = Account.find_local!(username_param)
- end
-
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
@@ -29,27 +24,15 @@ module AccountControllerConcern
response.headers['Link'] = LinkHeader.new(
[
webfinger_account_link,
- atom_account_url_link,
actor_url_link,
]
)
end
- def username_param
- params[:account_username]
- end
-
def webfinger_account_link
[
webfinger_account_url,
- [%w(rel lrdd), %w(type application/xrd+xml)],
- ]
- end
-
- def atom_account_url_link
- [
- account_url(@account, format: 'atom'),
- [%w(rel alternate), %w(type application/atom+xml)],
+ [%w(rel lrdd), %w(type application/jrd+json)],
]
end
@@ -63,15 +46,4 @@ module AccountControllerConcern
def webfinger_account_url
webfinger_url(resource: @account.to_webfinger_s)
end
-
- def check_account_approval
- not_found if @account.user_pending?
- end
-
- def check_account_suspension
- if @account.suspended?
- expires_in(3.minutes, public: true)
- gone
- end
- end
end
diff --git a/app/controllers/concerns/account_owned_concern.rb b/app/controllers/concerns/account_owned_concern.rb
new file mode 100644
index 00000000000..99c240fe986
--- /dev/null
+++ b/app/controllers/concerns/account_owned_concern.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module AccountOwnedConcern
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :set_account, if: :account_required?
+ before_action :check_account_approval, if: :account_required?
+ before_action :check_account_suspension, if: :account_required?
+ end
+
+ private
+
+ def account_required?
+ true
+ end
+
+ def set_account
+ @account = Account.find_local!(username_param)
+ end
+
+ def username_param
+ params[:account_username]
+ end
+
+ def check_account_approval
+ not_found if @account.local? && @account.user_pending?
+ end
+
+ def check_account_suspension
+ expires_in(3.minutes, public: true) && gone if @account.suspended?
+ end
+end
diff --git a/app/controllers/concerns/status_controller_concern.rb b/app/controllers/concerns/status_controller_concern.rb
new file mode 100644
index 00000000000..62a7cf5086a
--- /dev/null
+++ b/app/controllers/concerns/status_controller_concern.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+module StatusControllerConcern
+ extend ActiveSupport::Concern
+
+ ANCESTORS_LIMIT = 40
+ DESCENDANTS_LIMIT = 60
+ DESCENDANTS_DEPTH_LIMIT = 20
+
+ def create_descendant_thread(starting_depth, statuses)
+ depth = starting_depth + statuses.size
+
+ if depth < DESCENDANTS_DEPTH_LIMIT
+ {
+ statuses: statuses,
+ starting_depth: starting_depth,
+ }
+ else
+ next_status = statuses.pop
+
+ {
+ statuses: statuses,
+ starting_depth: starting_depth,
+ next_status: next_status,
+ }
+ end
+ end
+
+ def set_ancestors
+ @ancestors = @status.reply? ? cache_collection(@status.ancestors(ANCESTORS_LIMIT, current_account), Status) : []
+ @next_ancestor = @ancestors.size < ANCESTORS_LIMIT ? nil : @ancestors.shift
+ end
+
+ def set_descendants
+ @max_descendant_thread_id = params[:max_descendant_thread_id]&.to_i
+ @since_descendant_thread_id = params[:since_descendant_thread_id]&.to_i
+
+ descendants = cache_collection(
+ @status.descendants(
+ DESCENDANTS_LIMIT,
+ current_account,
+ @max_descendant_thread_id,
+ @since_descendant_thread_id,
+ DESCENDANTS_DEPTH_LIMIT
+ ),
+ Status
+ )
+
+ @descendant_threads = []
+
+ if descendants.present?
+ statuses = [descendants.first]
+ starting_depth = 0
+
+ descendants.drop(1).each_with_index do |descendant, index|
+ if descendants[index].id == descendant.in_reply_to_id
+ statuses << descendant
+ else
+ @descendant_threads << create_descendant_thread(starting_depth, statuses)
+
+ # The thread is broken, assume it's a reply to the root status
+ starting_depth = 0
+
+ # ... unless we can find its ancestor in one of the already-processed threads
+ @descendant_threads.reverse_each do |descendant_thread|
+ statuses = descendant_thread[:statuses]
+
+ index = statuses.find_index do |thread_status|
+ thread_status.id == descendant.in_reply_to_id
+ end
+
+ if index.present?
+ starting_depth = descendant_thread[:starting_depth] + index + 1
+ break
+ end
+ end
+
+ statuses = [descendant]
+ end
+ end
+
+ @descendant_threads << create_descendant_thread(starting_depth, statuses)
+ end
+
+ @max_descendant_thread_id = @descendant_threads.pop[:statuses].first.id if descendants.size >= DESCENDANTS_LIMIT
+ end
+end
diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb
index 6e80feaf837..7f4dcfcfe67 100644
--- a/app/controllers/custom_css_controller.rb
+++ b/app/controllers/custom_css_controller.rb
@@ -6,6 +6,7 @@ class CustomCssController < ApplicationController
before_action :set_cache_headers
def show
+ expires 3.minutes, public: true
render plain: Setting.custom_css || '', content_type: 'text/css'
end
end
diff --git a/app/controllers/emojis_controller.rb b/app/controllers/emojis_controller.rb
index 3feb081325f..fe4c19cadae 100644
--- a/