From e3eaa7fa7554fc8db9a43bc38c761b5c989e6567 Mon Sep 17 00:00:00 2001
From: Robin Ward <robin.ward@gmail.com>
Date: Tue, 24 Mar 2015 12:33:17 -0400
Subject: [PATCH] FIX: In long topics, filtering button was not always showing
 in card

---
 .../discourse/controllers/user-card.js.es6    | 45 ++++++++++---------
 .../javascripts/discourse/models/user.js.es6  |  9 +---
 .../discourse/templates/user-card.hbs         |  2 +-
 app/controllers/users_controller.rb           |  5 +++
 app/serializers/user_serializer.rb            | 10 ++++-
 5 files changed, 40 insertions(+), 31 deletions(-)

diff --git a/app/assets/javascripts/discourse/controllers/user-card.js.es6 b/app/assets/javascripts/discourse/controllers/user-card.js.es6
index 21c96e64600..60922c4c152 100644
--- a/app/assets/javascripts/discourse/controllers/user-card.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-card.js.es6
@@ -5,14 +5,16 @@ export default ObjectController.extend({
   visible: false,
   user: null,
   username: null,
-  participant: null,
   avatar: null,
   userLoading: null,
   cardTarget: null,
   post: null,
 
+  // If inside a topic
+  topicPostCount: null,
+
   postStream: Em.computed.alias('controllers.topic.postStream'),
-  enoughPostsForFiltering: Em.computed.gte('participant.post_count', 2),
+  enoughPostsForFiltering: Em.computed.gte('topicPostCount', 2),
   viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./),
   viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./),
   showFilter: Em.computed.and('viewingTopic', 'postStream.hasNoFilters', 'enoughPostsForFiltering'),
@@ -28,14 +30,14 @@ export default ObjectController.extend({
   }.property('user.badge_count', 'user.featured_user_badges.@each'),
 
   hasCardBadgeImage: function() {
-    var img = this.get('user.card_badge.image');
+    const img = this.get('user.card_badge.image');
     return img && img.indexOf('fa-') !== 0;
   }.property('user.card_badge.image'),
 
-  show: function(username, postId, target) {
+  show(username, postId, target) {
     // XSS protection (should be encapsulated)
     username = username.toString().replace(/[^A-Za-z0-9_]/g, "");
-    var url = "/users/" + username;
+    const url = "/users/" + username;
 
     // Don't show on mobile
     if (Discourse.Mobile.mobileView) {
@@ -43,7 +45,7 @@ export default ObjectController.extend({
       return;
     }
 
-    var currentUsername = this.get('username'),
+    const currentUsername = this.get('username'),
         wasVisible = this.get('visible'),
         post = this.get('viewingTopic') && postId ? this.get('controllers.topic.postStream').findLoadedPost(postId) : null;
 
@@ -60,20 +62,21 @@ export default ObjectController.extend({
       return;
     }
 
-    this.set('participant', null);
-
-    // Retrieve their participants info
-    var participants = this.get('controllers.topic.details.participants');
-    if (participants) {
-      this.set('participant', participants.findBy('username', username));
-    }
+    this.set('topicPostCount', null);
 
     this.setProperties({ user: null, userLoading: username, cardTarget: target });
 
-    var self = this;
-    return Discourse.User.findByUsername(username, { stats: false }).then(function(user) {
+    const args = { stats: false };
+    args.include_post_count_for = this.get('controllers.topic.id');
+
+    const self = this;
+    return Discourse.User.findByUsername(username, args).then(function(user) {
+
+      if (user.topic_post_count) {
+        self.set('topicPostCount', user.topic_post_count[args.include_post_count_for]);
+      }
       user = Discourse.User.create(user);
-      self.setProperties({ user: user, avatar: user, visible: true});
+      self.setProperties({ user, avatar: user, visible: true});
       self.appEvents.trigger('usercard:shown');
     }).catch(function(error) {
       self.close();
@@ -83,19 +86,19 @@ export default ObjectController.extend({
     });
   },
 
-  close: function() {
+  close() {
     this.setProperties({ visible: false, cardTarget: null });
   },
 
   actions: {
-    togglePosts: function(user) {
-      var postStream = this.get('controllers.topic.postStream');
+    togglePosts(user) {
+      const postStream = this.get('controllers.topic.postStream');
       postStream.toggleParticipant(user.get('username'));
       this.close();
     },
 
-    cancelFilter: function() {
-      var postStream = this.get('postStream');
+    cancelFilter() {
+      const postStream = this.get('postStream');
       postStream.cancelFilter();
       postStream.refresh();
       this.close();
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index dc5df8c2269..b458c11888c 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -427,14 +427,9 @@ const User = Discourse.Model.extend({
 
 User.reopenClass(Discourse.Singleton, {
 
-  /**
-    Find a `Discourse.User` for a given username.
-
-    @method findByUsername
-    @returns {Promise} a promise that resolves to a `Discourse.User`
-  **/
+  // Find a `Discourse.User` for a given username.
   findByUsername: function(username, options) {
-    var user = Discourse.User.create({username: username});
+    const user = Discourse.User.create({username: username});
     return user.findDetails(options);
   },
 
diff --git a/app/assets/javascripts/discourse/templates/user-card.hbs b/app/assets/javascripts/discourse/templates/user-card.hbs
index 1db3b3f3281..588da54eb0d 100644
--- a/app/assets/javascripts/discourse/templates/user-card.hbs
+++ b/app/assets/javascripts/discourse/templates/user-card.hbs
@@ -28,7 +28,7 @@
     {{/if}}
 
     {{#if showFilter}}
-      <li><a class='btn' {{action "togglePosts" user}}>{{fa-icon "filter"}}{{i18n 'topic.filter_to' username=username post_count=participant.post_count}}</a></li>
+      <li><a class='btn' {{action "togglePosts" user}}>{{fa-icon "filter"}}{{i18n 'topic.filter_to' username=username post_count=topicPostCount}}</a></li>
     {{/if}}
 
     {{#if hasUserFilters}}
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 5f9277d1213..a6950cbaafe 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -34,6 +34,11 @@ class UsersController < ApplicationController
     if params[:stats].to_s == "false"
       user_serializer.omit_stats = true
     end
+    topic_id = params[:include_post_count_for].to_i
+    if topic_id != 0
+      user_serializer.topic_post_count = {topic_id => Post.where(topic_id: topic_id, user_id: @user.id).count }
+    end
+
     respond_to do |format|
       format.html do
         @restrict_fields = guardian.restrict_user_fields?(@user)
diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb
index 37d42599c88..350b0262018 100644
--- a/app/serializers/user_serializer.rb
+++ b/app/serializers/user_serializer.rb
@@ -1,6 +1,7 @@
 class UserSerializer < BasicUserSerializer
 
-  attr_accessor :omit_stats
+  attr_accessor :omit_stats,
+                :topic_post_count
 
   def self.staff_attributes(*attrs)
     attributes(*attrs)
@@ -62,7 +63,8 @@ class UserSerializer < BasicUserSerializer
              :has_title_badges,
              :edit_history_public,
              :custom_fields,
-             :user_fields
+             :user_fields,
+             :topic_post_count
 
   has_one :invited_by, embed: :object, serializer: BasicUserSerializer
   has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer
@@ -293,6 +295,10 @@ class UserSerializer < BasicUserSerializer
     user_fields.present?
   end
 
+  def include_topic_post_count?
+    topic_post_count.present?
+  end
+
   def custom_fields
     fields = nil