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/accounts_controller.rb51
-rw-r--r--app/controllers/api/v1/accounts/statuses_controller.rb91
2 files changed, 87 insertions, 55 deletions
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index e26b6395f..8059e0e5d 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -13,7 +13,7 @@ class AccountsController < ApplicationController
   before_action :require_authenticated!, if: -> { @account.require_auth? || @account.private? }
 
   skip_around_action :set_locale, if: -> { [:json, :rss].include?(request.format&.to_sym) }
-  skip_before_action :require_functional! #, unless: :whitelist_mode?
+  skip_before_action :require_functional! # , unless: :whitelist_mode?
 
   def show
     respond_to do |format|
@@ -66,19 +66,26 @@ class AccountsController < ApplicationController
   end
 
   def show_pinned_statuses?
-    [replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none?
+    [threads_requested?, replies_requested?, reblogs_requested?, mentions_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none?
   end
 
   def filtered_statuses
+    return mentions_scope if mentions_requested?
+
     default_statuses.tap do |statuses|
-      statuses.merge!(hashtag_scope)    if tag_requested?
       statuses.merge!(only_media_scope) if media_requested?
-      statuses.merge!(no_replies_scope) unless (current_account&.id == @account.id || @account.show_replies?) && replies_requested?
     end
   end
 
   def default_statuses
-    @account.statuses.permitted_for(@account, current_account, user_signed_in: user_signed_in?).not_local_only
+    @account.statuses.permitted_for(
+      @account,
+      current_account,
+      include_reblogs: !(threads_requested? || replies_requested?),
+      only_reblogs: reblogs_requested?,
+      only_replies: replies_requested?,
+      tag: tag_requested? ? params[:tag] : nil
+    )
   end
 
   def only_media_scope
@@ -89,18 +96,10 @@ class AccountsController < ApplicationController
     @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
   end
 
-  def no_replies_scope
-    Status.without_replies
-  end
-
-  def hashtag_scope
-    tag = Tag.find_normalized(params[:tag])
+  def mentions_scope
+    return Status.none unless current_account?
 
-    if tag
-      Status.tagged_with(tag.id)
-    else
-      Status.none
-    end
+    Status.mentions_between(@account, current_account)
   end
 
   def username_param
@@ -128,8 +127,14 @@ class AccountsController < ApplicationController
       short_account_tag_url(@account, params[:tag], max_id: max_id, min_id: min_id)
     elsif media_requested?
       short_account_media_url(@account, max_id: max_id, min_id: min_id)
+    elsif threads_requested?
+      short_account_threads_url(@account, max_id: max_id, min_id: min_id)
     elsif replies_requested?
       short_account_with_replies_url(@account, max_id: max_id, min_id: min_id)
+    elsif reblogs_requested?
+      short_account_reblogs_url(@account, max_id: max_id, min_id: min_id)
+    elsif mentions_requested?
+      short_account_mentions_url(@account, max_id: max_id, min_id: min_id)
     else
       short_account_url(@account, max_id: max_id, min_id: min_id)
     end
@@ -139,7 +144,13 @@ class AccountsController < ApplicationController
     request.path.split('.').first.ends_with?('/media') && !tag_requested?
   end
 
+  def threads_requested?
+    request.path.split('.').first.ends_with?('/threads') && !tag_requested?
+  end
+
   def replies_requested?
+    return false unless current_account&.id == @account.id || @account.show_replies?
+
     request.path.split('.').first.ends_with?('/with_replies') && !tag_requested?
   end
 
@@ -147,6 +158,14 @@ class AccountsController < ApplicationController
     request.path.split('.').first.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
   end
 
+  def reblogs_requested?
+    request.path.split('.').first.ends_with?('/reblogs') && !tag_requested?
+  end
+
+  def mentions_requested?
+    request.path.split('.').first.ends_with?('/mentions') && !tag_requested?
+  end
+
   def filtered_status_page
     filtered_statuses.paginate_by_id(PAGE_SIZE, params_slice(:max_id, :min_id, :since_id))
   end
diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb
index 3e0feed7e..61633ce36 100644
--- a/app/controllers/api/v1/accounts/statuses_controller.rb
+++ b/app/controllers/api/v1/accounts/statuses_controller.rb
@@ -17,6 +17,10 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
     @account = Account.find(params[:account_id])
   end
 
+  def owner?
+    @account.id == current_account&.id
+  end
+
   def load_statuses
     cached_account_statuses
   end
@@ -26,62 +30,75 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
   end
 
   def account_statuses
-    return [] if (@account.private && !following?(@account)) || (@account.require_auth && !current_account?)
-
     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 (current_account&.id != @account.id && !@account.show_replies?) || truthy_param?(:exclude_replies)
-    statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
-    statuses.merge!(hashtag_scope)    if params[:tagged].present?
-
     statuses.paginate_by_id(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, user_signed_in: authenticated_or_following?(@account))
+    return mentions_scope if truthy_param?(:mentions)
+    return Status.none if unauthorized?
+
+    @account.statuses.permitted_for(
+      @account,
+      current_account,
+      include_reblogs: include_reblogs?,
+      include_replies: include_replies?,
+      only_reblogs: only_reblogs?,
+      only_replies: only_replies?,
+      include_unpublished: owner?,
+      tag: params[:tagged]
+    )
   end
 
-  def only_media_scope
-    Status.where(id: account_media_status_ids)
+  def unauthorized?
+    (@account.private && !following?(@account)) || (@account.require_auth && !current_account?)
   end
 
-  def account_media_status_ids
-    # `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
-    # Also, Avoid getting slow by not narrowing down by `statuses.account_id`.
-    # When narrowing down by `statuses.account_id`, `index_statuses_20180106` will be used
-    # and the table will be joined by `Merge Semi Join`, so the query will be slow.
-    @account.statuses.joins(:media_attachments).merge(@account.media_attachments).permitted_for(@account, current_account, user_signed_in: authenticated_or_following?(@account))
-            .paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id])
-            .reorder(id: :desc).distinct(:id).pluck(:id)
+  def include_reblogs?
+    params[:include_reblogs].present? ? truthy_param?(:include_reblogs) : !truthy_param?(:exclude_reblogs)
   end
 
