From afc94ac9e40b10f6806fbe7beb173446b2abd83c Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Wed, 18 Jul 2018 16:37:50 -0400 Subject: [PATCH] FEATURE: add a Top Categories section to the user summary page, showing the categories in which a user has the most activity --- .../discourse/templates/user/summary.hbs | 29 +++++++++++ app/assets/stylesheets/common/base/user.scss | 17 +++++++ app/models/user_summary.rb | 50 +++++++++++++++++++ app/serializers/user_summary_serializer.rb | 7 +++ config/locales/client.en.yml | 4 +- spec/models/user_summary_spec.rb | 7 ++- test/javascripts/acceptance/user-test.js.es6 | 4 ++ .../helpers/create-pretender.js.es6 | 15 +++++- 8 files changed, 130 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/user/summary.hbs b/app/assets/javascripts/discourse/templates/user/summary.hbs index 695cbf1c013..6d6a20b08fd 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"}} + + + + + + + + {{#each model.top_categories as |category|}} + + + + + + {{/each}} + +
{{i18n "user.summary.topics"}}{{i18n "user.summary.replies"}}
+ {{category.topic_count}} + + {{category.post_count}} +
+ {{/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 96a503612da..50e6b09f96e 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 6eb177382d0..e75a53cd52d 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 c641843796b..fcb5a00aeb7 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 c9fd0e40ecf..b6a1dcce2dc 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 77e96a496d4..4c0bfe779e5 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 05fe5885aa6..2c841513f6f 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 ef67ce445da..7fcd5269d2e 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" }]