mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 15:48:43 -05:00
large refactor, ship a few columns from the user table into user_stats
This commit is contained in:
parent
4613006ae3
commit
5bf26ec34e
29 changed files with 354 additions and 251 deletions
|
@ -17,7 +17,7 @@ module Jobs
|
|||
CategoryFeaturedTopic.feature_topics
|
||||
|
||||
# Update view counts for users
|
||||
User.update_view_counts
|
||||
UserStat.update_view_counts
|
||||
|
||||
# Update the scores of posts
|
||||
ScoreCalculator.new.calculate
|
||||
|
|
|
@ -61,7 +61,7 @@ class PostTiming < ActiveRecord::Base
|
|||
|
||||
|
||||
def self.process_timings(current_user, topic_id, topic_time, timings)
|
||||
current_user.update_time_read!
|
||||
current_user.user_stat.update_time_read!
|
||||
|
||||
highest_seen = 1
|
||||
timings.each do |post_number, time|
|
||||
|
|
|
@ -191,18 +191,21 @@ end
|
|||
#
|
||||
# Table name: site_customizations
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255) not null
|
||||
# stylesheet :text
|
||||
# header :text
|
||||
# position :integer not null
|
||||
# user_id :integer not null
|
||||
# enabled :boolean not null
|
||||
# key :string(255) not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# override_default_style :boolean default(FALSE), not null
|
||||
# stylesheet_baked :text default(""), not null
|
||||
# id :integer not null, primary key
|
||||
# name :string(255) not null
|
||||
# stylesheet :text
|
||||
# header :text
|
||||
# position :integer not null
|
||||
# user_id :integer not null
|
||||
# enabled :boolean not null
|
||||
# key :string(255) not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# override_default_style :boolean default(FALSE), not null
|
||||
# stylesheet_baked :text default(""), not null
|
||||
# mobile_stylesheet :text
|
||||
# mobile_header :text
|
||||
# mobile_stylesheet_baked :text
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -663,7 +663,9 @@ end
|
|||
#
|
||||
# Indexes
|
||||
#
|
||||
# idx_topics_user_id_deleted_at (user_id)
|
||||
# index_forum_threads_on_bumped_at (bumped_at)
|
||||
# idx_topics_user_id_deleted_at (user_id)
|
||||
# index_forum_threads_on_bumped_at (bumped_at)
|
||||
# index_topics_on_deleted_at_and_visible_and_archetype_and_id (deleted_at,visible,archetype,id)
|
||||
# index_topics_on_id_and_deleted_at (id,deleted_at)
|
||||
#
|
||||
|
||||
|
|
|
@ -106,8 +106,9 @@ end
|
|||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_uploads_on_sha1 (sha1) UNIQUE
|
||||
# index_uploads_on_url (url)
|
||||
# index_uploads_on_user_id (user_id)
|
||||
# index_uploads_on_id_and_url (id,url)
|
||||
# index_uploads_on_sha1 (sha1) UNIQUE
|
||||
# index_uploads_on_url (url)
|
||||
# index_uploads_on_user_id (user_id)
|
||||
#
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ class User < ActiveRecord::Base
|
|||
|
||||
def update_visit_record!(date)
|
||||
unless has_visit_record?(date)
|
||||
update_column(:days_visited, days_visited + 1)
|
||||
user_stat.update_column(:days_visited, user_stat.days_visited + 1)
|
||||
user_visits.create!(visited_at: date)
|
||||
end
|
||||
end
|
||||
|
@ -316,42 +316,6 @@ class User < ActiveRecord::Base
|
|||
uploaded_avatar_path || User.gravatar_template(email)
|
||||
end
|
||||
|
||||
# Updates the denormalized view counts for all users
|
||||
def self.update_view_counts
|
||||
|
||||
# NOTE: we only update the counts for users we have seen in the last hour
|
||||
# this avoids a very expensive query that may run on the entire user base
|
||||
# we also ensure we only touch the table if data changes
|
||||
|
||||
# Update denormalized topics_entered
|
||||
exec_sql "UPDATE users SET topics_entered = X.c
|
||||
FROM
|
||||
(SELECT v.user_id,
|
||||
COUNT(DISTINCT parent_id) AS c
|
||||
FROM views AS v
|
||||
WHERE parent_type = 'Topic' AND v.user_id IN (
|
||||
SELECT u1.id FROM users u1 where u1.last_seen_at > :seen_at
|
||||
)
|
||||
GROUP BY v.user_id) AS X
|
||||
WHERE
|
||||
X.user_id = users.id AND
|
||||
X.c <> topics_entered
|
||||
", seen_at: 1.hour.ago
|
||||
|
||||
# Update denormalzied posts_read_count
|
||||
exec_sql "UPDATE users SET posts_read_count = X.c
|
||||
FROM
|
||||
(SELECT pt.user_id,
|
||||
COUNT(*) AS c
|
||||
FROM post_timings AS pt
|
||||
WHERE pt.user_id IN (
|
||||
SELECT u1.id FROM users u1 where u1.last_seen_at > :seen_at
|
||||
)
|
||||
GROUP BY pt.user_id) AS X
|
||||
WHERE X.user_id = users.id AND
|
||||
X.c <> posts_read_count
|
||||
", seen_at: 1.hour.ago
|
||||
end
|
||||
|
||||
# The following count methods are somewhat slow - definitely don't use them in a loop.
|
||||
# They might need to be denormalized
|
||||
|
@ -458,20 +422,6 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
MAX_TIME_READ_DIFF = 100
|
||||
# attempt to add total read time to user based on previous time this was called
|
||||
def update_time_read!
|
||||
last_seen_key = "user-last-seen:#{id}"
|
||||
last_seen = $redis.get(last_seen_key)
|
||||
if last_seen.present?
|
||||
diff = (Time.now.to_f - last_seen.to_f).round
|
||||
if diff > 0 && diff < MAX_TIME_READ_DIFF
|
||||
User.where(id: id, time_read: time_read).update_all ["time_read = time_read + ?", diff]
|
||||
end
|
||||
end
|
||||
$redis.set(last_seen_key, Time.now.to_f)
|
||||
end
|
||||
|
||||
def readable_name
|
||||
return "#{name} (#{username})" if name.present? && name != username
|
||||
username
|
||||
|
@ -486,18 +436,6 @@ class User < ActiveRecord::Base
|
|||
where('created_at > ?', sinceDaysAgo.days.ago).group('date(created_at)').order('date(created_at)').count
|
||||
end
|
||||
|
||||
def update_topic_reply_count
|
||||
self.topic_reply_count =
|
||||
Topic
|
||||
.where(['id in (
|
||||
SELECT topic_id FROM posts p
|
||||
JOIN topics t2 ON t2.id = p.topic_id
|
||||
WHERE p.deleted_at IS NULL AND
|
||||
t2.user_id <> p.user_id AND
|
||||
p.user_id = ?
|
||||
)', self.id])
|
||||
.count
|
||||
end
|
||||
|
||||
def secure_category_ids
|
||||
cats = self.staff? ? Category.where(read_restricted: true) : secure_categories.references(:categories)
|
||||
|
@ -549,7 +487,7 @@ class User < ActiveRecord::Base
|
|||
|
||||
def create_user_stat
|
||||
stat = UserStat.new
|
||||
stat.user_id = self.id
|
||||
stat.user_id = id
|
||||
stat.save!
|
||||
end
|
||||
|
||||
|
@ -647,8 +585,6 @@ end
|
|||
# approved :boolean default(FALSE), not null
|
||||
# approved_by_id :integer
|
||||
# approved_at :datetime
|
||||
# topics_entered :integer default(0), not null
|
||||
# posts_read_count :integer default(0), not null
|
||||
# digest_after_days :integer
|
||||
# previous_visit_at :datetime
|
||||
# banned_at :datetime
|
||||
|
@ -657,22 +593,18 @@ end
|
|||
# auto_track_topics_after_msecs :integer
|
||||
# views :integer default(0), not null
|
||||
# flag_level :integer default(0), not null
|
||||
# time_read :integer default(0), not null
|
||||
# days_visited :integer default(0), not null
|
||||
# ip_address :string
|
||||
# new_topic_duration_minutes :integer
|
||||
# external_links_in_new_tab :boolean default(FALSE), not null
|
||||
# enable_quoting :boolean default(TRUE), not null
|
||||
# moderator :boolean default(FALSE)
|
||||
# likes_given :integer default(0), not null
|
||||
# likes_received :integer default(0), not null
|
||||
# topic_reply_count :integer default(0), not null
|
||||
# blocked :boolean default(FALSE)
|
||||
# dynamic_favicon :boolean default(FALSE), not null
|
||||
# title :string(255)
|
||||
# use_uploaded_avatar :boolean default(FALSE)
|
||||
# uploaded_avatar_template :string(255)
|
||||
# uploaded_avatar_id :integer
|
||||
# email_always :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -254,9 +254,9 @@ SQL
|
|||
|
||||
def self.update_like_count(user_id, action_type, delta)
|
||||
if action_type == LIKE
|
||||
User.where(id: user_id).update_all("likes_given = likes_given + #{delta.to_i}")
|
||||
UserStat.where(user_id: user_id).update_all("likes_given = likes_given + #{delta.to_i}")
|
||||
elsif action_type == WAS_LIKED
|
||||
User.where(id: user_id).update_all("likes_received = likes_received + #{delta.to_i}")
|
||||
UserStat.where(user_id: user_id).update_all("likes_received = likes_received + #{delta.to_i}")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -66,11 +66,11 @@ end
|
|||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: staff_action_logs
|
||||
# Table name: user_histories
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# action :integer not null
|
||||
# staff_user_id :integer not null
|
||||
# acting_user_id :integer
|
||||
# target_user_id :integer
|
||||
# details :text
|
||||
# created_at :datetime not null
|
||||
|
@ -81,12 +81,13 @@ end
|
|||
# subject :text
|
||||
# previous_value :text
|
||||
# new_value :text
|
||||
# topic_id :integer
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_staff_action_logs_on_action_and_id (action,id)
|
||||
# index_staff_action_logs_on_staff_user_id_and_id (staff_user_id,id)
|
||||
# index_staff_action_logs_on_subject_and_id (subject,id)
|
||||
# index_staff_action_logs_on_target_user_id_and_id (target_user_id,id)
|
||||
# index_staff_action_logs_on_action_and_id (action,id)
|
||||
# index_staff_action_logs_on_subject_and_id (subject,id)
|
||||
# index_staff_action_logs_on_target_user_id_and_id (target_user_id,id)
|
||||
# index_user_histories_on_acting_user_id_and_action_and_id (acting_user_id,action,id)
|
||||
#
|
||||
|
||||
|
|
|
@ -2,4 +2,84 @@ class UserStat < ActiveRecord::Base
|
|||
|
||||
belongs_to :user
|
||||
|
||||
# Updates the denormalized view counts for all users
|
||||
def self.update_view_counts
|
||||
|
||||
# NOTE: we only update the counts for users we have seen in the last hour
|
||||
# this avoids a very expensive query that may run on the entire user base
|
||||
# we also ensure we only touch the table if data changes
|
||||
|
||||
# Update denormalized topics_entered
|
||||
exec_sql "UPDATE user_stats SET topics_entered = X.c
|
||||
FROM
|
||||
(SELECT v.user_id,
|
||||
COUNT(DISTINCT parent_id) AS c
|
||||
FROM views AS v
|
||||
WHERE parent_type = 'Topic' AND v.user_id IN (
|
||||
SELECT u1.id FROM users u1 where u1.last_seen_at > :seen_at
|
||||
)
|
||||
GROUP BY v.user_id) AS X
|
||||
WHERE
|
||||
X.user_id = user_stats.user_id AND
|
||||
X.c <> topics_entered
|
||||
", seen_at: 1.hour.ago
|
||||
|
||||
# Update denormalzied posts_read_count
|
||||
exec_sql "UPDATE user_stats SET posts_read_count = X.c
|
||||
FROM
|
||||
(SELECT pt.user_id,
|
||||
COUNT(*) AS c
|
||||
FROM post_timings AS pt
|
||||
WHERE pt.user_id IN (
|
||||
SELECT u1.id FROM users u1 where u1.last_seen_at > :seen_at
|
||||
)
|
||||
GROUP BY pt.user_id) AS X
|
||||
WHERE X.user_id = user_stats.user_id AND
|
||||
X.c <> posts_read_count
|
||||
", seen_at: 1.hour.ago
|
||||
end
|
||||
|
||||
def update_topic_reply_count
|
||||
self.topic_reply_count =
|
||||
Topic
|
||||
.where(['id in (
|
||||
SELECT topic_id FROM posts p
|
||||
JOIN topics t2 ON t2.id = p.topic_id
|
||||
WHERE p.deleted_at IS NULL AND
|
||||
t2.user_id <> p.user_id AND
|
||||
p.user_id = ?
|
||||
)', self.user_id])
|
||||
.count
|
||||
end
|
||||
|
||||
MAX_TIME_READ_DIFF = 100
|
||||
# attempt to add total read time to user based on previous time this was called
|
||||
def update_time_read!
|
||||
last_seen_key = "user-last-seen:#{id}"
|
||||
last_seen = $redis.get(last_seen_key)
|
||||
if last_seen.present?
|
||||
diff = (Time.now.to_f - last_seen.to_f).round
|
||||
if diff > 0 && diff < MAX_TIME_READ_DIFF
|
||||
UserStat.where(user_id: id, time_read: time_read).update_all ["time_read = time_read + ?", diff]
|
||||
end
|
||||
end
|
||||
$redis.set(last_seen_key, Time.now.to_f)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: user_stats
|
||||
#
|
||||
# user_id :integer not null, primary key
|
||||
# has_custom_avatar :boolean default(FALSE), not null
|
||||
# topics_entered :integer default(0), not null
|
||||
# time_read :integer default(0), not null
|
||||
# days_visited :integer default(0), not null
|
||||
# posts_read_count :integer default(0), not null
|
||||
# likes_given :integer default(0), not null
|
||||
# likes_received :integer default(0), not null
|
||||
# topic_reply_count :integer default(0), not null
|
||||
#
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ class UserVisit < ActiveRecord::Base
|
|||
|
||||
def self.ensure_consistency!
|
||||
exec_sql <<SQL
|
||||
UPDATE users u set days_visited =
|
||||
UPDATE user_stats u set days_visited =
|
||||
(
|
||||
SELECT COUNT(*) FROM user_visits v WHERE v.user_id = u.id
|
||||
SELECT COUNT(*) FROM user_visits v WHERE v.user_id = u.user_id
|
||||
)
|
||||
WHERE days_visited <>
|
||||
(
|
||||
SELECT COUNT(*) FROM user_visits v WHERE v.user_id = u.id
|
||||
SELECT COUNT(*) FROM user_visits v WHERE v.user_id = u.user_id
|
||||
)
|
||||
SQL
|
||||
end
|
||||
|
|
|
@ -43,6 +43,7 @@ end
|
|||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_views_on_parent_id_and_parent_type (parent_id,parent_type)
|
||||
# index_views_on_parent_id_and_parent_type (parent_id,parent_type)
|
||||
# index_views_on_user_id_and_parent_type_and_parent_id (user_id,parent_type,parent_id)
|
||||
#
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ class AdminUserSerializer < BasicUserSerializer
|
|||
:admin,
|
||||
:moderator,
|
||||
:last_seen_age,
|
||||
:days_visited,
|
||||
:last_emailed_age,
|
||||
:created_at_age,
|
||||
:username_lower,
|
||||
|
@ -14,9 +13,6 @@ class AdminUserSerializer < BasicUserSerializer
|
|||
:username,
|
||||
:title,
|
||||
:avatar_template,
|
||||
:topics_entered,
|
||||
:posts_read_count,
|
||||
:time_read,
|
||||
:can_approve,
|
||||
:approved,
|
||||
:banned_at,
|
||||
|
@ -26,7 +22,15 @@ class AdminUserSerializer < BasicUserSerializer
|
|||
:can_send_activation_email,
|
||||
:can_activate,
|
||||
:can_deactivate,
|
||||
:blocked
|
||||
:blocked,
|
||||
:time_read
|
||||
|
||||
[:days_visited,:posts_read_count,:topics_entered].each do |sym|
|
||||
attributes sym
|
||||
define_method sym do
|
||||
object.user_stat.send(sym)
|
||||
end
|
||||
end
|
||||
|
||||
def is_banned
|
||||
object.is_banned?
|
||||
|
@ -47,8 +51,8 @@ class AdminUserSerializer < BasicUserSerializer
|
|||
end
|
||||
|
||||
def time_read
|
||||
return nil if object.time_read.blank?
|
||||
AgeWords.age_words(object.time_read)
|
||||
return nil if object.user_stat.time_read.blank?
|
||||
AgeWords.age_words(object.user_stat.time_read)
|
||||
end
|
||||
|
||||
def created_at_age
|
||||
|
|
|
@ -25,7 +25,7 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
end
|
||||
|
||||
def reply_count
|
||||
object.topic_reply_count
|
||||
object.user_stat.topic_reply_count
|
||||
end
|
||||
|
||||
def site_flagged_posts_count
|
||||
|
|
61
db/migrate/20131003061137_move_columns_to_user_stats.rb
Normal file
61
db/migrate/20131003061137_move_columns_to_user_stats.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
class MoveColumnsToUserStats < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :user_stats, :topics_entered, :integer, default: 0, null: false
|
||||
add_column :user_stats, :time_read, :integer, default: 0, null: false
|
||||
add_column :user_stats, :days_visited, :integer, default: 0, null: false
|
||||
add_column :user_stats, :posts_read_count, :integer, default: 0, null: false
|
||||
add_column :user_stats, :likes_given, :integer, default: 0, null: false
|
||||
add_column :user_stats, :likes_received, :integer, default: 0, null: false
|
||||
add_column :user_stats, :topic_reply_count, :integer, default: 0, null: false
|
||||
|
||||
execute 'UPDATE user_stats
|
||||
SET topics_entered = u.topics_entered,
|
||||
time_read = u.time_read,
|
||||
days_visited = u.days_visited,
|
||||
posts_read_count = u.posts_read_count,
|
||||
likes_given = u.likes_given,
|
||||
likes_received = u.likes_received,
|
||||
topic_reply_count = u.topic_reply_count
|
||||
FROM user_stats s
|
||||
JOIN users u on u.id = s.user_id
|
||||
'
|
||||
|
||||
remove_column :users, :topics_entered
|
||||
remove_column :users, :time_read
|
||||
remove_column :users, :days_visited
|
||||
remove_column :users, :posts_read_count
|
||||
remove_column :users, :likes_given
|
||||
remove_column :users, :likes_received
|
||||
remove_column :users, :topic_reply_count
|
||||
end
|
||||
|
||||
def down
|
||||
add_column :users, :topics_entered, :integer
|
||||
add_column :users, :time_read, :integer
|
||||
add_column :users, :days_visited, :integer
|
||||
add_column :users, :posts_read_count, :integer
|
||||
add_column :users, :likes_given, :integer
|
||||
add_column :users, :likes_received, :integer
|
||||
add_column :users, :topic_reply_count, :integer
|
||||
|
||||
execute 'UPDATE users
|
||||
SET topics_entered = u.topics_entered,
|
||||
time_read = u.time_read,
|
||||
days_visited = u.days_visited,
|
||||
posts_read_count = u.posts_read_count,
|
||||
likes_given = u.likes_given,
|
||||
likes_received = u.likes_received,
|
||||
topic_reply_count = u.topic_reply_count
|
||||
FROM users s
|
||||
JOIN user_stats u on s.id = u.user_id
|
||||
'
|
||||
|
||||
remove_column :user_stats, :topics_entered
|
||||
remove_column :user_stats, :time_read
|
||||
remove_column :user_stats, :days_visited
|
||||
remove_column :user_stats, :posts_read_count
|
||||
remove_column :user_stats, :likes_given
|
||||
remove_column :user_stats, :likes_received
|
||||
remove_column :user_stats, :topic_reply_count
|
||||
end
|
||||
end
|
|
@ -116,6 +116,7 @@ class Autospec::Runner
|
|||
puts s
|
||||
end
|
||||
puts
|
||||
queue_specs(specs.zip specs)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -425,10 +425,13 @@ class Guardian
|
|||
private
|
||||
|
||||
def is_my_own?(obj)
|
||||
@user.present? &&
|
||||
(obj.respond_to?(:user) || obj.respond_to?(:user_id)) &&
|
||||
(obj.respond_to?(:user) ? obj.user == @user : true) &&
|
||||
(obj.respond_to?(:user_id) ? (obj.user_id == @user.id) : true)
|
||||
|
||||
unless anonymous?
|
||||
return obj.user_id == @user.id if obj.respond_to?(:user_id)
|
||||
return obj.user == @user if obj.respond_to?(:user)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def is_me?(other)
|
||||
|
|
|
@ -232,7 +232,8 @@ class PostCreator
|
|||
def update_user_counts
|
||||
# We don't count replies to your own topics
|
||||
if @user.id != @topic.user_id
|
||||
@user.update_topic_reply_count
|
||||
@user.user_stat.update_topic_reply_count
|
||||
@user.user_stat.save!
|
||||
end
|
||||
|
||||
@user.last_posted_at = @post.created_at
|
||||
|
|
|
@ -22,9 +22,10 @@ class Promotion
|
|||
end
|
||||
|
||||
def review_newuser
|
||||
return false if @user.topics_entered < SiteSetting.basic_requires_topics_entered
|
||||
return false if @user.posts_read_count < SiteSetting.basic_requires_read_posts
|
||||
return false if (@user.time_read / 60) < SiteSetting.basic_requires_time_spent_mins
|
||||
stat = @user.user_stat
|
||||
return false if stat.topics_entered < SiteSetting.basic_requires_topics_entered
|
||||
return false if stat.posts_read_count < SiteSetting.basic_requires_read_posts
|
||||
return false if (stat.time_read / 60) < SiteSetting.basic_requires_time_spent_mins
|
||||
|
||||
@user.change_trust_level!(:basic)
|
||||
|
||||
|
@ -32,13 +33,14 @@ class Promotion
|
|||
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
|
||||
stat = @user.user_stat
|
||||
return false if stat.topics_entered < SiteSetting.regular_requires_topics_entered
|
||||
return false if stat.posts_read_count < SiteSetting.regular_requires_read_posts
|
||||
return false if (stat.time_read / 60) < SiteSetting.regular_requires_time_spent_mins
|
||||
return false if stat.days_visited < SiteSetting.regular_requires_days_visited
|
||||
return false if stat.likes_received < SiteSetting.regular_requires_likes_received
|
||||
return false if stat.likes_given < SiteSetting.regular_requires_likes_given
|
||||
return false if stat.topic_reply_count < SiteSetting.regular_requires_topic_reply_count
|
||||
|
||||
@user.change_trust_level!(:regular)
|
||||
end
|
||||
|
|
|
@ -39,9 +39,10 @@ describe BoostTrustLevel do
|
|||
context "for a user that has done the requisite things to attain their trust level" do
|
||||
|
||||
before do
|
||||
user.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
||||
user.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
||||
user.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||
stat = user.user_stat
|
||||
stat.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
||||
stat.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
||||
stat.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||
user.save!
|
||||
user.update_attributes(trust_level: TrustLevel.levels[:basic])
|
||||
end
|
||||
|
|
|
@ -163,12 +163,15 @@ describe PostCreator do
|
|||
topic_user.seen_post_count.should == first_post.post_number
|
||||
|
||||
user2 = Fabricate(:coding_horror)
|
||||
user2.topic_reply_count.should == 0
|
||||
first_post.user.reload.topic_reply_count.should == 0
|
||||
user2.user_stat.topic_reply_count.should == 0
|
||||
|
||||
first_post.user.user_stat.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
|
||||
|
||||
first_post.user.user_stat.reload.topic_reply_count.should == 0
|
||||
|
||||
user2.user_stat.reload.topic_reply_count.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -27,9 +27,10 @@ describe Promotion do
|
|||
context "that has done the requisite things" do
|
||||
|
||||
before do
|
||||
user.topics_entered = SiteSetting.basic_requires_topics_entered
|
||||
user.posts_read_count = SiteSetting.basic_requires_read_posts
|
||||
user.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||
stat = user.user_stat
|
||||
stat.topics_entered = SiteSetting.basic_requires_topics_entered
|
||||
stat.posts_read_count = SiteSetting.basic_requires_read_posts
|
||||
stat.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||
@result = promotion.review
|
||||
end
|
||||
|
||||
|
@ -64,13 +65,14 @@ describe Promotion do
|
|||
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
|
||||
stat = user.user_stat
|
||||
stat.topics_entered = SiteSetting.regular_requires_topics_entered
|
||||
stat.posts_read_count = SiteSetting.regular_requires_read_posts
|
||||
stat.time_read = SiteSetting.regular_requires_time_spent_mins * 60
|
||||
stat.days_visited = SiteSetting.regular_requires_days_visited * 60
|
||||
stat.likes_received = SiteSetting.regular_requires_likes_received
|
||||
stat.likes_given = SiteSetting.regular_requires_likes_given
|
||||
stat.topic_reply_count = SiteSetting.regular_requires_topic_reply_count
|
||||
|
||||
@result = promotion.review
|
||||
end
|
||||
|
|
|
@ -145,10 +145,11 @@ describe Admin::UsersController do
|
|||
|
||||
it "raises an error when demoting a user below their current trust level" do
|
||||
StaffActionLogger.any_instance.expects(:log_trust_level_change).never
|
||||
@another_user.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
||||
@another_user.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
||||
@another_user.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||
@another_user.save!
|
||||
stat = @another_user.user_stat
|
||||
stat.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
||||
stat.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
||||
stat.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||
stat.save!
|
||||
@another_user.update_attributes(trust_level: TrustLevel.levels[:basic])
|
||||
xhr :put, :trust_level, user_id: @another_user.id, level: TrustLevel.levels[:newuser]
|
||||
response.should be_forbidden
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
Fabricator(:user_action) do
|
||||
|
||||
user
|
||||
action_type UserAction::STAR
|
||||
|
||||
end
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
Fabricator(:user_stat) do
|
||||
end
|
||||
|
||||
Fabricator(:user) do
|
||||
name 'Bruce Wayne'
|
||||
username { sequence(:username) { |i| "bruce#{i}" } }
|
||||
|
@ -57,4 +60,4 @@ Fabricator(:active_user, from: :user) do
|
|||
trust_level TrustLevel.levels[:basic]
|
||||
active true
|
||||
bio_raw "Don't as me about my dad!"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ describe Jobs::PeriodicalUpdates do
|
|||
end
|
||||
|
||||
it "updates view counts" do
|
||||
User.expects(:update_view_counts).once
|
||||
UserStat.expects(:update_view_counts).once
|
||||
end
|
||||
|
||||
it "calculates scores" do
|
||||
|
|
|
@ -123,12 +123,12 @@ describe UserAction 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
|
||||
likee.user_stat.reload.likes_received.should == 1
|
||||
liker.user_stat.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
|
||||
likee.user_stat.reload.likes_received.should == 0
|
||||
liker.user_stat.reload.likes_given.should == 0
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'spec_helper'
|
||||
require_dependency 'user'
|
||||
|
||||
describe User do
|
||||
|
||||
|
@ -21,66 +22,6 @@ describe User do
|
|||
it { should validate_presence_of :username }
|
||||
it { should validate_presence_of :email }
|
||||
|
||||
context '#update_view_counts' do
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
context 'topics_entered' do
|
||||
context 'without any views' do
|
||||
it "doesn't increase the user's topics_entered" do
|
||||
lambda { User.update_view_counts; user.reload }.should_not change(user, :topics_entered)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a view' do
|
||||
let(:topic) { Fabricate(:topic) }
|
||||
let!(:view) { View.create_for(topic, '127.0.0.1', user) }
|
||||
|
||||
before do
|
||||
user.update_column :last_seen_at, 1.second.ago
|
||||
end
|
||||
|
||||
it "adds one to the topics entered" do
|
||||
User.update_view_counts
|
||||
user.reload
|
||||
user.topics_entered.should == 1
|
||||
end
|
||||
|
||||
it "won't record a second view as a different topic" do
|
||||
View.create_for(topic, '127.0.0.1', user)
|
||||
User.update_view_counts
|
||||
user.reload
|
||||
user.topics_entered.should == 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context 'posts_read_count' do
|
||||
context 'without any post timings' do
|
||||
it "doesn't increase the user's posts_read_count" do
|
||||
lambda { User.update_view_counts; user.reload }.should_not change(user, :posts_read_count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a post timing' do
|
||||
let!(:post) { Fabricate(:post) }
|
||||
let!(:post_timings) do
|
||||
PostTiming.record_timing(msecs: 1234, topic_id: post.topic_id, user_id: user.id, post_number: post.post_number)
|
||||
end
|
||||
|
||||
before do
|
||||
user.update_column :last_seen_at, 1.second.ago
|
||||
end
|
||||
|
||||
it "increases posts_read_count" do
|
||||
User.update_view_counts
|
||||
user.reload
|
||||
user.posts_read_count.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '.enqueue_welcome_message' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
@ -266,7 +207,6 @@ describe User do
|
|||
its(:approved_by_id) { should be_blank }
|
||||
its(:email_private_messages) { should be_true }
|
||||
its(:email_direct ) { should be_true }
|
||||
its(:time_read) { should == 0}
|
||||
|
||||
context 'digest emails' do
|
||||
it 'defaults to digests every week' do
|
||||
|
@ -295,8 +235,6 @@ describe User do
|
|||
its(:email_tokens) { should be_present }
|
||||
its(:bio_cooked) { should be_present }
|
||||
its(:bio_summary) { should be_present }
|
||||
its(:topics_entered) { should == 0 }
|
||||
its(:posts_read_count) { should == 0 }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -664,7 +602,7 @@ describe User do
|
|||
end
|
||||
|
||||
it "should have 0 for days_visited" do
|
||||
user.days_visited.should == 0
|
||||
user.user_stat.days_visited.should == 0
|
||||
end
|
||||
|
||||
describe 'with no previous values' do
|
||||
|
@ -685,7 +623,7 @@ describe User do
|
|||
|
||||
it "should have 0 for days_visited" do
|
||||
user.reload
|
||||
user.days_visited.should == 1
|
||||
user.user_stat.days_visited.should == 1
|
||||
end
|
||||
|
||||
it "should log a user_visit with the date" do
|
||||
|
@ -706,7 +644,7 @@ describe User do
|
|||
end
|
||||
|
||||
it "doesn't increase days_visited twice" do
|
||||
user.days_visited.should == 1
|
||||
user.user_stat.days_visited.should == 1
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -811,33 +749,6 @@ describe User do
|
|||
|
||||
end
|
||||
|
||||
describe 'update_time_read!' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it 'makes no changes if nothing is cached' do
|
||||
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(nil)
|
||||
user.update_time_read!
|
||||
user.reload
|
||||
user.time_read.should == 0
|
||||
end
|
||||
|
||||
it 'makes a change if time read is below threshold' do
|
||||
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(Time.now - 10.0)
|
||||
user.update_time_read!
|
||||
user.reload
|
||||
user.time_read.should == 10
|
||||
end
|
||||
|
||||
it 'makes no change if time read is above threshold' do
|
||||
t = Time.now - 1 - User::MAX_TIME_READ_DIFF
|
||||
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(t)
|
||||
user.update_time_read!
|
||||
user.reload
|
||||
user.time_read.should == 0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#readable_name' do
|
||||
context 'when name is missing' do
|
||||
it 'returns just the username' do
|
||||
|
|
|
@ -9,4 +9,96 @@ describe UserStat do
|
|||
user.user_stat.should be_present
|
||||
end
|
||||
|
||||
end
|
||||
context '#update_view_counts' do
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:stat) { user.user_stat }
|
||||
|
||||
context 'topics_entered' do
|
||||
context 'without any views' do
|
||||
it "doesn't increase the user's topics_entered" do
|
||||
lambda { UserStat.update_view_counts; stat.reload }.should_not change(stat, :topics_entered)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a view' do
|
||||
let(:topic) { Fabricate(:topic) }
|
||||
let!(:view) { View.create_for(topic, '127.0.0.1', user) }
|
||||
|
||||
before do
|
||||
user.update_column :last_seen_at, 1.second.ago
|
||||
end
|
||||
|
||||
it "adds one to the topics entered" do
|
||||
UserStat.update_view_counts
|
||||
stat.reload
|
||||
stat.topics_entered.should == 1
|
||||
end
|
||||
|
||||
it "won't record a second view as a different topic" do
|
||||
View.create_for(topic, '127.0.0.1', user)
|
||||
UserStat.update_view_counts
|
||||
stat.reload
|
||||
stat.topics_entered.should == 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context 'posts_read_count' do
|
||||
context 'without any post timings' do
|
||||
it "doesn't increase the user's posts_read_count" do
|
||||
lambda { UserStat.update_view_counts; stat.reload }.should_not change(stat, :posts_read_count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a post timing' do
|
||||
let!(:post) { Fabricate(:post) }
|
||||
let!(:post_timings) do
|
||||
PostTiming.record_timing(msecs: 1234, topic_id: post.topic_id, user_id: user.id, post_number: post.post_number)
|
||||
end
|
||||
|
||||
before do
|
||||
user.update_column :last_seen_at, 1.second.ago
|
||||
end
|
||||
|
||||
it "increases posts_read_count" do
|
||||
UserStat.update_view_counts
|
||||
stat.reload
|
||||
stat.posts_read_count.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'update_time_read!' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:stat) { user.user_stat }
|
||||
|
||||
it 'makes no changes if nothing is cached' do
|
||||
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(nil)
|
||||
stat.update_time_read!
|
||||
stat.reload
|
||||
stat.time_read.should == 0
|
||||
end
|
||||
|
||||
it 'makes a change if time read is below threshold' do
|
||||
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(Time.now - 10.0)
|
||||
stat.update_time_read!
|
||||
stat.reload
|
||||
stat.time_read.should == 10
|
||||
end
|
||||
|
||||
it 'makes no change if time read is above threshold' do
|
||||
t = Time.now - 1 - UserStat::MAX_TIME_READ_DIFF
|
||||
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(t)
|
||||
stat.update_time_read!
|
||||
stat.reload
|
||||
stat.time_read.should == 0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
@ -9,13 +9,13 @@ describe UserVisit do
|
|||
u.update_visit_record!(1.day.ago.to_date)
|
||||
|
||||
u.reload
|
||||
u.days_visited.should == 2
|
||||
u.user_stat.days_visited.should == 2
|
||||
|
||||
u.days_visited = 1
|
||||
u.user_stat.days_visited = 1
|
||||
u.save
|
||||
UserVisit.ensure_consistency!
|
||||
|
||||
u.reload
|
||||
u.days_visited.should == 2
|
||||
u.user_stat.days_visited.should == 2
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue