about summary refs log tree commit diff
path: root/app/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers')
-rw-r--r--app/controllers/activitypub/outboxes_controller.rb2
-rw-r--r--app/controllers/admin/email_domain_blocks_controller.rb72
-rw-r--r--app/controllers/admin/reports/actions_controller.rb4
-rw-r--r--app/controllers/admin/trends/links/preview_card_providers_controller.rb12
-rw-r--r--app/controllers/admin/trends/links_controller.rb20
-rw-r--r--app/controllers/admin/trends/statuses_controller.rb45
-rw-r--r--app/controllers/admin/trends/tags_controller.rb12
-rw-r--r--app/controllers/api/base_controller.rb1
-rw-r--r--app/controllers/api/v1/accounts/familiar_followers_controller.rb25
-rw-r--r--app/controllers/api/v1/accounts/statuses_controller.rb42
-rw-r--r--app/controllers/api/v1/accounts_controller.rb6
-rw-r--r--app/controllers/api/v1/admin/trends/links_controller.rb19
-rw-r--r--app/controllers/api/v1/admin/trends/statuses_controller.rb19
-rw-r--r--app/controllers/api/v1/admin/trends/tags_controller.rb2
-rw-r--r--app/controllers/api/v1/blocks_controller.rb2
-rw-r--r--app/controllers/api/v1/domain_blocks_controller.rb4
-rw-r--r--app/controllers/api/v1/follow_requests_controller.rb6
-rw-r--r--app/controllers/api/v1/media_controller.rb2
-rw-r--r--app/controllers/api/v1/mutes_controller.rb2
-rw-r--r--app/controllers/api/v1/reports_controller.rb12
-rw-r--r--app/controllers/api/v1/statuses_controller.rb5
-rw-r--r--app/controllers/api/v1/trends/links_controller.rb6
-rw-r--r--app/controllers/api/v1/trends/statuses_controller.rb27
-rw-r--r--app/controllers/api/v1/trends/tags_controller.rb2
-rw-r--r--app/controllers/auth/registrations_controller.rb2
-rw-r--r--app/controllers/concerns/access_token_tracking_concern.rb21
-rw-r--r--app/controllers/concerns/localized.rb4
-rw-r--r--app/controllers/concerns/session_tracking_concern.rb4
-rw-r--r--app/controllers/concerns/user_tracking_concern.rb4
-rw-r--r--app/controllers/disputes/strikes_controller.rb6
-rw-r--r--app/controllers/follower_accounts_controller.rb6
-rw-r--r--app/controllers/following_accounts_controller.rb6
-rw-r--r--app/controllers/settings/preferences_controller.rb3
-rw-r--r--app/controllers/settings/profiles_controller.rb2
34 files changed, 274 insertions, 133 deletions
diff --git a/app/controllers/activitypub/outboxes_controller.rb b/app/controllers/activitypub/outboxes_controller.rb
index b2aab56a5..cd3992502 100644
--- a/app/controllers/activitypub/outboxes_controller.rb
+++ b/app/controllers/activitypub/outboxes_controller.rb
@@ -62,7 +62,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
     return unless page_requested?
 
     @statuses = cache_collection_paginated_by_id(
-      @account.statuses.permitted_for(@account, signed_request_account),
+      AccountStatusesFilter.new(@account, signed_request_account).results,
       Status,
       LIMIT,
       params_slice(:max_id, :min_id, :since_id)
diff --git a/app/controllers/admin/email_domain_blocks_controller.rb b/app/controllers/admin/email_domain_blocks_controller.rb
index f7bdfb0c5..a4bbbba5b 100644
--- a/app/controllers/admin/email_domain_blocks_controller.rb
+++ b/app/controllers/admin/email_domain_blocks_controller.rb
@@ -6,7 +6,20 @@ module Admin
 
     def index
       authorize :email_domain_block, :index?
+
       @email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
+      @form                = Form::EmailDomainBlockBatch.new
+    end
+
+    def batch
+      @form = Form::EmailDomainBlockBatch.new(form_email_domain_block_batch_params.merge(current_account: current_account, action: action_from_button))
+      @form.save
+    rescue ActionController::ParameterMissing
+      flash[:alert] = I18n.t('admin.email_domain_blocks.no_email_domain_block_selected')
+    rescue Mastodon::NotPermittedError
+      flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
+    ensure
+      redirect_to admin_email_domain_blocks_path
     end
 
     def new
@@ -19,41 +32,27 @@ module Admin
 
       @email_domain_block = EmailDomainBlock.new(resource_params)
 
-      if @email_domain_block.save
-        log_action :create, @email_domain_block
-
-        if @email_domain_block.with_dns_records?
-          hostnames = []
-          ips       = []
-
-          Resolv::DNS.open do |dns|
-            dns.timeouts = 5
+      if action_from_button == 'save'
+        EmailDomainBlock.transaction do
+          @email_domain_block.save!
+          log_action :create, @email_domain_block
 
-            hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
+          (@email_domain_block.other_domains || []).uniq.each do |domain|
+            next if EmailDomainBlock.where(domain: domain).exists?
 
-            ([@email_domain_block.domain] + hostnames).uniq.each do |hostname|
-              ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
-              ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })
-            end
-          end
-
-          (hostnames + ips).each do |hostname|
-            another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: @email_domain_block)
-            log_action :create, another_email_domain_block if another_email_domain_block.save
+            other_email_domain_block = EmailDomainBlock.create!(domain: domain, parent: @email_domain_block)
+            log_action :create, other_email_domain_block
           end
         end
 
         redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
       else
+        set_resolved_records
         render :new
       end
-    end
-
-    def destroy
-      authorize @email_domain_block, :destroy?
-      @email_domain_block.destroy!
-      log_action :destroy, @email_domain_block
-      redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg')
+    rescue ActiveRecord::RecordInvalid
+      set_resolved_records
+      render :new
     end
 
     private
@@ -62,8 +61,27 @@ module Admin
       @email_domain_block = EmailDomainBlock.find(params[:id])
     end
 
+    def set_resolved_records
+      Resolv::DNS.open do |dns|
+        dns.timeouts = 5
+        @resolved_records = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a
+      end
+    end
+
     def resource_params
-      params.require(:email_domain_block).permit(:domain, :with_dns_records)
+      params.require(:email_domain_block).permit(:domain, other_domains: [])
+    end
+
+    def form_email_domain_block_batch_params
+      params.require(:form_email_domain_block_batch).permit(email_domain_block_ids: [])
+    end
+
+    def action_from_button
+      if params[:delete]
+        'delete'
+      elsif params[:save]
+        'save'
+      end
     end
   end
 end
diff --git a/app/controllers/admin/reports/actions_controller.rb b/app/controllers/admin/reports/actions_controller.rb
index 05a4fb63d..5cb5c744f 100644
--- a/app/controllers/admin/reports/actions_controller.rb
+++ b/app/controllers/admin/reports/actions_controller.rb
@@ -7,7 +7,7 @@ class Admin::Reports::ActionsController < Admin::BaseController
     authorize @report, :show?
 
     case action_from_button
