mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -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
|
CategoryFeaturedTopic.feature_topics
|
||||||
|
|
||||||
# Update view counts for users
|
# Update view counts for users
|
||||||
User.update_view_counts
|
UserStat.update_view_counts
|
||||||
|
|
||||||
# Update the scores of posts
|
# Update the scores of posts
|
||||||
ScoreCalculator.new.calculate
|
ScoreCalculator.new.calculate
|
||||||
|
|
|
@ -61,7 +61,7 @@ class PostTiming < ActiveRecord::Base
|
||||||
|
|
||||||
|
|
||||||
def self.process_timings(current_user, topic_id, topic_time, timings)
|
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
|
highest_seen = 1
|
||||||
timings.each do |post_number, time|
|
timings.each do |post_number, time|
|
||||||
|
|
|
@ -203,6 +203,9 @@ end
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# override_default_style :boolean default(FALSE), not null
|
# override_default_style :boolean default(FALSE), not null
|
||||||
# stylesheet_baked :text default(""), not null
|
# stylesheet_baked :text default(""), not null
|
||||||
|
# mobile_stylesheet :text
|
||||||
|
# mobile_header :text
|
||||||
|
# mobile_stylesheet_baked :text
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
|
|
|
@ -665,5 +665,7 @@ end
|
||||||
#
|
#
|
||||||
# idx_topics_user_id_deleted_at (user_id)
|
# idx_topics_user_id_deleted_at (user_id)
|
||||||
# index_forum_threads_on_bumped_at (bumped_at)
|
# 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,6 +106,7 @@ end
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
|
# index_uploads_on_id_and_url (id,url)
|
||||||
# index_uploads_on_sha1 (sha1) UNIQUE
|
# index_uploads_on_sha1 (sha1) UNIQUE
|
||||||
# index_uploads_on_url (url)
|
# index_uploads_on_url (url)
|
||||||
# index_uploads_on_user_id (user_id)
|
# index_uploads_on_user_id (user_id)
|
||||||
|
|
|
@ -259,7 +259,7 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
def update_visit_record!(date)
|
def update_visit_record!(date)
|
||||||
unless has_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)
|
user_visits.create!(visited_at: date)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -316,42 +316,6 @@ class User < ActiveRecord::Base
|
||||||
uploaded_avatar_path || User.gravatar_template(email)
|
uploaded_avatar_path || User.gravatar_template(email)
|
||||||
end
|
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.
|
# The following count methods are somewhat slow - definitely don't use them in a loop.
|
||||||
# They might need to be denormalized
|
# They might need to be denormalized
|
||||||
|
@ -458,20 +422,6 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
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
|
def readable_name
|
||||||
return "#{name} (#{username})" if name.present? && name != username
|
return "#{name} (#{username})" if name.present? && name != username
|
||||||
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
|
where('created_at > ?', sinceDaysAgo.days.ago).group('date(created_at)').order('date(created_at)').count
|
||||||
end
|
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
|
def secure_category_ids
|
||||||
cats = self.staff? ? Category.where(read_restricted: true) : secure_categories.references(:categories)
|
cats = self.staff? ? Category.where(read_restricted: true) : secure_categories.references(:categories)
|
||||||
|
@ -549,7 +487,7 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
def create_user_stat
|
def create_user_stat
|
||||||
stat = UserStat.new
|
stat = UserStat.new
|
||||||
stat.user_id = self.id
|
stat.user_id = id
|
||||||
stat.save!
|
stat.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -647,8 +585,6 @@ end
|
||||||
# approved :boolean default(FALSE), not null
|
# approved :boolean default(FALSE), not null
|
||||||
# approved_by_id :integer
|
# approved_by_id :integer
|
||||||
# approved_at :datetime
|
# approved_at :datetime
|
||||||
# topics_entered :integer default(0), not null
|
|
||||||
# posts_read_count :integer default(0), not null
|
|
||||||
# digest_after_days :integer
|
# digest_after_days :integer
|
||||||
# previous_visit_at :datetime
|
# previous_visit_at :datetime
|
||||||
# banned_at :datetime
|
# banned_at :datetime
|
||||||
|
@ -657,22 +593,18 @@ end
|
||||||
# auto_track_topics_after_msecs :integer
|
# auto_track_topics_after_msecs :integer
|
||||||
# views :integer default(0), not null
|
# views :integer default(0), not null
|
||||||
# flag_level :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
|
# ip_address :string
|
||||||
# new_topic_duration_minutes :integer
|
# new_topic_duration_minutes :integer
|
||||||
# external_links_in_new_tab :boolean default(FALSE), not null
|
# external_links_in_new_tab :boolean default(FALSE), not null
|
||||||
# enable_quoting :boolean default(TRUE), not null
|
# enable_quoting :boolean default(TRUE), not null
|
||||||
# moderator :boolean default(FALSE)
|
# 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)
|
# blocked :boolean default(FALSE)
|
||||||
# dynamic_favicon :boolean default(FALSE), not null
|
# dynamic_favicon :boolean default(FALSE), not null
|
||||||
# title :string(255)
|
# title :string(255)
|
||||||
# use_uploaded_avatar :boolean default(FALSE)
|
# use_uploaded_avatar :boolean default(FALSE)
|
||||||
# uploaded_avatar_template :string(255)
|
# uploaded_avatar_template :string(255)
|
||||||
# uploaded_avatar_id :integer
|
# uploaded_avatar_id :integer
|
||||||
|
# email_always :boolean default(FALSE), not null
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
|
|
|
@ -254,9 +254,9 @@ SQL
|
||||||
|
|
||||||
def self.update_like_count(user_id, action_type, delta)
|
def self.update_like_count(user_id, action_type, delta)
|
||||||
if action_type == LIKE
|
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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,11 @@ end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: staff_action_logs
|
# Table name: user_histories
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
# action :integer not null
|
# action :integer not null
|
||||||
# staff_user_id :integer not null
|
# acting_user_id :integer
|
||||||
# target_user_id :integer
|
# target_user_id :integer
|
||||||
# details :text
|
# details :text
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
|
@ -81,12 +81,13 @@ end
|
||||||
# subject :text
|
# subject :text
|
||||||
# previous_value :text
|
# previous_value :text
|
||||||
# new_value :text
|
# new_value :text
|
||||||
|
# topic_id :integer
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
# index_staff_action_logs_on_action_and_id (action,id)
|
# 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_subject_and_id (subject,id)
|
||||||
# index_staff_action_logs_on_target_user_id_and_id (target_user_id,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
|
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
|
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!
|
def self.ensure_consistency!
|
||||||
exec_sql <<SQL
|
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 <>
|
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
|
SQL
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,5 +44,6 @@ end
|
||||||
# Indexes
|
# 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,
|
:admin,
|
||||||
:moderator,
|
:moderator,
|
||||||
:last_seen_age,
|
:last_seen_age,
|
||||||
:days_visited,
|
|
||||||
:last_emailed_age,
|
:last_emailed_age,
|
||||||
:created_at_age,
|
:created_at_age,
|
||||||
:username_lower,
|
:username_lower,
|
||||||
|
@ -14,9 +13,6 @@ class AdminUserSerializer < BasicUserSerializer
|
||||||
:username,
|
:username,
|
||||||
:title,
|
:title,
|
||||||
:avatar_template,
|
:avatar_template,
|
||||||
:topics_entered,
|
|
||||||
:posts_read_count,
|
|
||||||
:time_read,
|
|
||||||
:can_approve,
|
:can_approve,
|
||||||
:approved,
|
:approved,
|
||||||
:banned_at,
|
:banned_at,
|
||||||
|
@ -26,7 +22,15 @@ class AdminUserSerializer < BasicUserSerializer
|
||||||
:can_send_activation_email,
|
:can_send_activation_email,
|
||||||
:can_activate,
|
:can_activate,
|
||||||
:can_deactivate,
|
: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
|
def is_banned
|
||||||
object.is_banned?
|
object.is_banned?
|
||||||
|
@ -47,8 +51,8 @@ class AdminUserSerializer < BasicUserSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def time_read
|
def time_read
|
||||||
return nil if object.time_read.blank?
|
return nil if object.user_stat.time_read.blank?
|
||||||
AgeWords.age_words(object.time_read)
|
AgeWords.age_words(object.user_stat.time_read)
|
||||||
end
|
end
|
||||||
|
|
||||||
def created_at_age
|
def created_at_age
|
||||||
|
|
|
@ -25,7 +25,7 @@ class CurrentUserSerializer < BasicUserSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def reply_count
|
def reply_count
|
||||||
object.topic_reply_count
|
object.user_stat.topic_reply_count
|
||||||
end
|
end
|
||||||
|
|
||||||
def site_flagged_posts_count
|
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
|
puts s
|
||||||
end
|
end
|
||||||
puts
|
puts
|
||||||
|
queue_specs(specs.zip specs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -425,10 +425,13 @@ class Guardian
|
||||||
private
|
private
|
||||||
|
|
||||||
def is_my_own?(obj)
|
def is_my_own?(obj)
|
||||||
@user.present? &&
|
|
||||||
(obj.respond_to?(:user) || obj.respond_to?(:user_id)) &&
|
unless anonymous?
|
||||||
(obj.respond_to?(:user) ? obj.user == @user : true) &&
|
return obj.user_id == @user.id if obj.respond_to?(:user_id)
|
||||||
(obj.respond_to?(:user_id) ? (obj.user_id == @user.id) : true)
|
return obj.user == @user if obj.respond_to?(:user)
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_me?(other)
|
def is_me?(other)
|
||||||
|
|
|
@ -232,7 +232,8 @@ class PostCreator
|
||||||
def update_user_counts
|
def update_user_counts
|
||||||
# We don't count replies to your own topics
|
# We don't count replies to your own topics
|
||||||
if @user.id != @topic.user_id
|
if @user.id != @topic.user_id
|
||||||
@user.update_topic_reply_count
|
@user.user_stat.update_topic_reply_count
|
||||||
|
@user.user_stat.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
@user.last_posted_at = @post.created_at
|
@user.last_posted_at = @post.created_at
|
||||||
|
|
|
@ -22,9 +22,10 @@ class Promotion
|
||||||
end
|
end
|
||||||
|
|
||||||
def review_newuser
|
def review_newuser
|
||||||
return false if @user.topics_entered < SiteSetting.basic_requires_topics_entered
|
stat = @user.user_stat
|
||||||
return false if @user.posts_read_count < SiteSetting.basic_requires_read_posts
|
return false if stat.topics_entered < SiteSetting.basic_requires_topics_entered
|
||||||
return false if (@user.time_read / 60) < SiteSetting.basic_requires_time_spent_mins
|
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)
|
@user.change_trust_level!(:basic)
|
||||||
|
|
||||||
|
@ -32,13 +33,14 @@ class Promotion
|
||||||
end
|
end
|
||||||
|
|
||||||
def review_basic
|
def review_basic
|
||||||
return false if @user.topics_entered < SiteSetting.regular_requires_topics_entered
|
stat = @user.user_stat
|
||||||
return false if @user.posts_read_count < SiteSetting.regular_requires_read_posts
|
return false if stat.topics_entered < SiteSetting.regular_requires_topics_entered
|
||||||
return false if (@user.time_read / 60) < SiteSetting.regular_requires_time_spent_mins
|
return false if stat.posts_read_count < SiteSetting.regular_requires_read_posts
|
||||||
return false if @user.days_visited < SiteSetting.regular_requires_days_visited
|
return false if (stat.time_read / 60) < SiteSetting.regular_requires_time_spent_mins
|
||||||
return false if @user.likes_received < SiteSetting.regular_requires_likes_received
|
return false if stat.days_visited < SiteSetting.regular_requires_days_visited
|
||||||
return false if @user.likes_given < SiteSetting.regular_requires_likes_given
|
return false if stat.likes_received < SiteSetting.regular_requires_likes_received
|
||||||
return false if @user.topic_reply_count < SiteSetting.regular_requires_topic_reply_count
|
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)
|
@user.change_trust_level!(:regular)
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,9 +39,10 @@ describe BoostTrustLevel do
|
||||||
context "for a user that has done the requisite things to attain their trust level" do
|
context "for a user that has done the requisite things to attain their trust level" do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
user.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
stat = user.user_stat
|
||||||
user.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
stat.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
||||||
user.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
stat.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
||||||
|
stat.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||||
user.save!
|
user.save!
|
||||||
user.update_attributes(trust_level: TrustLevel.levels[:basic])
|
user.update_attributes(trust_level: TrustLevel.levels[:basic])
|
||||||
end
|
end
|
||||||
|
|
|
@ -163,12 +163,15 @@ describe PostCreator do
|
||||||
topic_user.seen_post_count.should == first_post.post_number
|
topic_user.seen_post_count.should == first_post.post_number
|
||||||
|
|
||||||
user2 = Fabricate(:coding_horror)
|
user2 = Fabricate(:coding_horror)
|
||||||
user2.topic_reply_count.should == 0
|
user2.user_stat.topic_reply_count.should == 0
|
||||||
first_post.user.reload.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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,10 @@ describe Promotion do
|
||||||
context "that has done the requisite things" do
|
context "that has done the requisite things" do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
user.topics_entered = SiteSetting.basic_requires_topics_entered
|
stat = user.user_stat
|
||||||
user.posts_read_count = SiteSetting.basic_requires_read_posts
|
stat.topics_entered = SiteSetting.basic_requires_topics_entered
|
||||||
user.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
stat.posts_read_count = SiteSetting.basic_requires_read_posts
|
||||||
|
stat.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||||
@result = promotion.review
|
@result = promotion.review
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,13 +65,14 @@ describe Promotion do
|
||||||
context "that has done the requisite things" do
|
context "that has done the requisite things" do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
user.topics_entered = SiteSetting.regular_requires_topics_entered
|
stat = user.user_stat
|
||||||
user.posts_read_count = SiteSetting.regular_requires_read_posts
|
stat.topics_entered = SiteSetting.regular_requires_topics_entered
|
||||||
user.time_read = SiteSetting.regular_requires_time_spent_mins * 60
|
stat.posts_read_count = SiteSetting.regular_requires_read_posts
|
||||||
user.days_visited = SiteSetting.regular_requires_days_visited * 60
|
stat.time_read = SiteSetting.regular_requires_time_spent_mins * 60
|
||||||
user.likes_received = SiteSetting.regular_requires_likes_received
|
stat.days_visited = SiteSetting.regular_requires_days_visited * 60
|
||||||
user.likes_given = SiteSetting.regular_requires_likes_given
|
stat.likes_received = SiteSetting.regular_requires_likes_received
|
||||||
user.topic_reply_count = SiteSetting.regular_requires_topic_reply_count
|
stat.likes_given = SiteSetting.regular_requires_likes_given
|
||||||
|
stat.topic_reply_count = SiteSetting.regular_requires_topic_reply_count
|
||||||
|
|
||||||
@result = promotion.review
|
@result = promotion.review
|
||||||
end
|
end
|
||||||
|
|
|
@ -145,10 +145,11 @@ describe Admin::UsersController do
|
||||||
|
|
||||||
it "raises an error when demoting a user below their current trust level" do
|
it "raises an error when demoting a user below their current trust level" do
|
||||||
StaffActionLogger.any_instance.expects(:log_trust_level_change).never
|
StaffActionLogger.any_instance.expects(:log_trust_level_change).never
|
||||||
@another_user.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
stat = @another_user.user_stat
|
||||||
@another_user.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
stat.topics_entered = SiteSetting.basic_requires_topics_entered + 1
|
||||||
@another_user.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
stat.posts_read_count = SiteSetting.basic_requires_read_posts + 1
|
||||||
@another_user.save!
|
stat.time_read = SiteSetting.basic_requires_time_spent_mins * 60
|
||||||
|
stat.save!
|
||||||
@another_user.update_attributes(trust_level: TrustLevel.levels[:basic])
|
@another_user.update_attributes(trust_level: TrustLevel.levels[:basic])
|
||||||
xhr :put, :trust_level, user_id: @another_user.id, level: TrustLevel.levels[:newuser]
|
xhr :put, :trust_level, user_id: @another_user.id, level: TrustLevel.levels[:newuser]
|
||||||
response.should be_forbidden
|
response.should be_forbidden
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
Fabricator(:user_action) do
|
Fabricator(:user_action) do
|
||||||
|
|
||||||
user
|
user
|
||||||
action_type UserAction::STAR
|
action_type UserAction::STAR
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
Fabricator(:user_stat) do
|
||||||
|
end
|
||||||
|
|
||||||
Fabricator(:user) do
|
Fabricator(:user) do
|
||||||
name 'Bruce Wayne'
|
name 'Bruce Wayne'
|
||||||
username { sequence(:username) { |i| "bruce#{i}" } }
|
username { sequence(:username) { |i| "bruce#{i}" } }
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe Jobs::PeriodicalUpdates do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "updates view counts" do
|
it "updates view counts" do
|
||||||
User.expects(:update_view_counts).once
|
UserStat.expects(:update_view_counts).once
|
||||||
end
|
end
|
||||||
|
|
||||||
it "calculates scores" do
|
it "calculates scores" do
|
||||||
|
|
|
@ -123,12 +123,12 @@ describe UserAction do
|
||||||
it 'should result in correct data assignment' do
|
it 'should result in correct data assignment' do
|
||||||
@liker_action.should_not be_nil
|
@liker_action.should_not be_nil
|
||||||
@likee_action.should_not be_nil
|
@likee_action.should_not be_nil
|
||||||
likee.reload.likes_received.should == 1
|
likee.user_stat.reload.likes_received.should == 1
|
||||||
liker.reload.likes_given.should == 1
|
liker.user_stat.reload.likes_given.should == 1
|
||||||
|
|
||||||
PostAction.remove_act(liker, post, PostActionType.types[:like])
|
PostAction.remove_act(liker, post, PostActionType.types[:like])
|
||||||
likee.reload.likes_received.should == 0
|
likee.user_stat.reload.likes_received.should == 0
|
||||||
liker.reload.likes_given.should == 0
|
liker.user_stat.reload.likes_given.should == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
require_dependency 'user'
|
||||||
|
|
||||||
describe User do
|
describe User do
|
||||||
|
|
||||||
|
@ -21,66 +22,6 @@ describe User do
|
||||||
it { should validate_presence_of :username }
|
it { should validate_presence_of :username }
|
||||||
it { should validate_presence_of :email }
|
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
|
context '.enqueue_welcome_message' do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
|
@ -266,7 +207,6 @@ describe User do
|
||||||
its(:approved_by_id) { should be_blank }
|
its(:approved_by_id) { should be_blank }
|
||||||
its(:email_private_messages) { should be_true }
|
its(:email_private_messages) { should be_true }
|
||||||
its(:email_direct ) { should be_true }
|
its(:email_direct ) { should be_true }
|
||||||
its(:time_read) { should == 0}
|
|
||||||
|
|
||||||
context 'digest emails' do
|
context 'digest emails' do
|
||||||
it 'defaults to digests every week' do
|
it 'defaults to digests every week' do
|
||||||
|
@ -295,8 +235,6 @@ describe User do
|
||||||
its(:email_tokens) { should be_present }
|
its(:email_tokens) { should be_present }
|
||||||
its(:bio_cooked) { should be_present }
|
its(:bio_cooked) { should be_present }
|
||||||
its(:bio_summary) { should be_present }
|
its(:bio_summary) { should be_present }
|
||||||
its(:topics_entered) { should == 0 }
|
|
||||||
its(:posts_read_count) { should == 0 }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -664,7 +602,7 @@ describe User do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should have 0 for days_visited" do
|
it "should have 0 for days_visited" do
|
||||||
user.days_visited.should == 0
|
user.user_stat.days_visited.should == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with no previous values' do
|
describe 'with no previous values' do
|
||||||
|
@ -685,7 +623,7 @@ describe User do
|
||||||
|
|
||||||
it "should have 0 for days_visited" do
|
it "should have 0 for days_visited" do
|
||||||
user.reload
|
user.reload
|
||||||
user.days_visited.should == 1
|
user.user_stat.days_visited.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should log a user_visit with the date" do
|
it "should log a user_visit with the date" do
|
||||||
|
@ -706,7 +644,7 @@ describe User do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't increase days_visited twice" do
|
it "doesn't increase days_visited twice" do
|
||||||
user.days_visited.should == 1
|
user.user_stat.days_visited.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -811,33 +749,6 @@ describe User do
|
||||||
|
|
||||||
end
|
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
|
describe '#readable_name' do
|
||||||
context 'when name is missing' do
|
context 'when name is missing' do
|
||||||
it 'returns just the username' do
|
it 'returns just the username' do
|
||||||
|
|
|
@ -9,4 +9,96 @@ describe UserStat do
|
||||||
user.user_stat.should be_present
|
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
|
end
|
|
@ -9,13 +9,13 @@ describe UserVisit do
|
||||||
u.update_visit_record!(1.day.ago.to_date)
|
u.update_visit_record!(1.day.ago.to_date)
|
||||||
|
|
||||||
u.reload
|
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
|
u.save
|
||||||
UserVisit.ensure_consistency!
|
UserVisit.ensure_consistency!
|
||||||
|
|
||||||
u.reload
|
u.reload
|
||||||
u.days_visited.should == 2
|
u.user_stat.days_visited.should == 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue