about summary refs log tree commit diff
path: root/app/models
diff options
context:
space:
mode:
authorFire Demon <firedemon@creature.cafe>2020-07-21 01:44:16 -0500
committerFire Demon <firedemon@creature.cafe>2020-08-30 05:44:01 -0500
commit263ead73616dba43a0337c2a3edaf96a6382d533 (patch)
treeca47a9366dbbdf95018c55bde32b59d6b05c8299 /app/models
parent21de9efc2d89ce8dbb9edb997f8a3b99f831d05a (diff)
[Feature] Add post and thread (un)hiding to backend
Diffstat (limited to 'app/models')
-rw-r--r--app/models/concerns/account_interactions.rb30
-rw-r--r--app/models/conversation.rb1
-rw-r--r--app/models/conversation_mute.rb5
-rw-r--r--app/models/status.rb34
-rw-r--r--app/models/status_mute.rb14
5 files changed, 68 insertions, 16 deletions
diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb
index 01a711493..d5e2fe985 100644
--- a/app/models/concerns/account_interactions.rb
+++ b/app/models/concerns/account_interactions.rb
@@ -90,9 +90,10 @@ module AccountInteractions
     has_many :muting, -> { order('mutes.id desc') }, through: :mute_relationships, source: :target_account
     has_many :muted_by_relationships, class_name: 'Mute', foreign_key: :target_account_id, dependent: :destroy
     has_many :muted_by, -> { order('mutes.id desc') }, through: :muted_by_relationships, source: :account
-    has_many :conversation_mutes, dependent: :destroy
+    has_many :conversation_mutes, inverse_of: :account, dependent: :destroy
     has_many :domain_blocks, class_name: 'AccountDomainBlock', dependent: :destroy
     has_many :announcement_mutes, dependent: :destroy
+    has_many :status_mutes, inverse_of: :account, dependent: :destroy
   end
 
   def follow!(other_account, reblogs: nil, uri: nil, rate_limit: false)
@@ -132,15 +133,15 @@ module AccountInteractions
     remove_potential_friendship(other_account)
 
     # When toggling a mute between hiding and allowing notifications, the mute will already exist, so the find_or_create_by! call will return the existing Mute without updating the hide_notifications attribute. Therefore, we check that hide_notifications? is what we want and set it if it isn't.
-    if mute.hide_notifications? != notifications
-      mute.update!(hide_notifications: notifications, timelines_only: timelines_only)
-    end
+    mute.update!(hide_notifications: notifications, timelines_only: timelines_only) if mute.hide_notifications? != notifications
 
     mute
   end
 
-  def mute_conversation!(conversation)
-    conversation_mutes.find_or_create_by!(conversation: conversation)
+  def mute_conversation!(conversation, hidden: false)
+    mute = conversation_mutes.find_or_create_by!(conversation: conversation)
+    mute.update(hidden: hidden) if mute.hidden? != hidden
+    mute
   end
 
   def block_domain!(other_domain)
@@ -172,6 +173,15 @@ module AccountInteractions
     block&.destroy
   end
 
+  def mute_status!(status)
+    status_mutes.find_or_create_by!(status: status)
+  end
+
+  def unmute_status!(status)
+    mute = status_mutes.find_by(status: status)
+    mute&.destroy
+  end
+
   def following?(other_account)
     active_relationships.where(target_account: other_account).exists?
   end
@@ -192,6 +202,10 @@ module AccountInteractions
     conversation_mutes.where(conversation: conversation).exists?
   end
 
+  def hiding_conversation?(conversation)
+    conversation_mutes.where(conversation: conversation, hidden: true).exists?
+  end
+
   def muting_notifications?(other_account)
     mute_relationships.where(target_account: other_account, hide_notifications: true).exists?
   end
@@ -200,6 +214,10 @@ module AccountInteractions
     active_relationships.where(target_account: other_account, show_reblogs: false).exists?
   end
 
+  def muting_status?(status)
+    status_mutes.where(status: status).exists?
+  end
+
   def requested?(other_account)
     follow_requests.where(target_account: other_account).exists?
   end
diff --git a/app/models/conversation.rb b/app/models/conversation.rb
index 4dfaea889..bbe3ada31 100644
--- a/app/models/conversation.rb
+++ b/app/models/conversation.rb
@@ -13,6 +13,7 @@ class Conversation < ApplicationRecord
   validates :uri, uniqueness: true, if: :uri?
 
   has_many :statuses
+  has_many :mutes, class_name: 'ConversationMute', inverse_of: :conversation, dependent: :destroy
 
   def local?
     uri.nil?