-    when 'delete'
+    when 'delete', 'mark_as_sensitive'
       status_batch_action = Admin::StatusBatchAction.new(
         type: action_from_button,
         status_ids: @report.status_ids,
@@ -41,6 +41,8 @@ class Admin::Reports::ActionsController < Admin::BaseController
   def action_from_button
     if params[:delete]
       'delete'
+    elsif params[:mark_as_sensitive]
+      'mark_as_sensitive'
     elsif params[:silence]
       'silence'
     elsif params[:suspend]
diff --git a/app/controllers/admin/trends/links/preview_card_providers_controller.rb b/app/controllers/admin/trends/links/preview_card_providers_controller.rb
index 2c26e03f3..40a466cd6 100644
--- a/app/controllers/admin/trends/links/preview_card_providers_controller.rb
+++ b/app/controllers/admin/trends/links/preview_card_providers_controller.rb
@@ -5,11 +5,11 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
     authorize :preview_card_provider, :index?
 
     @preview_card_providers = filtered_preview_card_providers.page(params[:page])
-    @form = Form::PreviewCardProviderBatch.new
+    @form = Trends::PreviewCardProviderBatch.new
   end
 
   def batch
-    @form = Form::PreviewCardProviderBatch.new(form_preview_card_provider_batch_params.merge(current_account: current_account, action: action_from_button))
+    @form = Trends::PreviewCardProviderBatch.new(trends_preview_card_provider_batch_params.merge(current_account: current_account, action: action_from_button))
     @form.save
   rescue ActionController::ParameterMissing
     flash[:alert] = I18n.t('admin.accounts.no_account_selected')
@@ -20,15 +20,15 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
   private
 
   def filtered_preview_card_providers
-    PreviewCardProviderFilter.new(filter_params).results
+    Trends::PreviewCardProviderFilter.new(filter_params).results
   end
 
   def filter_params
-    params.slice(:page, *PreviewCardProviderFilter::KEYS).permit(:page, *PreviewCardProviderFilter::KEYS)
+    params.slice(:page, *Trends::PreviewCardProviderFilter::KEYS).permit(:page, *Trends::PreviewCardProviderFilter::KEYS)
   end
 
-  def form_preview_card_provider_batch_params
-    params.require(:form_preview_card_provider_batch).permit(:action, preview_card_provider_ids: [])
+  def trends_preview_card_provider_batch_params
+    params.require(:trends_preview_card_provider_batch).permit(:action, preview_card_provider_ids: [])
   end
 
   def action_from_button
diff --git a/app/controllers/admin/trends/links_controller.rb b/app/controllers/admin/trends/links_controller.rb
index 619b37deb..434eec5fe 100644
--- a/app/controllers/admin/trends/links_controller.rb
+++ b/app/controllers/admin/trends/links_controller.rb
@@ -5,11 +5,11 @@ class Admin::Trends::LinksController < Admin::BaseController
     authorize :preview_card, :index?
 
     @preview_cards = filtered_preview_cards.page(params[:page])
-    @form          = Form::PreviewCardBatch.new
+    @form          = Trends::PreviewCardBatch.new
   end
 
   def batch
-    @form = Form::PreviewCardBatch.new(form_preview_card_batch_params.merge(current_account: current_account, action: action_from_button))
+    @form = Trends::PreviewCardBatch.new(trends_preview_card_batch_params.merge(current_account: current_account, action: action_from_button))
     @form.save
   rescue ActionController::ParameterMissing
     flash[:alert] = I18n.t('admin.accounts.no_account_selected')
@@ -20,26 +20,26 @@ class Admin::Trends::LinksController < Admin::BaseController
   private
 
   def filtered_preview_cards
-    PreviewCardFilter.new(filter_params.with_defaults(trending: 'all')).results
+    Trends::PreviewCardFilter.new(filter_params.with_defaults(trending: 'all')).results
   end
 
   def filter_params
-    params.slice(:page, *PreviewCardFilter::KEYS).permit(:page, *PreviewCardFilter::KEYS)
+    params.slice(:page, *Trends::PreviewCardFilter::KEYS).permit(:page, *Trends::PreviewCardFilter::KEYS)
   end
 
-  def form_preview_card_batch_params
-    params.require(:form_preview_card_batch).permit(:action, preview_card_ids: [])
+  def trends_preview_card_batch_params
+    params.require(:trends_preview_card_batch).permit(:action, preview_card_ids: [])
   end
 
   def action_from_button
     if params[:approve]
       'approve'
-    elsif params[:approve_all]
-      'approve_all'
+    elsif params[:approve_providers]
+      'approve_providers'
     elsif params[:reject]
       'reject'
-    elsif params[:reject_all]
-      'reject_all'
+    elsif params[:reject_providers]
+      'reject_providers'
     end
   end
 end
diff --git a/app/controllers/admin/trends/statuses_controller.rb b/app/controllers/admin/trends/statuses_controller.rb
new file mode 100644
index 000000000..766242738
--- /dev/null
+++ b/app/controllers/admin/trends/statuses_controller.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class Admin::Trends::StatusesController < Admin::BaseController
+  def index
+    authorize :status, :index?
+
+    @statuses = filtered_statuses.page(params[:page])
+    @form     = Trends::StatusBatch.new
+  end
+
+  def batch
+    @form = Trends::StatusBatch.new(trends_status_batch_params.merge(current_account: current_account, action: action_from_button))
+    @form.save
+  rescue ActionController::ParameterMissing
+    flash[:alert] = I18n.t('admin.accounts.no_account_selected')
+  ensure
+    redirect_to admin_trends_statuses_path(filter_params)
+  end
+
+  private
+
+  def filtered_statuses
+    Trends::StatusFilter.new(filter_params.with_defaults(trending: 'all')).results.includes(:account, :media_attachments, :active_mentions)
+  end
+
+  def filter_params
+    params.slice(:page, *Trends::StatusFilter::KEYS).permit(:page, *Trends::StatusFilter::KEYS)
+  end
+
+  def trends_status_batch_params
+    params.require(:trends_status_batch).permit(:action, status_ids: [])
+  end
+
+  def action_from_button
+    if params[:approve]
+      'approve'
+    elsif params[:approve_accounts]
+      'approve_accounts'
+    elsif params[:reject]
+      'reject'
+    elsif params[:reject_accounts]
+      'reject_accounts'
+    end
+  end
+end
diff --git a/app/controllers/admin/trends/tags_controller.rb b/app/controllers/admin/trends/tags_controller.rb
index 91ff33d40..f4d1ec0d1 100644
--- a/app/controllers/admin/trends/tags_controller.rb
+++ b/app/controllers/admin/trends/tags_controller.rb
@@ -5,11 +5,11 @@ class Admin::Trends::TagsController < Admin::BaseController
     authorize :tag, :index?
 
     @tags = filtered_tags.page(params[:page])
-    @form = Form::TagBatch.new
+    @form = Trends::TagBatch.new
   end
 
   def batch
-    @form = Form::TagBatch.new(form_tag_batch_params.merge(current_account: current_account, action: action_from_button))
+    @form = Trends::TagBatch.new(trends_tag_batch_params.merge(current_account: current_account, action: action_from_button))
     @form.save
   rescue ActionController::ParameterMissing
     flash[:alert] = I18n.t('admin.accounts.no_account_selected')
@@ -20,15 +20,15 @@ class Admin::Trends::TagsController < Admin::BaseController
   private
 
   def filtered_tags
-    TagFilter.new(filter_params).results
+    Trends::TagFilter.new(filter_params).results
   end
 
   def filter_params
-    params.slice(:page, *TagFilter::KEYS).permit(:page, *TagFilter::KEYS)
+    params.slice(:page, *Trends::TagFilter::KEYS).permit(:page, *Trends::TagFilter::KEYS)
   end
 
-  def form_tag_batch_params
-    params.require(:form_tag_batch).permit(:action, tag_ids: [])
+  def trends_tag_batch_params
+    params.require(:trends_tag_batch).permit(:action, tag_ids: [])
   end
 
   def action_from_button
diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index b863d8643..72c30dec7 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -5,6 +5,7 @@ class Api::BaseController < ApplicationController
   DEFAULT_ACCOUNTS_LIMIT = 40
 
   include RateLimitHeaders
+  include AccessTokenTrackingConcern
 
   skip_before_action :store_current_location
   skip_before_action :require_functional!, unless: :whitelist_mode?
diff --git a/app/controllers/api/v1/accounts/familiar_followers_controller.rb b/app/controllers/api/v1/accounts/familiar_followers_controller.rb
new file mode 100644
index 000000000..b0bd8018a
--- /dev/null
+++ b/app/controllers/api/v1/accounts/familiar_followers_controller.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class Api::V1::Accounts::FamiliarFollowersController < Api::BaseController
+  before_action -> { doorkeeper_authorize! :read, :'read:follows' }
+  before_action :require_user!
+  before_action :set_accounts
+
+  def index
+    render json: familiar_followers.accounts, each_serializer: REST::FamiliarFollowersSerializer
+  end
+
+  private
+
+  def set_accounts
+    @accounts = Account.without_suspended.where(id: account_ids).select('id, hide_collections').index_by(&:id).values_at(*account_ids).compact
+  end
+
+  def familiar_followers
+    FamiliarFollowersPresenter.new(@accounts, current_user.account_id)
+  end
+
+  def account_ids
+    Array(params[:id]).map(&:to_i)
+  end
+end
diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb
index 5e5d2b19b..a68d266a7 100644
--- a/app/controllers/api/v1/accounts/statuses_controller.rb
+++ b/app/controllers/api/v1/accounts/statuses_controller.rb
@@ -23,54 +23,16 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
 
   def cached_account_statuses
     return Status.none unless user_signed_in?
-
-    statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses
-
-    statuses.merge!(only_media_scope) if truthy_param?(:only_media)
-    statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies)
-    statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
-    statuses.merge!(hashtag_scope)    if params[:tagged].present?
-
     cache_collection_paginated_by_id(
-      statuses,
+      AccountStatusesFilter.new(@account, current_account, params).results,
       Status,
       limit_param(DEFAULT_STATUSES_LIMIT),
       params_slice(:max_id, :since_id, :min_id)
     )
   end
 
