FEATURE: add a Top Categories section to the user summary page, showing the categories in which a user has the most activity
This commit is contained in:
parent
2dc3a50dac
commit
afc94ac9e4
|
@ -115,6 +115,35 @@
|
|||
{{/user-summary-section}}
|
||||
</div>
|
||||
|
||||
{{#if model.top_categories.length}}
|
||||
<div class='top-section top-categories-section'>
|
||||
{{#user-summary-section title="top_categories" class="summary-category-list pull-left"}}
|
||||
<table>
|
||||
<thead>
|
||||
<th class="category-link"></th>
|
||||
<th class='topic-count'>{{i18n "user.summary.topics"}}</th>
|
||||
<th class='reply-count'>{{i18n "user.summary.replies"}}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each model.top_categories as |category|}}
|
||||
<tr>
|
||||
<td class="category-link">
|
||||
{{category-link category allowUncategorized="true" hideParent=false}}
|
||||
</td>
|
||||
<td class='topic-count'>
|
||||
{{category.topic_count}}
|
||||
</td>
|
||||
<td class='reply-count'>
|
||||
{{category.post_count}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/user-summary-section}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if siteSettings.enable_badges}}
|
||||
<div class='top-section badges-section'>
|
||||
<h3 class='stats-title'>{{i18n "user.summary.top_badges"}}</h3>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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" }]
|
||||
|
|
Loading…
Reference in New Issue