diff --git a/app/models/conversation_mute.rb b/app/models/conversation_mute.rb
index 52c1a33e0..5d56a3172 100644
--- a/app/models/conversation_mute.rb
+++ b/app/models/conversation_mute.rb
@@ -6,9 +6,10 @@
 #  id              :bigint(8)        not null, primary key
 #  conversation_id :bigint(8)        not null
 #  account_id      :bigint(8)        not null
+#  hidden          :boolean          default(FALSE), not null
 #
 
 class ConversationMute < ApplicationRecord
-  belongs_to :account
-  belongs_to :conversation
+  belongs_to :account, inverse_of: :conversation_mutes
+  belongs_to :conversation, inverse_of: :mutes
 end
diff --git a/app/models/status.rb b/app/models/status.rb
index b94aad633..74012c22e 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -69,6 +69,9 @@ class Status < ApplicationRecord
   has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status
   has_many :media_attachments, dependent: :nullify
 
+  has_many :mutes, class_name: 'StatusMute', inverse_of: :status, dependent: :destroy
+  belongs_to :conversation_mute, primary_key: 'conversation_id', foreign_key: 'conversation_id', inverse_of: :conversation, dependent: :destroy, optional: true
+
   has_and_belongs_to_many :tags
   has_and_belongs_to_many :preview_cards
 
@@ -120,6 +123,10 @@ class Status < ApplicationRecord
   scope :unpublished, -> { rewhere(published: false) }
   scope :published, -> { where(published: true) }
 
+  scope :not_hidden_by_account, ->(account) do
+    left_outer_joins(:mutes, :conversation_mute).where('(status_mutes.account_id IS NULL OR status_mutes.account_id != ?) AND (conversation_mutes.account_id IS NULL OR (conversation_mutes.account_id != ? AND conversation_mutes.hidden = TRUE))', account.id, account.id)
+  end
+
   cache_associated :application,
                    :media_attachments,
                    :conversation,
@@ -371,6 +378,14 @@ class Status < ApplicationRecord
       ConversationMute.select('conversation_id').where(conversation_id: conversation_ids).where(account_id: account_id).each_with_object({}) { |m, h| h[m.conversation_id] = true }
     end
 
+    def hidden_conversations_map(conversation_ids, account_id)
+      ConversationMute.select('conversation_id').where(conversation_id: conversation_ids, hidden: true).where(account_id: account_id).each_with_object({}) { |m, h| h[m.conversation_id] = true }
+    end
+
+    def hidden_statuses_map(status_ids, account_id)
+      StatusMute.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |m, h| h[m.status_id] = true }
+    end
+
     def pins_map(status_ids, account_id)
       StatusPin.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |p, h| h[p.status_id] = true }
     end
@@ -411,9 +426,11 @@ class Status < ApplicationRecord
 
         scope = left_outer_joins(:reblog).published
 
-        scope.where(visibility: visibility)
-             .or(scope.where(id: account.mentions.select(:status_id)))
-             .merge(scope.where(reblog_of_id: nil).or(scope.where.not(reblogs_statuses: { account_id: account.excluded_from_timeline_account_ids })))
+        scope = scope.where(visibility: visibility)
+                     .or(scope.where(id: account.mentions.select(:status_id)))
+                     .merge(scope.where(reblog_of_id: nil).or(scope.where.not(reblogs_statuses: { account_id: account.excluded_from_timeline_account_ids })))
+
+        apply_timeline_filters(scope, account, false)
       end
     end
 
@@ -463,6 +480,7 @@ class Status < ApplicationRecord
       query = query.not_excluded_by_account(account)
       query = query.not_domain_blocked_by_account(account) unless local_only
       query = query.in_chosen_languages(account) if account.chosen_languages.present?
+      query = query.not_hidden_by_account(account)
       query.merge(account_silencing_filter(account))
     end
 
@@ -556,11 +574,11 @@ class Status < ApplicationRecord
   def set_nest_level
     return if attribute_changed?(:nest_level)
 
-    if reply?
-      self.nest_level = [thread&.account_id == account_id ? thread&.nest_level.to_i : thread&.nest_level.to_i + 1, 127].min
-    else
-      self.nest_level = 0
-    end
+    self.nest_level = if reply?
+                        [thread&.account_id == account_id ? thread&.nest_level.to_i : thread&.nest_level.to_i + 1, 127].min
+                      else
+                        0
+                      end
   end
 
   def update_statistics
diff --git a/app/models/status_mute.rb b/app/models/status_mute.rb
new file mode 100644
index 000000000..3bfd9d51f
--- /dev/null
+++ b/app/models/status_mute.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+# == Schema Information
+#
+# Table name: status_mutes
+#
+#  id         :bigint(8)        not null, primary key
+#  account_id :integer          not null
+#  status_id  :bigint(8)        not null
+#
+
+class StatusMute < ApplicationRecord
+  belongs_to :account, inverse_of: :status_mutes
+  belongs_to :status, inverse_of: :mutes
+end