-  def permitted_account_statuses
-    @account.statuses.permitted_for(@account, current_account)
-  end
-
-  def only_media_scope
-    Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id)
-  end
-
-  def pinned_scope
-    @account.pinned_statuses.permitted_for(@account, current_account)
-  end
-
-  def no_replies_scope
-    Status.without_replies
-  end
-
-  def no_reblogs_scope
-    Status.without_reblogs
-  end
-
-  def hashtag_scope
-    tag = Tag.find_normalized(params[:tagged])
-
-    if tag
-      Status.tagged_with(tag.id)
-    else
-      Status.none
-    end
-  end
-
   def pagination_params(core_params)
-    params.slice(:limit, :only_media, :exclude_replies).permit(:limit, :only_media, :exclude_replies).merge(core_params)
+    params.slice(:limit, *AccountStatusesFilter::KEYS).permit(:limit, *AccountStatusesFilter::KEYS).merge(core_params)
   end
 
   def insert_pagination_headers
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 5c47158e0..5134bfb94 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -2,9 +2,9 @@
 
 class Api::V1::AccountsController < Api::BaseController
   before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute]
-  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
-  before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute]
-  before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock]
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, only: [:mute, :unmute]
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock]
   before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]
 
   before_action :require_user!, except: [:show, :create]
