FEATURE: reorder participants in topic so always chronological

FEATURE: tie breaker for same number of posts is last post date
UX: highlight for latest poster when it is OP
This commit is contained in:
Sam 2015-04-06 17:27:05 +10:00
parent 0fcb98c80a
commit c6a5081763
7 changed files with 33 additions and 43 deletions

View File

@ -108,7 +108,16 @@
} }
} }
} }
.posters a:first-child .avatar.latest:not(.single) {
box-shadow: 0 0 3px 1px desaturate(scale-color($tertiary, $lightness: 65%), 35%);
border: 2px solid desaturate(scale-color($tertiary, $lightness: 50%), 40%);
position: relative;
top: -2px;
left: -2px;
}
.sortable { .sortable {
cursor: pointer; cursor: pointer;
&:hover { &:hover {

View File

@ -43,6 +43,7 @@ class PostMover
update_user_actions update_user_actions
set_last_post_user_id(destination_topic) set_last_post_user_id(destination_topic)
destination_topic.reload
destination_topic destination_topic
end end

View File

@ -11,10 +11,8 @@ class TopicFeaturedUsers
# Chooses which topic users to feature # Chooses which topic users to feature
def choose(args={}) def choose(args={})
clear self.class.ensure_consistency!(topic.id.to_i)
update keys(args)
update_participant_count update_participant_count
topic.save
end end
def user_ids def user_ids
@ -24,19 +22,29 @@ class TopicFeaturedUsers
topic.featured_user4_id].uniq.compact topic.featured_user4_id].uniq.compact
end end
def self.ensure_consistency! def self.ensure_consistency!(topic_id=nil)
sql = <<SQL sql = <<SQL
WITH cte as ( WITH cte as (
SELECT SELECT
t.id, p.user_id, t.id,
ROW_NUMBER() OVER(PARTITION BY t.id ORDER BY COUNT(*) DESC) as rank p.user_id,
MAX(p.created_at) last_post_date,
ROW_NUMBER() OVER(PARTITION BY t.id ORDER BY COUNT(*) DESC, MAX(p.created_at) DESC) as rank
FROM topics t FROM topics t
JOIN posts p ON p.topic_id = t.id JOIN posts p ON p.topic_id = t.id
WHERE p.deleted_at IS NULL AND NOT p.hidden AND p.user_id <> t.user_id AND WHERE p.deleted_at IS NULL AND
NOT p.hidden AND
p.user_id <> t.user_id AND
p.user_id <> t.last_post_user_id p.user_id <> t.last_post_user_id
GROUP BY t.id, p.user_id GROUP BY t.id, p.user_id
),
cte2 as (
SELECT id, user_id, ROW_NUMBER() OVER(PARTITION BY id ORDER BY last_post_date ASC) as rank
FROM cte
WHERE rank <= #{count}
) )
UPDATE topics tt UPDATE topics tt
@ -52,8 +60,7 @@ FROM (
MAX(case when c.rank = 2 then c.user_id end) featured_user2, MAX(case when c.rank = 2 then c.user_id end) featured_user2,
MAX(case when c.rank = 3 then c.user_id end) featured_user3, MAX(case when c.rank = 3 then c.user_id end) featured_user3,
MAX(case when c.rank = 4 then c.user_id end) featured_user4 MAX(case when c.rank = 4 then c.user_id end) featured_user4
FROM cte as c FROM cte2 as c
WHERE c.rank <= 4
GROUP BY c.id GROUP BY c.id
) x ) x
WHERE x.id = tt.id AND WHERE x.id = tt.id AND
@ -62,7 +69,7 @@ WHERE x.id = tt.id AND
COALESCE(featured_user2_id,-99) <> COALESCE(featured_user2,-99) OR COALESCE(featured_user2_id,-99) <> COALESCE(featured_user2,-99) OR
COALESCE(featured_user3_id,-99) <> COALESCE(featured_user3,-99) OR COALESCE(featured_user3_id,-99) <> COALESCE(featured_user3,-99) OR
COALESCE(featured_user4_id,-99) <> COALESCE(featured_user4,-99) COALESCE(featured_user4_id,-99) <> COALESCE(featured_user4,-99)
) ) #{"AND x.id = #{topic_id.to_i}" if topic_id}
SQL SQL
Topic.exec_sql(sql) Topic.exec_sql(sql)
@ -70,30 +77,7 @@ SQL
private private
def keys(args)
# Don't include the OP or the last poster
to_feature = topic.posts.where('user_id NOT IN (?, ?)', topic.user_id, topic.last_post_user_id)
# Exclude a given post if supplied (in the case of deletes)
to_feature = to_feature.where("id <> ?", args[:except_post_id]) if args[:except_post_id].present?
# Assign the featured_user{x} columns
to_feature.group(:user_id).order('count_all desc').limit(TopicFeaturedUsers.count).count.keys
end
def clear
TopicFeaturedUsers.count.times do |i|
topic.send("featured_user#{i+1}_id=", nil)
end
end
def update(user_keys)
user_keys.each_with_index do |user_id, i|
topic.send("featured_user#{i+1}_id=", user_id)
end
end
def update_participant_count def update_participant_count
topic.participant_count = topic.posts.count('distinct user_id') topic.update_columns(participant_count: topic.posts.count('distinct user_id'))
end end
end end

