mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
get regular trust level going, self heal inconsistent topic timings
This commit is contained in:
parent
6aaa0ffe5e
commit
4fbf017272
|
@ -152,6 +152,14 @@ class SiteSetting < ActiveRecord::Base
|
|||
setting(:basic_requires_read_posts, 50)
|
||||
setting(:basic_requires_time_spent_mins, 15)
|
||||
|
||||
setting(:regular_requires_topics_entered, 3)
|
||||
setting(:regular_requires_read_posts, 100)
|
||||
setting(:regular_requires_time_spent_mins, 60)
|
||||
setting(:regular_requires_days_visited, 15)
|
||||
setting(:regular_requires_likes_received, 1)
|
||||
setting(:regular_requires_likes_given, 1)
|
||||
setting(:regular_requires_topic_reply_count, 3)
|
||||
|
||||
# Entropy checks
|
||||
setting(:title_min_entropy, 10)
|
||||
setting(:body_min_entropy, 7)
|
||||
|
|
|
@ -171,4 +171,24 @@ class TopicUser < ActiveRecord::Base
|
|||
|
||||
end
|
||||
|
||||
def self.ensure_consistency!
|
||||
exec_sql <<SQL
|
||||
UPDATE topic_users t
|
||||
SET
|
||||
last_read_post_number = last_read,
|
||||
seen_post_count = post_count
|
||||
FROM (
|
||||
SELECT topic_id, user_id, COUNT(*) post_count, MAX(post_number) last_read
|
||||
FROM post_timings
|
||||
GROUP BY topic_id, user_id
|
||||
) as X
|
||||
WHERE X.topic_id = t.topic_id AND
|
||||
X.user_id = t.user_id AND
|
||||
(
|
||||
last_read_post_number <> last_read OR
|
||||
seen_post_count <> post_count
|
||||
)
|
||||
SQL
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -201,6 +201,15 @@ JOIN users pu on pu.id = COALESCE(p.user_id, t.user_id)
|
|||
action.created_at = hash[:created_at]
|
||||
end
|
||||
action.save!
|
||||
|
||||
action_type = hash[:action_type]
|
||||
user_id = hash[:user_id]
|
||||
if action_type == LIKE
|
||||
User.update_all('likes_given = likes_given + 1', id: user_id)
|
||||
elsif action_type == WAS_LIKED
|
||||
User.update_all('likes_received = likes_received + 1', id: user_id)
|
||||
end
|
||||
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
# can happen, don't care already logged
|
||||
raise ActiveRecord::Rollback
|
||||
|
@ -214,6 +223,14 @@ JOIN users pu on pu.id = COALESCE(p.user_id, t.user_id)
|
|||
action.destroy
|
||||
MessageBus.publish("/user/#{hash[:user_id]}", {user_action_id: action.id, remove: true})
|
||||
end
|
||||
|
||||
action_type = hash[:action_type]
|
||||
user_id = hash[:user_id]
|
||||
if action_type == LIKE
|
||||
User.update_all('likes_given = likes_given - 1', id: user_id)
|
||||
elsif action_type == WAS_LIKED
|
||||
User.update_all('likes_received = likes_received - 1', id: user_id)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -12,8 +12,8 @@ module Clockwork
|
|||
|
||||
every(1.day, 'enqueue_digest_emails', at: '06:00')
|
||||
every(1.day, 'category_stats', at: '04:00')
|
||||
every(1.day, 'ensure_db_consistency', at: '02:00')
|
||||
every(10.minutes, 'periodical_updates')
|
||||
every(1.day, 'version_check')
|
||||
every(1.minute, 'clockwork_heartbeat')
|
||||
|
||||
end
|
||||
|
|
|
@ -455,6 +455,15 @@ en:
|
|||
basic_requires_topics_entered: "How many a topics a new user must enter before promotion to basic (1) trust level"
|
||||
basic_requires_read_posts: "How many posts a new user must read before promotion to basic (1) trust level"
|
||||
basic_requires_time_spent_mins: "How many minutes a new user must read posts before promotion to basic (1) trust level"
|
||||
|
||||
regular_requires_topics_entered: "How many a topics a basic user must enter before promotion to regular (2) trust level"
|
||||
regular_requires_read_posts: "How many posts a basic user must read before promotion to regular (2) trust level"
|
||||
regular_requires_time_spent_mins: "How many minutes a basic user must read posts before promotion to regular (2) trust level"
|
||||
regular_requires_days_visited: "How many days a basic user must visit the site before promotion to regular (2) trust level"
|
||||
regular_requires_likes_received: "How many likes a basic user must receive before promotion to regular (2) trust level"
|
||||
regular_requires_likes_given: "How many likes a basic user must cast before promotion to regular (2) trust level"
|
||||
regular_requires_topic_reply_count: "How many topics a basic user must reply to before promotion to regular (2) trust level"
|
||||
|
||||
visitor_max_links: "How many links a visitor can add to a post"
|
||||
visitor_max_images: "How many images a visitor can add to a post"
|
||||
visitor_max_mentions_per_post: "Maximum number of @name notifications a visitor can use in a post"
|
||||
|
|
70
db/migrate/20130404232558_add_user_extras.rb
Normal file
70
db/migrate/20130404232558_add_user_extras.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
class AddUserExtras < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
# NOTE: our user table is getting bloated, we probably want to split it for performance
|
||||
# put lesser used columns into a user_extras table and frequently used ones here.
|
||||
add_column :users, :likes_given, :integer, null: false, default: 0
|
||||
add_column :users, :likes_received, :integer, null: false, default: 0
|
||||
add_column :users, :topic_reply_count, :integer, null: false, default: 0
|
||||
|
||||
|
||||
# NOTE: to keep migrations working through refactorings we avoid externalizing this stuff.
|
||||
# even though a helper method may make sense
|
||||
execute <<SQL
|
||||
UPDATE users u
|
||||
SET
|
||||
likes_given = X.likes_given
|
||||
FROM (
|
||||
SELECT
|
||||
a.user_id,
|
||||
COUNT(*) likes_given
|
||||
FROM user_actions a
|
||||
JOIN posts p ON p.id = a.target_post_id
|
||||
WHERE p.deleted_at IS NULL AND a.action_type = 1
|
||||
GROUP BY a.user_id
|
||||
) as X
|
||||
WHERE X.user_id = u.id
|
||||
SQL
|
||||
|
||||
execute <<SQL
|
||||
UPDATE users u
|
||||
SET
|
||||
likes_received = Y.likes_received
|
||||
FROM (
|
||||
SELECT
|
||||
a.user_id,
|
||||
COUNT(*) likes_received
|
||||
FROM user_actions a
|
||||
JOIN posts p ON p.id = a.target_post_id
|
||||
WHERE p.deleted_at IS NULL AND a.action_type = 2
|
||||
GROUP BY a.user_id
|
||||
) as Y
|
||||
WHERE Y.user_id = u.id
|
||||
SQL
|
||||
|
||||
execute <<SQL
|
||||
UPDATE users u
|
||||
SET
|
||||
topic_reply_count = Z.topic_reply_count
|
||||
FROM (
|
||||
SELECT
|
||||
p.user_id,
|
||||
COUNT(DISTINCT topic_id) topic_reply_count
|
||||
FROM posts p
|
||||
JOIN topics t on t.id = p.topic_id
|
||||
WHERE t.user_id <> p.user_id AND
|
||||
p.deleted_at IS NULL AND t.deleted_at IS NULL
|
||||
GROUP BY p.user_id
|
||||
) Z
|
||||
WHERE
|
||||
Z.user_id = u.id
|
||||
SQL
|
||||
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :users, :likes_given
|
||||
remove_column :users, :likes_received
|
||||
remove_column :users, :topic_reply_count
|
||||
end
|
||||
end
|
|
@ -186,7 +186,7 @@ class Guardian
|
|||
return false if @user.blank?
|
||||
return false unless can_see?(object)
|
||||
return false if SiteSetting.must_approve_users?
|
||||
@user.moderator?
|
||||
@user.has_trust_level?(:regular) || @user.moderator?
|
||||
end
|
||||
|
||||
|
||||
|
|
8
lib/jobs/ensure_db_consistency.rb
Normal file
8
lib/jobs/ensure_db_consistency.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
module Jobs
|
||||
# checks to see if any users need to be promoted
|
||||
class EnsureDbConsistency < Jobs::Base
|
||||
def execute(args)
|
||||
TopicUser.ensure_consistency!
|
||||
end
|
||||
end
|
||||
end
|
|
@ -23,6 +23,8 @@ class PostCreator
|
|||
# target_usernames - comma delimited list of usernames for membership (private message)
|
||||
# meta_data - Topic meta data hash
|
||||
def initialize(user, opts)
|
||||
# TODO: we should reload user in case it is tainted, should take in a user_id as opposed to user
|
||||
# If we don't do this we introduce a rather risky dependency
|
||||
@user = user
|
||||
@opts = opts
|
||||
raise Discourse::InvalidParameters.new(:raw) if @opts[:raw].blank?
|
||||
|
@ -113,8 +115,13 @@ class PostCreator
|
|||
# Track the topic
|
||||
TopicUser.auto_track(@user.id, topic.id, TopicUser.notification_reasons[:created_post])
|
||||
|
||||
# Update `last_posted_at` to match the post's created_at
|
||||
@user.update_column(:last_posted_at, post.created_at)
|
||||
|
||||
if @user.id != topic.user_id
|
||||
@user.topic_reply_count += 1
|
||||
end
|
||||
|
||||
@user.last_posted_at = post.created_at
|
||||
@user.save!
|
||||
|
||||
# Publish the post in the message bus
|
||||
MessageBus.publish("/topic/#{post.topic_id}",
|
||||
|
|
|
@ -32,4 +32,17 @@ class Promotion
|
|||
true
|
||||
end
|
||||
|
||||
def review_basic
|
||||
return false if @user.topics_entered < SiteSetting.regular_requires_topics_entered
|
||||
return false if @user.posts_read_count < SiteSetting.regular_requires_read_posts
|
||||
return false if (@user.time_read / 60) < SiteSetting.regular_requires_time_spent_mins
|
||||
return false if @user.days_visited < SiteSetting.regular_requires_days_visited
|
||||
return false if @user.likes_received < SiteSetting.regular_requires_likes_received
|
||||
return false if @user.likes_given < SiteSetting.regular_requires_likes_given
|
||||
return false if @user.topic_reply_count < SiteSetting.regular_requires_topic_reply_count
|
||||
|
||||
@user.trust_level = TrustLevel.levels[:regular]
|
||||
@user.save
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -71,7 +71,6 @@ describe PostCreator do
|
|||
creator.create
|
||||
end
|
||||
|
||||
|
||||
it 'assigns a category when supplied' do
|
||||
creator_with_category.create.topic.category.should == category
|
||||
end
|
||||
|
@ -84,6 +83,18 @@ describe PostCreator do
|
|||
Post.any_instance.expects(:image_sizes=).with(image_sizes)
|
||||
creator_with_image_sizes.create
|
||||
end
|
||||
|
||||
it 'increases topic response counts' do
|
||||
first_post = creator.create
|
||||
user2 = Fabricate(:coding_horror)
|
||||
|
||||
user2.topic_reply_count.should == 0
|
||||
first_post.user.reload.topic_reply_count.should == 0
|
||||
|
||||
PostCreator.new(user2, topic_id: first_post.topic_id, raw: "this is my test post 123").create
|
||||
user2.reload.topic_reply_count.should == 1
|
||||
first_post.user.reload.topic_reply_count.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -44,5 +44,46 @@ describe Promotion do
|
|||
|
||||
end
|
||||
|
||||
context "basic" do
|
||||
|
||||
let(:user) { Fabricate(:user, trust_level: TrustLevel.levels[:basic])}
|
||||
let(:promotion) { Promotion.new(user) }
|
||||
|
||||
context 'that has done nothing' do
|
||||
let!(:result) { promotion.review }
|
||||
|
||||
it "returns false" do
|
||||
result.should be_false
|
||||
end
|
||||
|
||||
it "has not changed the user's trust level" do
|
||||
user.trust_level.should == TrustLevel.levels[:basic]
|
||||
end
|
||||
end
|
||||
|
||||
context "that has done the requisite things" do
|
||||
|
||||
before do
|
||||
user.topics_entered = SiteSetting.regular_requires_topics_entered
|
||||
user.posts_read_count = SiteSetting.regular_requires_read_posts
|
||||
user.time_read = SiteSetting.regular_requires_time_spent_mins * 60
|
||||
user.days_visited = SiteSetting.regular_requires_days_visited * 60
|
||||
user.likes_received = SiteSetting.regular_requires_likes_received
|
||||
user.likes_given = SiteSetting.regular_requires_likes_given
|
||||
user.topic_reply_count = SiteSetting.regular_requires_topic_reply_count
|
||||
|
||||
@result = promotion.review
|
||||
end
|
||||
|
||||
it "returns true" do
|
||||
@result.should be_true
|
||||
end
|
||||
|
||||
it "has upgraded the user to regular" do
|
||||
user.trust_level.should == TrustLevel.levels[:regular]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -207,4 +207,23 @@ describe TopicUser do
|
|||
|
||||
end
|
||||
|
||||
|
||||
it "is able to self heal" do
|
||||
p1 = Fabricate(:post)
|
||||
p2 = Fabricate(:post, user: p1.user, topic: p1.topic, post_number: 2)
|
||||
|
||||
TopicUser.exec_sql("UPDATE topic_users set seen_post_count=0, last_read_post_number=0
|
||||
WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: p1.topic_id, user_id: p1.user_id)
|
||||
|
||||
[p1,p2].each do |p|
|
||||
PostTiming.create(topic_id: p.topic_id, post_number: p.post_number, user_id: p.user_id, msecs: 100)
|
||||
end
|
||||
|
||||
TopicUser.ensure_consistency!
|
||||
|
||||
tu = TopicUser.where(user_id: p1.user_id, topic_id: p1.topic_id).first
|
||||
tu.last_read_post_number.should == p2.post_number
|
||||
tu.seen_post_count.should == 2
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -108,13 +108,17 @@ describe UserAction do
|
|||
@likee_action = likee.user_actions.where(action_type: UserAction::WAS_LIKED).first
|
||||
end
|
||||
|
||||
it 'should create a like action on the liker' do
|
||||
it 'should result in correct data assignment' do
|
||||
@liker_action.should_not be_nil
|
||||
@likee_action.should_not be_nil
|
||||
likee.reload.likes_received.should == 1
|
||||
liker.reload.likes_given.should == 1
|
||||
|
||||
PostAction.remove_act(liker, post, PostActionType.types[:like])
|
||||
likee.reload.likes_received.should == 0
|
||||
liker.reload.likes_given.should == 0
|
||||
end
|
||||
|
||||
it 'should create a like action on the likee' do
|
||||
@likee_action.should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "liking a private message" do
|
||||
|
|
Loading…
Reference in New Issue
Block a user