FIX: Hide post replies content for ignored users (#7320)

FIX: Hide post replies content for ignored users (#7320)

diff --git a/app/assets/javascripts/discourse/lib/transform-post.js.es6 b/app/assets/javascripts/discourse/lib/transform-post.js.es6
index e0d0866..7579e30 100644
--- a/app/assets/javascripts/discourse/lib/transform-post.js.es6
+++ b/app/assets/javascripts/discourse/lib/transform-post.js.es6
@@ -80,7 +80,6 @@ export function transformBasicPost(post) {
     expandablePost: false,
     replyCount: post.reply_count,
     locked: post.locked,
-    ignored: post.ignored,
     userCustomFields: post.user_custom_fields
   };
 
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index c8c0db7..55a5801 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -619,6 +619,15 @@ const User = RestModel.extend({
     return ajax(`${userPath(this.get("username"))}/notification_level.json`, {
       type: "PUT",
       data: { notification_level: level, expiring_at: expiringAt }
+    }).then(() => {
+      const currentUser = Discourse.User.current();
+      if (currentUser) {
+        if (level === "normal" || level === "mute") {
+          currentUser.ignored_users.removeObject(this.get("username"));
+        } else if (level === "ignore") {
+          currentUser.ignored_users.addObject(this.get("username"));
+        }
+      }
     });
   },
 
diff --git a/app/assets/javascripts/discourse/widgets/post-cooked.js.es6 b/app/assets/javascripts/discourse/widgets/post-cooked.js.es6
index 3309b29..44f2944 100644
--- a/app/assets/javascripts/discourse/widgets/post-cooked.js.es6
+++ b/app/assets/javascripts/discourse/widgets/post-cooked.js.es6
@@ -17,6 +17,8 @@ export default class PostCooked {
     this.expanding = false;
     this._highlighted = false;
     this.decoratorHelper = decoratorHelper;
+    this.currentUser = decoratorHelper.widget.currentUser;
+    this.ignoredUsers = this.currentUser ? this.currentUser.ignored_users : null;
   }
 
   update(prev) {
@@ -29,7 +31,7 @@ export default class PostCooked {
   }
 
   init() {
-    const $html = $(`<div class='cooked'>${this.attrs.cooked}</div>`);
+    const $html = this._computeCooked();
     this._insertQuoteControls($html);
     this._showLinkCounts($html);
     this._fixImageSizes($html);
@@ -212,6 +214,16 @@ export default class PostCooked {
       expandContract = iconHTML(desc, { title: "post.expand_collapse" });
       $(".title", $aside).css("cursor", "pointer");
     }
+    if (this.ignoredUsers && this.ignoredUsers.length > 0) {
+      const username = $aside
+        .find(".title")
+        .text()
+        .trim()
+        .slice(0, -1);
+      if (username.length > 0 && this.ignoredUsers.includes(username)) {
+        $aside.find("p").replaceWith(`<i>${I18n.t("post.ignored")}</i>`);
+      }
+    }
     $(".quote-controls", $aside).html(expandContract + navLink);
   }
 
@@ -241,6 +253,20 @@ export default class PostCooked {
       }
     });
   }
+
+  _computeCooked() {
+    if (
+      this.ignoredUsers &&
+      this.ignoredUsers.length > 0 &&
+      this.ignoredUsers.includes(this.attrs.username)
+    ) {
+      return $(
+        `<div class='cooked post-ignored'>${I18n.t("post.ignored")}</div>`
+      );
+    }
+
+    return $(`<div class='cooked'>${this.attrs.cooked}</div>`);
+  }
 }
 
 PostCooked.prototype.type = "Widget";
diff --git a/app/assets/javascripts/discourse/widgets/post.js.es6 b/app/assets/javascripts/discourse/widgets/post.js.es6
index 77f3f31..14e1a46 100644
--- a/app/assets/javascripts/discourse/widgets/post.js.es6
+++ b/app/assets/javascripts/discourse/widgets/post.js.es6
@@ -657,7 +657,12 @@ export default createWidget("post", {
     } else {
       classNames.push("regular");
     }
-    if (attrs.ignored) {
+    if (
+      this.currentUser &&
+      this.currentUser.ignored_users &&
+      this.currentUser.ignored_users.length > 0 &&
+      this.currentUser.ignored_users.includes(attrs.username)
+    ) {
       classNames.push("post-ignored");
     }
     if (addPostClassesCallbacks) {
diff --git a/app/serializers/basic_post_serializer.rb b/app/serializers/basic_post_serializer.rb
index ce2a5fe..bcc75f7 100644
--- a/app/serializers/basic_post_serializer.rb
+++ b/app/serializers/basic_post_serializer.rb
@@ -6,8 +6,7 @@ class BasicPostSerializer < ApplicationSerializer
              :avatar_template,
              :created_at,
              :cooked,
-             :cooked_hidden,
-             :ignored
+             :cooked_hidden
 
   def name
     object.user && object.user.name
@@ -36,21 +35,11 @@ class BasicPostSerializer < ApplicationSerializer
       else
         I18n.t('flagging.user_must_edit')
       end
-    elsif ignored
-      I18n.t('ignored.hidden_content')
     else
       object.filter_quotes(@parent_post)
     end
   end
 
-  def ignored
-    return false unless SiteSetting.ignore_user_enabled?
-    object.is_first_post? &&
-      scope.current_user&.id != object.user_id &&
-      IgnoredUser.where(user_id: scope.current_user&.id,
-                        ignored_user_id: object.user_id).exists?
-  end
-
   def include_name?
     SiteSetting.enable_names?
   end
diff --git a/app/serializers/current_user_serializer.rb b/app/serializers/current_user_serializer.rb
index 39aff70..7e6ddb0 100644
--- a/app/serializers/current_user_serializer.rb
+++ b/app/serializers/current_user_serializer.rb
@@ -42,7 +42,8 @@ class CurrentUserSerializer < BasicUserSerializer
              :top_category_ids,
              :hide_profile_and_presence,
              :groups,
-             :second_factor_enabled
+             :second_factor_enabled,
+             :ignored_users
 
   def groups
     object.visible_groups.pluck(:id, :name).map { |id, name| { id: id, name: name.downcase } }
@@ -157,6 +158,10 @@ class CurrentUserSerializer < BasicUserSerializer
     CategoryUser.lookup(object, :muted).pluck(:category_id)
   end
 
+  def ignored_users
+    IgnoredUser.where(user: object.id).joins(:ignored_user).pluck(:username)
+  end
+
   def top_category_ids
     omitted_notification_levels = [CategoryUser.notification_levels[:muted], CategoryUser.notification_levels[:regular]]
     CategoryUser.where(user_id: object.id)
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 01cdc9a..f3565fb 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2247,6 +2247,7 @@ en:
       quote_reply: "Quote"
       edit_reason: "Reason: "
       post_number: "post {{number}}"
+      ignored: "Hidden content"
       wiki_last_edited_on: "wiki last edited on"
       last_edited_on: "post last edited on"
       reply_as_new_topic: "Reply as linked Topic"
diff --git a/spec/serializers/web_hook_post_serializer_spec.rb b/spec/serializers/web_hook_post_serializer_spec.rb
index eabc42b..2d56df3 100644
--- a/spec/serializers/web_hook_post_serializer_spec.rb
+++ b/spec/serializers/web_hook_post_serializer_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe WebHookPostSerializer do
 
   it 'should only include the required keys' do
     count = serialized_for_user(admin).keys.count
-    difference = count - 35
+    difference = count - 34
 
     expect(difference).to eq(0), lambda {
       message = ""

GitHub sha: 131eba03