-  def pinned_scope
-    return Status.none if @account.blocking?(current_account)
+  def include_replies?
+    return false unless owner? || @account.show_replies?
 
-    @account.pinned_statuses
+    params[:include_replies].present? ? truthy_param?(:include_replies) : !truthy_param?(:exclude_replies)
+  end
+
+  def only_reblogs?
+    truthy_param?(:only_reblogs).presence || false
   end
 
-  def no_replies_scope
-    Status.without_replies
+  def only_replies?
+    return false unless owner? || @account.show_replies?
+
+    truthy_param?(:only_replies).presence || false
   end
 
-  def no_reblogs_scope
-    Status.without_reblogs
+  def mentions_scope
+    return Status.none unless current_account?
+
+    Status.mentions_between(@account, current_account)
   end
 
-  def hashtag_scope
-    tag = Tag.find_normalized(params[:tagged])
+  def only_media_scope
+    Status.where(id: account_media_status_ids)
+  end
 
-    if tag
-      Status.tagged_with(tag.id)
-    else
-      Status.none
-    end
+  def account_media_status_ids
+    @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
+  end
+
+  def pinned_scope
+    return Status.none if @account.blocking?(current_account)
+
+    @account.pinned_statuses
   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, :only_media, :include_replies, :exclude_replies, :only_replies, :include_reblogs, :exclude_reblogs, :only_relogs, :mentions)
+          .permit(:limit, :only_media, :include_replies, :exclude_replies, :only_replies, :include_reblogs, :exclude_reblogs, :only_relogs, :mentions)
+          .merge(core_params)
   end
 
   def insert_pagination_headers
@@ -89,15 +106,11 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
   end
 
   def next_path
-    if records_continue?
-      api_v1_account_statuses_url pagination_params(max_id: pagination_max_id)
-    end
+    api_v1_account_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
   end
 
   def prev_path
-    unless @statuses.empty?
-      api_v1_account_statuses_url pagination_params(min_id: pagination_since_id)
-    end
+    api_v1_account_statuses_url pagination_params(min_id: pagination_since_id) unless @statuses.empty?
   end
 
   def records_continue?