diff --git a/app/controllers/api/v1/admin/trends/links_controller.rb b/app/controllers/api/v1/admin/trends/links_controller.rb
new file mode 100644
index 000000000..63b3d9358
--- /dev/null
+++ b/app/controllers/api/v1/admin/trends/links_controller.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class Api::V1::Admin::Trends::LinksController < Api::BaseController
+  protect_from_forgery with: :exception
+
+  before_action -> { authorize_if_got_token! :'admin:read' }
+  before_action :require_staff!
+  before_action :set_links
+
+  def index
+    render json: @links, each_serializer: REST::Trends::LinkSerializer
+  end
+
+  private
+
+  def set_links
+    @links = Trends.links.query.limit(limit_param(10))
+  end
+end
diff --git a/app/controllers/api/v1/admin/trends/statuses_controller.rb b/app/controllers/api/v1/admin/trends/statuses_controller.rb
new file mode 100644
index 000000000..86633cc74
--- /dev/null
+++ b/app/controllers/api/v1/admin/trends/statuses_controller.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class Api::V1::Admin::Trends::StatusesController < Api::BaseController
+  protect_from_forgery with: :exception
+
+  before_action -> { authorize_if_got_token! :'admin:read' }
+  before_action :require_staff!
+  before_action :set_statuses
+
+  def index
+    render json: @statuses, each_serializer: REST::StatusSerializer
+  end
+
+  private
+
+  def set_statuses
+    @statuses = cache_collection(Trends.statuses.query.limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status)
+  end
+end
diff --git a/app/controllers/api/v1/admin/trends/tags_controller.rb b/app/controllers/api/v1/admin/trends/tags_controller.rb
index 4815af31e..5cc4c269d 100644
--- a/app/controllers/api/v1/admin/trends/tags_controller.rb
+++ b/app/controllers/api/v1/admin/trends/tags_controller.rb
@@ -14,6 +14,6 @@ class Api::V1::Admin::Trends::TagsController < Api::BaseController
   private
 
   def set_tags
-    @tags = Trends.tags.get(false, limit_param(10))
+    @tags = Trends.tags.query.limit(limit_param(10))
   end
 end
diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb
index 586cdfca9..a65e762c9 100644
--- a/app/controllers/api/v1/blocks_controller.rb
+++ b/app/controllers/api/v1/blocks_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Api::V1::BlocksController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:blocks' }
   before_action :require_user!
   after_action :insert_pagination_headers
 
diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb
index 5bb02d834..1891261b9 100644
--- a/app/controllers/api/v1/domain_blocks_controller.rb
+++ b/app/controllers/api/v1/domain_blocks_controller.rb
@@ -3,8 +3,8 @@
 class Api::V1::DomainBlocksController < Api::BaseController
   BLOCK_LIMIT = 100
 
-  before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }, only: :show
-  before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, except: :show
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:blocks' }, only: :show
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, except: :show
   before_action :require_user!
   after_action :insert_pagination_headers, only: :show
 
diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb
index f4b2a74d0..54ff0e11d 100644
--- a/app/controllers/api/v1/follow_requests_controller.rb
+++ b/app/controllers/api/v1/follow_requests_controller.rb
@@ -1,8 +1,8 @@
 # frozen_string_literal: true
 
 class Api::V1::FollowRequestsController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :follow, :'read:follows' }, only: :index
-  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, except: :index
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }, only: :index
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, except: :index
   before_action :require_user!
   after_action :insert_pagination_headers, only: :index
 
@@ -13,7 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController
 
   def authorize
     AuthorizeFollowService.new.call(account, current_account)
-    NotifyService.new.call(current_account, :follow, Follow.find_by(account: account, target_account: current_account))
+    LocalNotificationWorker.perform_async(current_account.id, Follow.find_by(account: account, target_account: current_account).id, 'Follow', 'follow')
     render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
   end
 
diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb
index 72094790f..f9c935bf3 100644
--- a/app/controllers/api/v1/media_controller.rb
+++ b/app/controllers/api/v1/media_controller.rb
@@ -31,7 +31,7 @@ class Api::V1::MediaController < Api::BaseController
   end
 
   def set_media_attachment
-    @media_attachment = current_account.media_attachments.unattached.find(params[:id])
+    @media_attachment = current_account.media_attachments.where(status_id: nil).find(params[:id])
   end
 
   def check_processing
diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb
index fd52511d7..6cde53a2a 100644
--- a/app/controllers/api/v1/mutes_controller.rb
+++ b/app/controllers/api/v1/mutes_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Api::V1::MutesController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :follow, :'read:mutes' }
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:mutes' }
   before_action :require_user!
   after_action :insert_pagination_headers
 
diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb
index 052d70cc8..8ff6c8fe5 100644
--- a/app/controllers/api/v1/reports_controller.rb
+++ b/app/controllers/api/v1/reports_controller.rb
@@ -10,9 +10,7 @@ class Api::V1::ReportsController < Api::BaseController
     @report = ReportService.new.call(
       current_account,
       reported_account,
-      status_ids: reported_status_ids,
-      comment: report_params[:comment],
-      forward: report_params[:forward]
+      report_params
     )
 
     render json: @report, serializer: REST::ReportSerializer
@@ -20,14 +18,6 @@ class Api::V1::ReportsController < Api::BaseController
 
   private
 
-  def reported_status_ids
-    reported_account.statuses.with_discarded.find(status_ids).pluck(:id)
-  end
-
-  def status_ids
-    Array(report_params[:status_ids])
-  end
-
   def reported_account
     Account.find(report_params[:account_id])
   end
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index eaac8e563..ddd7c33ae 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -94,8 +94,9 @@ class Api::V1::StatusesController < Api::BaseController
   end
 
   def set_thread
-    @thread = status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id])
-  rescue ActiveRecord::RecordNotFound
+    @thread = Status.find(status_params[:in_reply_to_id]) if status_params[:in_reply_to_id].present?
+    authorize(@thread, :show?) if @thread.present?
+  rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
     render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
   end
 
diff --git a/app/controllers/api/v1/trends/links_controller.rb b/app/controllers/api/v1/trends/links_controller.rb
index 1c3ab1e1c..ad20e7f8b 100644
--- a/app/controllers/api/v1/trends/links_controller.rb
+++ b/app/controllers/api/v1/trends/links_controller.rb
@@ -12,10 +12,14 @@ class Api::V1::Trends::LinksController < Api::BaseController
   def set_links
     @links = begin
       if Setting.trends
-        Trends.links.get(true, limit_param(10))
+        links_from_trends
       else
         []
       end
     end
   end
+
+  def links_from_trends
+    Trends.links.query.allowed.in_locale(content_locale).limit(limit_param(10))
+  end
 end
diff --git a/app/controllers/api/v1/trends/statuses_controller.rb b/app/controllers/api/v1/trends/statuses_controller.rb
new file mode 100644
index 000000000..d4ec97ae5
--- /dev/null
+++ b/app/controllers/api/v1/trends/statuses_controller.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class Api::V1::Trends::StatusesController < Api::BaseController
+  before_action :set_statuses
+
+  def index
+    render json: @statuses, each_serializer: REST::StatusSerializer
+  end
+
+  private
+
+  def set_statuses
+    @statuses = begin
+      if Setting.trends
+        cache_collection(statuses_from_trends, Status)
+      else
+        []
+      end
+    end
+  end
+
+  def statuses_from_trends
+    scope = Trends.statuses.query.allowed.in_locale(content_locale)
+    scope = scope.filtered_for(current_account) if user_signed_in?
+    scope.limit(limit_param(DEFAULT_STATUSES_LIMIT))
+  end
+end
diff --git a/app/controllers/api/v1/trends/tags_controller.rb b/app/controllers/api/v1/trends/tags_controller.rb
index 947b53de2..1334b72d2 100644
--- a/app/controllers/api/v1/trends/tags_controller.rb
+++ b/app/controllers/api/v1/trends/tags_controller.rb
@@ -12,7 +12,7 @@ class Api::V1::Trends::TagsController < Api::BaseController
   def set_tags
     @tags = begin
       if Setting.trends
-        Trends.tags.get(true, limit_param(10))
+        Trends.tags.query.allowed.limit(limit_param(10))
       else
         []
       end
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 5d32fe66e..1c0f360a9 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -132,7 +132,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
   end
 
   def set_strikes
-    @strikes = current_account.strikes.active.latest
+    @strikes = current_account.strikes.recent.latest
   end
 
   def require_not_suspended!
diff --git a/app/controllers/concerns/access_token_tracking_concern.rb b/app/controllers/concerns/access_token_tracking_concern.rb
new file mode 100644
index 000000000..cf60cfb99
--- /dev/null
+++ b/app/controllers/concerns/access_token_tracking_concern.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module AccessTokenTrackingConcern
+  extend ActiveSupport::Concern
+
+  ACCESS_TOKEN_UPDATE_FREQUENCY = 24.hours.freeze
+
+  included do
+    before_action :update_access_token_last_used
+  end
+
+  private
+
+  def update_access_token_last_used
+    doorkeeper_token.update_last_used(request) if access_token_needs_update?
+  end
+
+  def access_token_needs_update?
+    doorkeeper_token.present? && (doorkeeper_token.last_used_at.nil? || doorkeeper_token.last_used_at < ACCESS_TOKEN_UPDATE_FREQUENCY.ago)
+  end
+end
diff --git a/app/controllers/concerns/localized.rb b/app/controllers/concerns/localized.rb
index 173316800..ede299d5a 100644
--- a/app/controllers/concerns/localized.rb
+++ b/app/controllers/concerns/localized.rb
@@ -27,4 +27,8 @@ module Localized
   def available_locale_or_nil(locale_name)
     locale_name.to_sym if locale_name.present? && I18n.available_locales.include?(locale_name.to_sym)
   end
+
+  def content_locale
+    @content_locale ||= I18n.locale.to_s.split(/[_-]/).first
+  end
 end
diff --git a/app/controllers/concerns/session_tracking_concern.rb b/app/controllers/concerns/session_tracking_concern.rb
index 45361b019..eaaa4ac59 100644
--- a/app/controllers/concerns/session_tracking_concern.rb
+++ b/app/controllers/concerns/session_tracking_concern.rb
@@ -3,7 +3,7 @@
 module SessionTrackingConcern
   extend ActiveSupport::Concern
 
-  UPDATE_SIGN_IN_HOURS = 24
+  SESSION_UPDATE_FREQUENCY = 24.hours.freeze
 
   included do
     before_action :set_session_activity
@@ -17,6 +17,6 @@ module SessionTrackingConcern
   end
 
   def session_needs_update?
-    !current_session.nil? && current_session.updated_at < UPDATE_SIGN_IN_HOURS.hours.ago
+    !current_session.nil? && current_session.updated_at < SESSION_UPDATE_FREQUENCY.ago
   end
 end
