From 190b19f3c269637ecfd84c58400d0f2bfdeb2af8 Mon Sep 17 00:00:00 2001
From: Tarek Khalil <45508821+khalilovcmded@users.noreply.github.com>
Date: Tue, 5 Mar 2019 14:47:51 +0000
Subject: [PATCH] FEATURE: Add ignored user list to the User's preference page
 (#7107)

* FEATURE: Add ignored user list to the User's preference page

## Why?

Part of: https://meta.discourse.org/t/ability-to-ignore-a-user/110254

We want to add list of Ignored users under or along with the muted users preferences section.
This way Users can find and update their list of ignored users.

## UI


![gif](https://user-images.githubusercontent.com/45508821/53746179-8e9b3c00-3e98-11e9-9e90-94b8520896a6.gif)

## Open questions

Two of many options to represent a list of ignored users is that we can:

1. We can represent the ignored user list as a table with the ability to `un-ignore` but NOT to add new ignored users.
2. We can keep it functioning as the `muted user list` where you can `un-ignore` or `ignore` users.
---
 .../controllers/preferences/users.js.es6      | 16 ++++++++++
 .../discourse/routes/app-route-map.js.es6     |  1 +
 .../discourse/routes/preferences-users.js.es6 |  5 ++++
 .../discourse/templates/preferences.hbs       |  5 ++++
 .../templates/preferences/notifications.hbs   |  9 ------
 .../discourse/templates/preferences/users.hbs | 29 +++++++++++++++++++
 app/serializers/user_serializer.rb            |  5 ++++
 config/locales/client.en.yml                  |  3 ++
 config/routes.rb                              |  1 +
 config/site_settings.yml                      |  1 +
 .../javascripts/fixtures/user_fixtures.js.es6 |  1 +
 11 files changed, 67 insertions(+), 9 deletions(-)
 create mode 100644 app/assets/javascripts/discourse/controllers/preferences/users.js.es6
 create mode 100644 app/assets/javascripts/discourse/routes/preferences-users.js.es6
 create mode 100644 app/assets/javascripts/discourse/templates/preferences/users.hbs

diff --git a/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/users.js.es6
new file mode 100644
index 00000000000..7ecb891f1f7
--- /dev/null
+++ b/app/assets/javascripts/discourse/controllers/preferences/users.js.es6
@@ -0,0 +1,16 @@
+import PreferencesTabController from "discourse/mixins/preferences-tab-controller";
+import { popupAjaxError } from "discourse/lib/ajax-error";
+
+export default Ember.Controller.extend(PreferencesTabController, {
+  saveAttrNames: ["muted_usernames", "ignored_usernames"],
+
+  actions: {
+    save() {
+      this.set("saved", false);
+      return this.get("model")
+        .save(this.get("saveAttrNames"))
+        .then(() => this.set("saved", true))
+        .catch(popupAjaxError);
+    }
+  }
+});
diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
index 160a72938bb..b9fc992d74b 100644
--- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6
+++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
@@ -147,6 +147,7 @@ export default function() {
         this.route("emails");
         this.route("notifications");
         this.route("categories");
+        this.route("users");
         this.route("tags");
         this.route("interface");
         this.route("apps");
diff --git a/app/assets/javascripts/discourse/routes/preferences-users.js.es6 b/app/assets/javascripts/discourse/routes/preferences-users.js.es6
new file mode 100644
index 00000000000..713d79e4207
--- /dev/null
+++ b/app/assets/javascripts/discourse/routes/preferences-users.js.es6
@@ -0,0 +1,5 @@
+import RestrictedUserRoute from "discourse/routes/restricted-user";
+
+export default RestrictedUserRoute.extend({
+  showFooter: true
+});
diff --git a/app/assets/javascripts/discourse/templates/preferences.hbs b/app/assets/javascripts/discourse/templates/preferences.hbs
index e714afba84b..82712f60260 100644
--- a/app/assets/javascripts/discourse/templates/preferences.hbs
+++ b/app/assets/javascripts/discourse/templates/preferences.hbs
@@ -25,6 +25,11 @@
         {{i18n 'user.preferences_nav.categories'}}
       {{/link-to}}
     </li>
+    <li class='indent nav-users'>
+      {{#link-to 'preferences.users'}}
+        {{i18n 'user.preferences_nav.users'}}
+      {{/link-to}}
+    </li>
     {{#if siteSettings.tagging_enabled}}
       <li class='indent nav-tags'>
         {{#link-to 'preferences.tags'}}
diff --git a/app/assets/javascripts/discourse/templates/preferences/notifications.hbs b/app/assets/javascripts/discourse/templates/preferences/notifications.hbs
index d4d258c748d..5c06984a876 100644
--- a/app/assets/javascripts/discourse/templates/preferences/notifications.hbs
+++ b/app/assets/javascripts/discourse/templates/preferences/notifications.hbs
@@ -39,15 +39,6 @@
   </div>
 {{/if}}
 
-<div class="control-group muting">
-  <label class="control-label">{{i18n 'user.users'}}</label>
-  <div class="controls category-controls">
-    <label>{{d-icon "d-muted" class="muted icon"}} {{i18n 'user.muted_users'}}</label>
-    {{user-selector excludeCurrentUser=true usernames=model.muted_usernames class="user-selector"}}
-  </div>
-  <div class="instructions">{{i18n 'user.muted_users_instructions'}}</div>
-</div>
-
 {{plugin-outlet name="user-preferences-notifications" args=(hash model=model save=(action "save"))}}
 
 <br/>
diff --git a/app/assets/javascripts/discourse/templates/preferences/users.hbs b/app/assets/javascripts/discourse/templates/preferences/users.hbs
new file mode 100644
index 00000000000..7249b6140a4
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/preferences/users.hbs
@@ -0,0 +1,29 @@
+<div class="control-group muting">
+  <label class="control-label">{{i18n 'user.users'}}</label>
+  <div class="controls category-controls">
+    <label>{{d-icon "d-muted" class="``icon"}} {{i18n 'user.muted_users'}}</label>
+    {{user-selector excludeCurrentUser=true usernames=model.muted_usernames class="user-selector"}}
+  </div>
+  <div class="instructions">{{i18n 'user.muted_users_instructions'}}</div>
+
+  {{#if siteSettings.ignore_user_enabled}}
+    <div class="controls category-controls">
+      <label>{{d-icon "eye-slash" class="icon"}} {{i18n 'user.ignored_users'}}</label>
+      {{user-selector excludeCurrentUser=true
+                      usernames=model.ignored_usernames class="user-selector"}}
+    </div>
+    <div class="instructions">{{i18n 'user.ignored_users_instructions'}}</div>
+  {{/if}}
+</div>
+
+{{plugin-outlet name="user-preferences-notifications" args=(hash model=model save=(action "save"))}}
+
+<br/>
+
+{{plugin-outlet name="user-custom-controls" args=(hash model=model)}}
+
+<div class="control-group save-button">
+  <div class="controls">
+    {{partial 'user/preferences/save-button'}}
+  </div>
+</div>
diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb
index 7f30eadbb0c..b4de993b2ca 100644
--- a/app/serializers/user_serializer.rb
+++ b/app/serializers/user_serializer.rb
@@ -112,6 +112,7 @@ class UserSerializer < BasicUserSerializer
                      :custom_avatar_template,
                      :has_title_badges,
                      :muted_usernames,
+                     :ignored_usernames,
                      :mailing_list_posts_per_day,
                      :can_change_bio,
                      :user_api_keys,
@@ -377,6 +378,10 @@ class UserSerializer < BasicUserSerializer
     MutedUser.where(user_id: object.id).joins(:muted_user).pluck(:username)
   end
 
+  def ignored_usernames
+    IgnoredUser.where(user_id: object.id).joins(:ignored_user).pluck(:username)
+  end
+
   def include_private_messages_stats?
     can_edit && !(omit_stats == true)
   end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index a7524bf5d5a..e2dfc29843d 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -722,6 +722,8 @@ en:
       users: "Users"
       muted_users: "Muted"
       muted_users_instructions: "Suppress all notifications from these users."
+      ignored_users: "Ignored"
+      ignored_users_instructions: "Lists all your ignored users."
       muted_topics_link: "Show muted topics"
       watched_topics_link: "Show watched topics"
       tracked_topics_link: "Show tracked topics"
@@ -761,6 +763,7 @@ en:
         emails: "Emails"
         notifications: "Notifications"
         categories: "Categories"
+        users: "Users"
         tags: "Tags"
         interface: "Interface"
         apps: "Apps"
diff --git a/config/routes.rb b/config/routes.rb
index 392400fcc13..49e7f26d1dd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -403,6 +403,7 @@ Discourse::Application.routes.draw do
     get "#{root_path}/:username/preferences/emails" => "users#preferences", constraints: { username: RouteFormat.username }
     get "#{root_path}/:username/preferences/notifications" => "users#preferences", constraints: { username: RouteFormat.username }
     get "#{root_path}/:username/preferences/categories" => "users#preferences", constraints: { username: RouteFormat.username }
+    get "#{root_path}/:username/preferences/users" => "users#preferences", constraints: { username: RouteFormat.username }
     get "#{root_path}/:username/preferences/tags" => "users#preferences", constraints: { username: RouteFormat.username }
     get "#{root_path}/:username/preferences/interface" => "users#preferences", constraints: { username: RouteFormat.username }
     get "#{root_path}/:username/preferences/apps" => "users#preferences", constraints: { username: RouteFormat.username }
diff --git a/config/site_settings.yml b/config/site_settings.yml
index ed2aedae39b..2acedd3ec46 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -532,6 +532,7 @@ users:
   ignore_user_enabled:
     hidden: true
     default: false
+    client: true
 
 groups:
   enable_group_directory:
diff --git a/test/javascripts/fixtures/user_fixtures.js.es6 b/test/javascripts/fixtures/user_fixtures.js.es6
index 0ac8d77bfdd..51df0412233 100644
--- a/test/javascripts/fixtures/user_fixtures.js.es6
+++ b/test/javascripts/fixtures/user_fixtures.js.es6
@@ -189,6 +189,7 @@ export default {
       card_image_badge: "/images/avatar.png",
       card_image_badge_id: 120,
       muted_usernames: [],
+      ignored_usernames: [],
       invited_by: {
         id: 1,
         username: "sam",