View File

@ -19,6 +19,7 @@ class PostOwnerChanger
@topic.update_statistics @topic.update_statistics
@new_owner.user_stat.update(first_post_created_at: @new_owner.posts(true).order('created_at ASC').first.try(:created_at)) @new_owner.user_stat.update(first_post_created_at: @new_owner.posts(true).order('created_at ASC').first.try(:created_at))
@topic.save!
end end
end end
end end

View File

@ -72,7 +72,6 @@ class PostDestroyer
if @post.topic if @post.topic
make_previous_post_the_last_one make_previous_post_the_last_one
clear_user_posted_flag clear_user_posted_flag
feature_users_in_the_topic
Topic.reset_highest(@post.topic_id) Topic.reset_highest(@post.topic_id)
end end
trash_public_post_actions trash_public_post_actions
@ -92,6 +91,7 @@ class PostDestroyer
TopicUser.update_post_action_cache(topic_id: @post.topic_id) TopicUser.update_post_action_cache(topic_id: @post.topic_id)
end end
feature_users_in_the_topic if @post.topic
@post.publish_change_to_clients! :deleted if @post.topic @post.publish_change_to_clients! :deleted if @post.topic
end end
@ -136,7 +136,7 @@ class PostDestroyer
end end
def feature_users_in_the_topic def feature_users_in_the_topic
Jobs.enqueue(:feature_topic_users, topic_id: @post.topic_id, except_post_id: @post.id) Jobs.enqueue(:feature_topic_users, topic_id: @post.topic_id)
end end
def trash_public_post_actions def trash_public_post_actions

View File

@ -291,7 +291,7 @@ describe PostDestroyer do
let!(:post) { Fabricate(:post, raw: "Hello @CodingHorror") } let!(:post) { Fabricate(:post, raw: "Hello @CodingHorror") }
it "should feature the users again (in case they've changed)" do it "should feature the users again (in case they've changed)" do
Jobs.expects(:enqueue).with(:feature_topic_users, has_entries(topic_id: post.topic_id, except_post_id: post.id)) Jobs.expects(:enqueue).with(:feature_topic_users, has_entries(topic_id: post.topic_id))
PostDestroyer.new(moderator, post).destroy PostDestroyer.new(moderator, post).destroy
end end

View File

@ -30,11 +30,6 @@ describe Jobs::FeatureTopicUsers do
expect(topic.reload.featured_user_ids.include?(coding_horror.id)).to eq(true) expect(topic.reload.featured_user_ids.include?(coding_horror.id)).to eq(true)
end end
it "will not feature the second poster if we supply their post to be ignored" do
Jobs::FeatureTopicUsers.new.execute(topic_id: topic.id, except_post_id: second_post.id)
expect(topic.reload.featured_user_ids.include?(coding_horror.id)).to eq(false)
end
it "won't feature the last poster" do it "won't feature the last poster" do
Jobs::FeatureTopicUsers.new.execute(topic_id: topic.id) Jobs::FeatureTopicUsers.new.execute(topic_id: topic.id)
expect(topic.reload.featured_user_ids.include?(evil_trout.id)).to eq(false) expect(topic.reload.featured_user_ids.include?(evil_trout.id)).to eq(false)