diff --git a/app/controllers/concerns/user_tracking_concern.rb b/app/controllers/concerns/user_tracking_concern.rb
index 45f3aab0d..e960cce53 100644
--- a/app/controllers/concerns/user_tracking_concern.rb
+++ b/app/controllers/concerns/user_tracking_concern.rb
@@ -3,7 +3,7 @@
 module UserTrackingConcern
   extend ActiveSupport::Concern
 
-  UPDATE_SIGN_IN_FREQUENCY = 24.hours.freeze
+  SIGN_IN_UPDATE_FREQUENCY = 24.hours.freeze
 
   included do
     before_action :update_user_sign_in
@@ -16,6 +16,6 @@ module UserTrackingConcern
   end
 
   def user_needs_sign_in_update?
-    user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_FREQUENCY.ago)
+    user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < SIGN_IN_UPDATE_FREQUENCY.ago)
   end
 end
diff --git a/app/controllers/disputes/strikes_controller.rb b/app/controllers/disputes/strikes_controller.rb
index d41c5c727..d85dcb4d5 100644
--- a/app/controllers/disputes/strikes_controller.rb
+++ b/app/controllers/disputes/strikes_controller.rb
@@ -1,7 +1,11 @@
 # frozen_string_literal: true
 
 class Disputes::StrikesController < Disputes::BaseController
-  before_action :set_strike
+  before_action :set_strike, only: [:show]
+
+  def index
+    @strikes = current_account.strikes.latest
+  end
 
   def show
     authorize @strike, :show?
diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb
index d519138cd..f898994ac 100644
--- a/app/controllers/follower_accounts_controller.rb
+++ b/app/controllers/follower_accounts_controller.rb
@@ -16,13 +16,13 @@ class FollowerAccountsController < ApplicationController
         use_pack 'public'
         expires_in 0, public: true unless user_signed_in?
 
-        next if @account.user_hides_network?
+        next if @account.hide_collections?
 
         follows
       end
 
       format.json do
-        raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network?
+        raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
 
         expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
 
@@ -83,7 +83,7 @@ class FollowerAccountsController < ApplicationController
   end
 
   def restrict_fields_to
-    if page_requested? || !@account.user_hides_network?
+    if page_requested? || !@account.hide_collections?
       # Return all fields
     else
       %i(id type total_items)
diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb
index 4b4978fb9..bc291c962 100644
--- a/app/controllers/following_accounts_controller.rb
+++ b/app/controllers/following_accounts_controller.rb
@@ -16,13 +16,13 @@ class FollowingAccountsController < ApplicationController
         use_pack 'public'
         expires_in 0, public: true unless user_signed_in?
 
-        next if @account.user_hides_network?
+        next if @account.hide_collections?
 
         follows
       end
 
       format.json do
-        raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network?
+        raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
 
         expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
 
@@ -83,7 +83,7 @@ class FollowingAccountsController < ApplicationController
   end
 
   def restrict_fields_to
-    if page_requested? || !@account.user_hides_network?
+    if page_requested? || !@account.hide_collections?
       # Return all fields
     else
       %i(id type total_items)
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index d05ceb53f..1fddd087b 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -48,7 +48,6 @@ class Settings::PreferencesController < Settings::BaseController
       :setting_system_font_ui,
       :setting_system_emoji_font,
       :setting_noindex,
-      :setting_hide_network,
       :setting_hide_followers_count,
       :setting_aggregate_reblogs,
       :setting_show_application,
@@ -58,7 +57,7 @@ class Settings::PreferencesController < Settings::BaseController
       :setting_use_pending_items,
       :setting_trends,
       :setting_crop_images,
-      notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
+      notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag trending_link trending_status),
       interactions: %i(must_be_follower must_be_following must_be_following_dm)
     )
   end
diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb
index 0c15447a6..be5b4f302 100644
--- a/app/controllers/settings/profiles_controller.rb
+++ b/app/controllers/settings/profiles_controller.rb
@@ -20,7 +20,7 @@ class Settings::ProfilesController < Settings::BaseController
   private
 
   def account_params
-    params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, fields_attributes: [:name, :value])
+    params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, :hide_collections, fields_attributes: [:name, :value])
   end
 
   def set_account