The "Best Of" mode uses a percentage ranking of posts.
This commit is contained in:
parent
ab412dd8b4
commit
9c38c13ac5
|
@ -157,7 +157,7 @@ class Post < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.best_of
|
||||
where("(post_number = 1) or (score >= ?)", SiteSetting.best_of_score_threshold)
|
||||
where(["(post_number = 1) or (percent_rank <= ?)", SiteSetting.best_of_percent_filter.to_f / 100.0])
|
||||
end
|
||||
|
||||
def update_flagged_posts_count
|
||||
|
|
|
@ -106,6 +106,7 @@ class SiteSetting < ActiveRecord::Base
|
|||
setting(:best_of_score_threshold, 15)
|
||||
setting(:best_of_posts_required, 50)
|
||||
setting(:best_of_likes_required, 1)
|
||||
setting(:best_of_percent_filter, 5)
|
||||
|
||||
# we need to think of a way to force users to enter certain settings, this is a minimal config thing
|
||||
setting(:notification_email, 'info@discourse.org')
|
||||
|
|
|
@ -329,6 +329,7 @@ en:
|
|||
best_of_score_threshold: "The minimum score of a post to be included in the 'best of'"
|
||||
best_of_posts_required: "Minimum posts in a topic before 'best of' mode is enabled"
|
||||
best_of_likes_required: "Minimum likes in a topic before the 'best of' mode will be enabled"
|
||||
best_of_percent_filter: "When a user clicks best of, show the top % of posts"
|
||||
enable_private_messages: "Allow trust level 1 users to create private messages and conversations"
|
||||
|
||||
enable_long_polling: "Message bus used for notification can use long polling"
|
||||
|
|
|
@ -171,7 +171,7 @@ Discourse::Application.routes.draw do
|
|||
get 'threads/:topic_id/:post_number/avatar' => 'topics#avatar', :constraints => {:topic_id => /\d+/, :post_number => /\d+/}
|
||||
|
||||
# Topic routes
|
||||
get 't/:slug/:topic_id/best_of' => 'topics#show', :constraints => {:topic_id => /\d+/, :post_number => /\d+/}
|
||||
get 't/:slug/:topic_id/best_of' => 'topics#show', :defaults => {best_of: true}, :constraints => {:topic_id => /\d+/, :post_number => /\d+/}
|
||||
get 't/:topic_id/best_of' => 'topics#show', :constraints => {:topic_id => /\d+/, :post_number => /\d+/}
|
||||
put 't/:slug/:topic_id' => 'topics#update', :constraints => {:topic_id => /\d+/}
|
||||
put 't/:slug/:topic_id/star' => 'topics#star', :constraints => {:topic_id => /\d+/}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
class AddPercentRankToPosts < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :posts, :percent_rank, :float, default: 1.0
|
||||
|
||||
execute "UPDATE posts SET percent_rank = x.percent_rank
|
||||
FROM (SELECT id, percent_rank()
|
||||
OVER (PARTITION BY topic_id ORDER BY SCORE DESC)
|
||||
FROM posts) AS x
|
||||
WHERE x.id = posts.id"
|
||||
|
||||
end
|
||||
end
|
|
@ -21,6 +21,15 @@ class ScoreCalculator
|
|||
# First update the scores of the posts
|
||||
exec_sql(post_score_sql, @weightings)
|
||||
|
||||
# Update the percent rankings of the posts
|
||||
|
||||
exec_sql("UPDATE posts SET percent_rank = x.percent_rank
|
||||
FROM (SELECT id, percent_rank()
|
||||
OVER (PARTITION BY topic_id ORDER BY SCORE DESC) as percent_rank
|
||||
FROM posts) AS x
|
||||
WHERE x.id = posts.id")
|
||||
|
||||
|
||||
# Update the best of flag
|
||||
exec_sql "
|
||||
UPDATE topics SET has_best_of =
|
||||
|
@ -41,7 +50,7 @@ class ScoreCalculator
|
|||
|
||||
private
|
||||
|
||||
def exec_sql(sql, params)
|
||||
def exec_sql(sql, params=nil)
|
||||
ActiveRecord::Base.exec_sql(sql, params)
|
||||
end
|
||||
|
||||
|
|
|
@ -3,19 +3,25 @@ require 'score_calculator'
|
|||
|
||||
describe ScoreCalculator do
|
||||
|
||||
before do
|
||||
@post = Fabricate(:post, reads: 111)
|
||||
@topic = @post.topic
|
||||
end
|
||||
let!(:post) { Fabricate(:post, reads: 111) }
|
||||
let!(:another_post) { Fabricate(:post, topic: post.topic, reads: 222) }
|
||||
let(:topic) { post.topic }
|
||||
|
||||
context 'with weightings' do
|
||||
before do
|
||||
ScoreCalculator.new(reads: 3).calculate
|
||||
@post.reload
|
||||
post.reload
|
||||
another_post.reload
|
||||
end
|
||||
|
||||
it 'takes the supplied weightings into effect' do
|
||||
@post.score.should == 333
|
||||
post.score.should == 333
|
||||
another_post.score.should == 666
|
||||
end
|
||||
|
||||
it "creates the percent_ranks" do
|
||||
another_post.percent_rank.should == 0.0
|
||||
post.percent_rank.should == 1.0
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -23,15 +29,15 @@ describe ScoreCalculator do
|
|||
|
||||
it "won't update the site settings when the site settings don't match" do
|
||||
ScoreCalculator.new(reads: 3).calculate
|
||||
@topic.reload
|
||||
@topic.has_best_of.should be_false
|
||||
topic.reload
|
||||
topic.has_best_of.should be_false
|
||||
end
|
||||
|
||||
it "removes the best_of flag if the topic no longer qualifies" do
|
||||
@topic.update_column(:has_best_of, true)
|
||||
topic.update_column(:has_best_of, true)
|
||||
ScoreCalculator.new(reads: 3).calculate
|
||||
@topic.reload
|
||||
@topic.has_best_of.should be_false
|
||||
topic.reload
|
||||
topic.has_best_of.should be_false
|
||||
end
|
||||
|
||||
it "won't update the site settings when the site settings don't match" do
|
||||
|
@ -40,8 +46,8 @@ describe ScoreCalculator do
|
|||
SiteSetting.expects(:best_of_score_threshold).returns(100)
|
||||
|
||||
ScoreCalculator.new(reads: 3).calculate
|
||||
@topic.reload
|
||||
@topic.has_best_of.should be_true
|
||||
topic.reload
|
||||
topic.has_best_of.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -628,12 +628,12 @@ describe Post do
|
|||
end
|
||||
|
||||
context 'best_of' do
|
||||
let!(:p1) { Fabricate(:post, post_args.merge(score: 4)) }
|
||||
let!(:p2) { Fabricate(:post, post_args.merge(score: 10)) }
|
||||
let!(:p3) { Fabricate(:post, post_args.merge(score: 5)) }
|
||||
let!(:p1) { Fabricate(:post, post_args.merge(score: 4, percent_rank: 0.33)) }
|
||||
let!(:p2) { Fabricate(:post, post_args.merge(score: 10, percent_rank: 0.66)) }
|
||||
let!(:p3) { Fabricate(:post, post_args.merge(score: 5, percent_rank: 0.99)) }
|
||||
|
||||
it "returns the OP and posts above the threshold in best of mode" do
|
||||
SiteSetting.stubs(:best_of_score_threshold).returns(10)
|
||||
SiteSetting.stubs(:best_of_percent_filter).returns(66)
|
||||
Post.best_of.order(:post_number).should == [p1, p2]
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue