diff --git a/app/assets/javascripts/discourse/templates/user/summary.hbs b/app/assets/javascripts/discourse/templates/user/summary.hbs
index 695cbf1c01..6d6a20b08f 100644
--- a/app/assets/javascripts/discourse/templates/user/summary.hbs
+++ b/app/assets/javascripts/discourse/templates/user/summary.hbs
@@ -115,6 +115,35 @@
{{/user-summary-section}}
+ {{#if model.top_categories.length}}
+
+ {{#user-summary-section title="top_categories" class="summary-category-list pull-left"}}
+
+
+ |
+ {{i18n "user.summary.topics"}} |
+ {{i18n "user.summary.replies"}} |
+
+
+ {{#each model.top_categories as |category|}}
+
+ |
+ {{category-link category allowUncategorized="true" hideParent=false}}
+ |
+
+ {{category.topic_count}}
+ |
+
+ {{category.post_count}}
+ |
+
+ {{/each}}
+
+
+ {{/user-summary-section}}
+
+ {{/if}}
+
{{#if siteSettings.enable_badges}}
{{i18n "user.summary.top_badges"}}
diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss
index 96a503612d..50e6b09f96 100644
--- a/app/assets/stylesheets/common/base/user.scss
+++ b/app/assets/stylesheets/common/base/user.scss
@@ -502,6 +502,23 @@
}
}
+.top-categories-section {
+ table {
+ max-width: 95%;
+ tr {
+ border: none;
+ }
+ td,
+ th {
+ padding: 0.5em;
+ &.topic-count,
+ &.reply-count {
+ text-align: center;
+ }
+ }
+ }
+}
+
.summary-user-list {
li {
height: 40px;
diff --git a/app/models/user_summary.rb b/app/models/user_summary.rb
index 6eb177382d..e75a53cd52 100644
--- a/app/models/user_summary.rb
+++ b/app/models/user_summary.rb
@@ -155,6 +155,56 @@ class UserSummary
@user.recent_time_read
end
+ class CategoryWithCounts < OpenStruct
+ include ActiveModel::SerializerSupport
+ KEYS = [:id, :name, :color, :text_color, :slug, :read_restricted, :parent_category_id]
+ end
+
+ def top_categories
+ post_count_query = Post
+ .joins(:topic)
+ .includes(:topic)
+ .secured(@guardian)
+ .merge(Topic.listable_topics.visible.secured(@guardian))
+ .where(user: @user)
+ .group('topics.category_id')
+ .order('COUNT(*) DESC')
+
+ top_categories = {}
+
+ Category.where(id: post_count_query.limit(MAX_SUMMARY_RESULTS).pluck('category_id'))
+ .pluck(:id, :name, :color, :text_color, :slug, :read_restricted, :parent_category_id)
+ .each do |c|
+ top_categories[c[0].to_i] = CategoryWithCounts.new(
+ Hash[CategoryWithCounts::KEYS.zip(c)].merge(
+ topic_count: 0,
+ post_count: 0
+ )
+ )
+ end
+
+ post_count_query.where('post_number > 1')
+ .where('topics.category_id in (?)', top_categories.keys)
+ .pluck('category_id, COUNT(*)')
+ .each do |r|
+ top_categories[r[0].to_i].post_count = r[1]
+ end
+
+ Topic.listable_topics.visible.secured(@guardian)
+ .where('topics.category_id in (?)', top_categories.keys)
+ .where(user: @user)
+ .group('topics.category_id')
+ .order('COUNT(*) DESC')
+ .pluck('category_id, COUNT(*)')
+ .each do |r|
+ top_categories[r[0].to_i].topic_count = r[1]
+ end
+
+ top_categories.values.sort_by do |r|
+ -(r[:post_count] + r[:topic_count])
+ end
+ end
+
delegate :likes_given,
:likes_received,
:days_visited,
diff --git a/app/serializers/user_summary_serializer.rb b/app/serializers/user_summary_serializer.rb
index c641843796..fcb5a00aeb 100644
--- a/app/serializers/user_summary_serializer.rb
+++ b/app/serializers/user_summary_serializer.rb
@@ -22,6 +22,12 @@ class UserSummarySerializer < ApplicationSerializer
attributes :count, :name
end
+ class CategoryWithCountsSerializer < ApplicationSerializer
+ attributes :topic_count, :post_count,
+ :id, :name, :color, :text_color, :slug,
+ :read_restricted, :parent_category_id
+ end
+
has_many :topics, serializer: TopicSerializer
has_many :replies, serializer: ReplySerializer, embed: :object
has_many :links, serializer: LinkSerializer, embed: :object
@@ -29,6 +35,7 @@ class UserSummarySerializer < ApplicationSerializer
has_many :most_liked_users, serializer: UserWithCountSerializer, embed: :object
has_many :most_replied_to_users, serializer: UserWithCountSerializer, embed: :object
has_many :badges, serializer: UserBadgeSerializer, embed: :object
+ has_many :top_categories, serializer: CategoryWithCountsSerializer, embed: :object
attributes :likes_given,
:likes_received,
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index c9fd0e40ec..b6a1dcce2d 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1004,7 +1004,9 @@ en:
most_liked_users: "Most Liked"
most_replied_to_users: "Most Replied To"
no_likes: "No likes yet."
-
+ top_categories: "Top Categories"
+ topics: "Topics"
+ replies: "Replies"
associated_accounts: "Logins"
ip_address:
diff --git a/spec/models/user_summary_spec.rb b/spec/models/user_summary_spec.rb
index 77e96a496d..4c0bfe779e 100644
--- a/spec/models/user_summary_spec.rb
+++ b/spec/models/user_summary_spec.rb
@@ -11,16 +11,21 @@ describe UserSummary do
expect(summary.topics.length).to eq(1)
expect(summary.replies.length).to eq(1)
+ expect(summary.top_categories.length).to eq(1)
+ expect(summary.top_categories.first[:topic_count]).to eq(1)
+ expect(summary.top_categories.first[:post_count]).to eq(1)
topic.update_columns(deleted_at: Time.now)
expect(summary.topics.length).to eq(0)
expect(summary.replies.length).to eq(0)
+ expect(summary.top_categories.length).to eq(0)
topic.update_columns(deleted_at: nil, visible: false)
expect(summary.topics.length).to eq(0)
expect(summary.replies.length).to eq(0)
+ expect(summary.top_categories.length).to eq(0)
category = Fabricate(:category)
topic.update_columns(category_id: category.id, deleted_at: nil, visible: true)
@@ -30,7 +35,7 @@ describe UserSummary do
expect(summary.topics.length).to eq(0)
expect(summary.replies.length).to eq(0)
-
+ expect(summary.top_categories.length).to eq(0)
end
end
diff --git a/test/javascripts/acceptance/user-test.js.es6 b/test/javascripts/acceptance/user-test.js.es6
index 05fe5885aa..2c841513f6 100644
--- a/test/javascripts/acceptance/user-test.js.es6
+++ b/test/javascripts/acceptance/user-test.js.es6
@@ -46,5 +46,9 @@ QUnit.test("Viewing Summary", assert => {
assert.ok(exists(".liked-by-section .user-info"), "liked by");
assert.ok(exists(".liked-section .user-info"), "liked");
assert.ok(exists(".badges-section .badge-card"), "badges");
+ assert.ok(
+ exists(".top-categories-section .category-link"),
+ "top categories"
+ );
});
});
diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6
index ef67ce445d..7fcd5269d2 100644
--- a/test/javascripts/helpers/create-pretender.js.es6
+++ b/test/javascripts/helpers/create-pretender.js.es6
@@ -88,7 +88,20 @@ export default function() {
most_replied_to_users: [{ id: 333 }],
most_liked_by_users: [{ id: 333 }],
most_liked_users: [{ id: 333 }],
- badges: [{ badge_id: 444 }]
+ badges: [{ badge_id: 444 }],
+ top_categories: [
+ {
+ id: 1,
+ name: "bug",
+ color: "e9dd00",
+ text_color: "000000",
+ slug: "bug",
+ read_restricted: false,
+ parent_category_id: null,
+ topic_count: 1,
+ post_count: 1
+ }
+ ]
},
badges: [{ id: 444, count: 1 }],
topics: [{ id: 1234, title: "cool title", url: "/t/1234/cool-title" }]