mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-02-17 04:01:29 -05:00
Merge branch 'master' of github.com:discourse/discourse
This commit is contained in:
commit
31c5859bbe
3 changed files with 2138 additions and 84 deletions
|
@ -37,7 +37,7 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
after_save :update_tracked_topics
|
after_save :update_tracked_topics
|
||||||
|
|
||||||
after_create :create_email_token
|
after_create :create_email_token
|
||||||
|
|
||||||
# Whether we need to be sending a system message after creation
|
# Whether we need to be sending a system message after creation
|
||||||
attr_accessor :send_welcome_message
|
attr_accessor :send_welcome_message
|
||||||
|
@ -46,7 +46,7 @@ class User < ActiveRecord::Base
|
||||||
attr_accessor :notification_channel_position
|
attr_accessor :notification_channel_position
|
||||||
|
|
||||||
def self.username_length
|
def self.username_length
|
||||||
3..15
|
3..15
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.suggest_username(name)
|
def self.suggest_username(name)
|
||||||
|
@ -141,7 +141,7 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
# Use a temporary key to find this user, store it in redis with an expiry
|
# Use a temporary key to find this user, store it in redis with an expiry
|
||||||
def temporary_key
|
def temporary_key
|
||||||
key = SecureRandom.hex(32)
|
key = SecureRandom.hex(32)
|
||||||
$redis.setex "temporary_key:#{key}", 1.week, id.to_s
|
$redis.setex "temporary_key:#{key}", 1.week, id.to_s
|
||||||
key
|
key
|
||||||
|
@ -164,7 +164,7 @@ class User < ActiveRecord::Base
|
||||||
def invited_by
|
def invited_by
|
||||||
used_invite = invites.where("redeemed_at is not null").includes(:invited_by).first
|
used_invite = invites.where("redeemed_at is not null").includes(:invited_by).first
|
||||||
return nil unless used_invite.present?
|
return nil unless used_invite.present?
|
||||||
used_invite.invited_by
|
used_invite.invited_by
|
||||||
end
|
end
|
||||||
|
|
||||||
# Approve this user
|
# Approve this user
|
||||||
|
@ -176,11 +176,11 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.email_hash(email)
|
def self.email_hash(email)
|
||||||
Digest::MD5.hexdigest(email)
|
Digest::MD5.hexdigest(email.strip.downcase)
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_hash
|
def email_hash
|
||||||
User.email_hash(self.email)
|
User.email_hash(self.email)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unread_notifications_by_type
|
def unread_notifications_by_type
|
||||||
|
@ -200,12 +200,12 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
def unread_notifications
|
def unread_notifications
|
||||||
result = 0
|
result = 0
|
||||||
unread_notifications_by_type.each do |k,v|
|
unread_notifications_by_type.each do |k,v|
|
||||||
result += v unless k == Notification.Types[:private_message]
|
result += v unless k == Notification.Types[:private_message]
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def saw_notification_id(notification_id)
|
def saw_notification_id(notification_id)
|
||||||
User.update_all ["seen_notification_id = ?", notification_id], ["seen_notification_id < ?", notification_id]
|
User.update_all ["seen_notification_id = ?", notification_id], ["seen_notification_id < ?", notification_id]
|
||||||
end
|
end
|
||||||
|
@ -220,15 +220,15 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
# A selection of people to autocomplete on @mention
|
# A selection of people to autocomplete on @mention
|
||||||
def self.mentionable_usernames
|
def self.mentionable_usernames
|
||||||
User.select(:username).order('last_posted_at desc').limit(20)
|
User.select(:username).order('last_posted_at desc').limit(20)
|
||||||
end
|
end
|
||||||
|
|
||||||
def regular?
|
def regular?
|
||||||
(not admin?) and (not has_trust_level?(:moderator))
|
(not admin?) and (not has_trust_level?(:moderator))
|
||||||
end
|
end
|
||||||
|
|
||||||
def password=(password)
|
def password=(password)
|
||||||
# special case for passwordless accounts
|
# special case for passwordless accounts
|
||||||
unless password.blank?
|
unless password.blank?
|
||||||
@raw_password = password
|
@raw_password = password
|
||||||
end
|
end
|
||||||
|
@ -250,9 +250,9 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
if self.last_seen_at.nil? || self.last_seen_at.to_date < now_date
|
if self.last_seen_at.nil? || self.last_seen_at.to_date < now_date
|
||||||
# count it
|
# count it
|
||||||
row_count = User.exec_sql('insert into user_visits(user_id,visited_at) select :user_id, :visited_at
|
row_count = User.exec_sql('insert into user_visits(user_id,visited_at) select :user_id, :visited_at
|
||||||
where not exists(select 1 from user_visits where user_id = :user_id and visited_at = :visited_at)', user_id: self.id, visited_at: now.to_date)
|
where not exists(select 1 from user_visits where user_id = :user_id and visited_at = :visited_at)', user_id: self.id, visited_at: now.to_date)
|
||||||
if row_count.cmd_tuples == 1
|
if row_count.cmd_tuples == 1
|
||||||
User.update_all "days_visited = days_visited + 1", ["id = ? and days_visited = ?", self.id, self.days_visited]
|
User.update_all "days_visited = days_visited + 1", ["id = ? and days_visited = ?", self.id, self.days_visited]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -291,7 +291,7 @@ class User < ActiveRecord::Base
|
||||||
# Update denormalized topics_entered
|
# Update denormalized topics_entered
|
||||||
exec_sql "UPDATE users SET topics_entered = x.c
|
exec_sql "UPDATE users SET topics_entered = x.c
|
||||||
FROM
|
FROM
|
||||||
(SELECT v.user_id,
|
(SELECT v.user_id,
|
||||||
COUNT(DISTINCT parent_id) AS c
|
COUNT(DISTINCT parent_id) AS c
|
||||||
FROM views AS v
|
FROM views AS v
|
||||||
WHERE parent_type = 'Topic'
|
WHERE parent_type = 'Topic'
|
||||||
|
@ -306,7 +306,7 @@ class User < ActiveRecord::Base
|
||||||
FROM post_timings AS pt
|
FROM post_timings AS pt
|
||||||
GROUP BY pt.user_id) AS X
|
GROUP BY pt.user_id) AS X
|
||||||
WHERE x.user_id = users.id"
|
WHERE x.user_id = users.id"
|
||||||
|
|
||||||
end
|
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.
|
||||||
|
@ -341,7 +341,7 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
# Use this helper to determine if the user has a particular trust level.
|
# Use this helper to determine if the user has a particular trust level.
|
||||||
# Takes into account admin, etc.
|
# Takes into account admin, etc.
|
||||||
def has_trust_level?(level)
|
def has_trust_level?(level)
|
||||||
raise "Invalid trust level #{level}" unless TrustLevel.Levels.has_key?(level)
|
raise "Invalid trust level #{level}" unless TrustLevel.Levels.has_key?(level)
|
||||||
|
|
||||||
# Admins can do everything
|
# Admins can do everything
|
||||||
|
@ -370,19 +370,19 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
if auto_track_topics_after_msecs < 0
|
if auto_track_topics_after_msecs < 0
|
||||||
|
|
||||||
User.exec_sql('update topic_users set notification_level = ?
|
User.exec_sql('update topic_users set notification_level = ?
|
||||||
where notifications_reason_id is null and
|
where notifications_reason_id is null and
|
||||||
user_id = ?' , TopicUser::NotificationLevel::REGULAR , self.id)
|
user_id = ?' , TopicUser::NotificationLevel::REGULAR , self.id)
|
||||||
else
|
else
|
||||||
|
|
||||||
User.exec_sql('update topic_users set notification_level = ?
|
User.exec_sql('update topic_users set notification_level = ?
|
||||||
where notifications_reason_id is null and
|
where notifications_reason_id is null and
|
||||||
user_id = ? and
|
user_id = ? and
|
||||||
total_msecs_viewed < ?' , TopicUser::NotificationLevel::REGULAR , self.id, auto_track_topics_after_msecs)
|
total_msecs_viewed < ?' , TopicUser::NotificationLevel::REGULAR , self.id, auto_track_topics_after_msecs)
|
||||||
|
|
||||||
User.exec_sql('update topic_users set notification_level = ?
|
User.exec_sql('update topic_users set notification_level = ?
|
||||||
where notifications_reason_id is null and
|
where notifications_reason_id is null and
|
||||||
user_id = ? and
|
user_id = ? and
|
||||||
total_msecs_viewed >= ?' , TopicUser::NotificationLevel::TRACKING , self.id, auto_track_topics_after_msecs)
|
total_msecs_viewed >= ?' , TopicUser::NotificationLevel::TRACKING , self.id, auto_track_topics_after_msecs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -396,7 +396,7 @@ class User < ActiveRecord::Base
|
||||||
def ensure_password_is_hashed
|
def ensure_password_is_hashed
|
||||||
if @raw_password
|
if @raw_password
|
||||||
self.salt = SecureRandom.hex(16)
|
self.salt = SecureRandom.hex(16)
|
||||||
self.password_hash = hash_password(@raw_password, salt)
|
self.password_hash = hash_password(@raw_password, salt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -404,27 +404,27 @@ class User < ActiveRecord::Base
|
||||||
PBKDF2.new(:password => password, :salt => salt, :iterations => Rails.configuration.pbkdf2_iterations).hex_string
|
PBKDF2.new(:password => password, :salt => salt, :iterations => Rails.configuration.pbkdf2_iterations).hex_string
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_trust_level
|
def add_trust_level
|
||||||
self.trust_level ||= SiteSetting.default_trust_level
|
self.trust_level ||= SiteSetting.default_trust_level
|
||||||
rescue ActiveModel::MissingAttributeError
|
rescue ActiveModel::MissingAttributeError
|
||||||
# Ignore it, safely - see http://www.tatvartha.com/2011/03/activerecordmissingattributeerror-missing-attribute-a-bug-or-a-features/
|
# Ignore it, safely - see http://www.tatvartha.com/2011/03/activerecordmissingattributeerror-missing-attribute-a-bug-or-a-features/
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_username_lower
|
def update_username_lower
|
||||||
self.username_lower = username.downcase
|
self.username_lower = username.downcase
|
||||||
end
|
end
|
||||||
|
|
||||||
def password_validator
|
def password_validator
|
||||||
if @raw_password
|
if @raw_password
|
||||||
return errors.add(:password, "must be 6 letters or longer") if @raw_password.length < 6
|
return errors.add(:password, "must be 6 letters or longer") if @raw_password.length < 6
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def username_validator
|
def username_validator
|
||||||
unless username
|
unless username
|
||||||
return errors.add(:username, I18n.t(:'user.username.blank'))
|
return errors.add(:username, I18n.t(:'user.username.blank'))
|
||||||
end
|
end
|
||||||
|
|
||||||
if username.length < User.username_length.begin
|
if username.length < User.username_length.begin
|
||||||
return errors.add(:username, I18n.t(:'user.username.short', min: User.username_length.begin))
|
return errors.add(:username, I18n.t(:'user.username.short', min: User.username_length.begin))
|
||||||
end
|
end
|
||||||
|
|
2068
db/structure.sql
2068
db/structure.sql
File diff suppressed because it is too large
Load diff
|
@ -36,7 +36,7 @@ describe User do
|
||||||
it "adds one to the topics entered" do
|
it "adds one to the topics entered" do
|
||||||
User.update_view_counts
|
User.update_view_counts
|
||||||
user.reload
|
user.reload
|
||||||
user.topics_entered.should == 1
|
user.topics_entered.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
it "won't record a second view as a different topic" do
|
it "won't record a second view as a different topic" do
|
||||||
|
@ -44,9 +44,9 @@ describe User do
|
||||||
User.update_view_counts
|
User.update_view_counts
|
||||||
user.reload
|
user.reload
|
||||||
user.topics_entered.should == 1
|
user.topics_entered.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'posts_read_count' do
|
context 'posts_read_count' do
|
||||||
|
@ -58,7 +58,7 @@ describe User do
|
||||||
|
|
||||||
context 'with a post timing' do
|
context 'with a post timing' do
|
||||||
let!(:post) { Fabricate(:post) }
|
let!(:post) { Fabricate(:post) }
|
||||||
let!(:post_timings) do
|
let!(:post_timings) do
|
||||||
PostTiming.record_timing(msecs: 1234, topic_id: post.topic_id, user_id: user.id, post_number: post.post_number)
|
PostTiming.record_timing(msecs: 1234, topic_id: post.topic_id, user_id: user.id, post_number: post.post_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ describe User do
|
||||||
it 'has a value for approved_at' do
|
it 'has a value for approved_at' do
|
||||||
user.approved_at.should be_present
|
user.approved_at.should be_present
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ describe User do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a bookmark with the true parameter" do
|
it "creates a bookmark with the true parameter" do
|
||||||
lambda {
|
lambda {
|
||||||
PostAction.act(@post.user, @post, PostActionType.Types[:bookmark])
|
PostAction.act(@post.user, @post, PostActionType.Types[:bookmark])
|
||||||
}.should change(PostAction, :count).by(1)
|
}.should change(PostAction, :count).by(1)
|
||||||
end
|
end
|
||||||
|
@ -138,7 +138,7 @@ describe User do
|
||||||
|
|
||||||
it 'reduces the bookmark count of the post' do
|
it 'reduces the bookmark count of the post' do
|
||||||
active = PostAction.where(deleted_at: nil)
|
active = PostAction.where(deleted_at: nil)
|
||||||
lambda {
|
lambda {
|
||||||
PostAction.remove_act(@post.user, @post, PostActionType.Types[:bookmark])
|
PostAction.remove_act(@post.user, @post, PostActionType.Types[:bookmark])
|
||||||
}.should change(active, :count).by(-1)
|
}.should change(active, :count).by(-1)
|
||||||
end
|
end
|
||||||
|
@ -195,10 +195,10 @@ describe User do
|
||||||
|
|
||||||
context 'after_save' do
|
context 'after_save' do
|
||||||
before do
|
before do
|
||||||
subject.save
|
subject.save
|
||||||
end
|
end
|
||||||
|
|
||||||
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(:topics_entered) { should == 0 }
|
its(:topics_entered) { should == 0 }
|
||||||
its(:posts_read_count) { should == 0 }
|
its(:posts_read_count) { should == 0 }
|
||||||
|
@ -248,12 +248,12 @@ describe User do
|
||||||
it "is a moderator if the user level is moderator" do
|
it "is a moderator if the user level is moderator" do
|
||||||
user.trust_level = TrustLevel.Levels[:moderator]
|
user.trust_level = TrustLevel.Levels[:moderator]
|
||||||
user.has_trust_level?(:moderator).should be_true
|
user.has_trust_level?(:moderator).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is a moderator if the user is an admin" do
|
it "is a moderator if the user is an admin" do
|
||||||
user.admin = true
|
user.admin = true
|
||||||
user.has_trust_level?(:moderator).should be_true
|
user.has_trust_level?(:moderator).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -283,40 +283,56 @@ describe User do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'email_hash' do
|
describe 'email_hash' do
|
||||||
before do
|
before do
|
||||||
@user = Fabricate(:user)
|
@user = Fabricate(:user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should have a sane email hash' do
|
it 'should have a sane email hash' do
|
||||||
@user.email_hash.should =~ /^[0-9a-f]{32}$/
|
@user.email_hash.should =~ /^[0-9a-f]{32}$/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'should use downcase email' do
|
||||||
|
@user.email = "example@example.com"
|
||||||
|
@user2 = Fabricate(:user)
|
||||||
|
@user2.email = "ExAmPlE@eXaMpLe.com"
|
||||||
|
|
||||||
|
@user.email_hash.should == @user2.email_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should trim whitespace before hashing' do
|
||||||
|
@user.email = "example@example.com"
|
||||||
|
@user2 = Fabricate(:user)
|
||||||
|
@user2.email = " example@example.com "
|
||||||
|
|
||||||
|
@user.email_hash.should == @user2.email_hash
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'name heuristics' do
|
describe 'name heuristics' do
|
||||||
it 'is able to guess a decent username from an email' do
|
it 'is able to guess a decent username from an email' do
|
||||||
User.suggest_username('bob@bob.com').should == 'bob'
|
User.suggest_username('bob@bob.com').should == 'bob'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is able to guess a decent name from an email' do
|
it 'is able to guess a decent name from an email' do
|
||||||
User.suggest_name('sam.saffron@gmail.com').should == 'Sam Saffron'
|
User.suggest_name('sam.saffron@gmail.com').should == 'Sam Saffron'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'username format' do
|
describe 'username format' do
|
||||||
it "should always be 3 chars or longer" do
|
it "should always be 3 chars or longer" do
|
||||||
@user = Fabricate.build(:user)
|
@user = Fabricate.build(:user)
|
||||||
@user.username = 'ss'
|
@user.username = 'ss'
|
||||||
@user.save.should == false
|
@user.save.should == false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should never end with a ." do
|
it "should never end with a ." do
|
||||||
@user = Fabricate.build(:user)
|
@user = Fabricate.build(:user)
|
||||||
@user.username = 'sam.'
|
@user.username = 'sam.'
|
||||||
@user.save.should == false
|
@user.save.should == false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should never contain spaces" do
|
it "should never contain spaces" do
|
||||||
@user = Fabricate.build(:user)
|
@user = Fabricate.build(:user)
|
||||||
@user.username = 'sam s'
|
@user.username = 'sam s'
|
||||||
@user.save.should == false
|
@user.save.should == false
|
||||||
|
@ -337,13 +353,13 @@ describe User do
|
||||||
@user.save!
|
@user.save!
|
||||||
@codinghorror = Fabricate.build(:coding_horror)
|
@codinghorror = Fabricate.build(:coding_horror)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not allow saving if username is reused" do
|
it "should not allow saving if username is reused" do
|
||||||
@codinghorror.username = @user.username
|
@codinghorror.username = @user.username
|
||||||
@codinghorror.save.should be_false
|
@codinghorror.save.should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not allow saving if username is reused in different casing" do
|
it "should not allow saving if username is reused in different casing" do
|
||||||
@codinghorror.username = @user.username.upcase
|
@codinghorror.username = @user.username.upcase
|
||||||
@codinghorror.save.should be_false
|
@codinghorror.save.should be_false
|
||||||
end
|
end
|
||||||
|
@ -359,7 +375,7 @@ describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.suggest_username' do
|
describe '.suggest_username' do
|
||||||
it 'corrects weird characters' do
|
it 'corrects weird characters' do
|
||||||
User.suggest_username("Darth%^Vadar").should == "Darth_Vadar"
|
User.suggest_username("Darth%^Vadar").should == "Darth_Vadar"
|
||||||
end
|
end
|
||||||
|
@ -384,7 +400,7 @@ describe User do
|
||||||
it "makes room for the digit added if the username is too long" do
|
it "makes room for the digit added if the username is too long" do
|
||||||
User.create(username: 'myreallylongnam', email: 'fake@discourse.org')
|
User.create(username: 'myreallylongnam', email: 'fake@discourse.org')
|
||||||
User.suggest_username("myreallylongnam").should == 'myreallylongna1'
|
User.suggest_username("myreallylongnam").should == 'myreallylongna1'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes leading character if it is not alphanumeric" do
|
it "removes leading character if it is not alphanumeric" do
|
||||||
User.suggest_username("_myname").should == 'myname'
|
User.suggest_username("_myname").should == 'myname'
|
||||||
|
@ -411,18 +427,18 @@ describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'passwords' do
|
describe 'passwords' do
|
||||||
before do
|
before do
|
||||||
@user = Fabricate.build(:user)
|
@user = Fabricate.build(:user)
|
||||||
@user.password = "ilovepasta"
|
@user.password = "ilovepasta"
|
||||||
@user.save!
|
@user.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should have a valid password after the initial save" do
|
it "should have a valid password after the initial save" do
|
||||||
@user.confirm_password?("ilovepasta").should be_true
|
@user.confirm_password?("ilovepasta").should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not have an active account after initial save" do
|
it "should not have an active account after initial save" do
|
||||||
@user.active.should be_false
|
@user.active.should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -509,10 +525,10 @@ describe User do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "last_seen_at" do
|
describe "last_seen_at" do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
it "should have a blank last seen on creation" do
|
it "should have a blank last seen on creation" do
|
||||||
user.last_seen_at.should be_nil
|
user.last_seen_at.should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -535,11 +551,11 @@ 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.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
|
||||||
user.user_visits.first.visited_at.should == date.to_date
|
user.user_visits.first.visited_at.should == date.to_date
|
||||||
end
|
end
|
||||||
|
|
||||||
context "called twice" do
|
context "called twice" do
|
||||||
|
|
||||||
|
@ -571,7 +587,7 @@ describe User do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue