2013-02-05 14:16:51 -05:00
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe User do
|
|
|
|
|
|
|
|
it { should have_many :posts }
|
|
|
|
it { should have_many :notifications }
|
|
|
|
it { should have_many :topic_users }
|
|
|
|
it { should have_many :post_actions }
|
|
|
|
it { should have_many :user_actions }
|
|
|
|
it { should have_many :topics }
|
|
|
|
it { should have_many :user_open_ids }
|
|
|
|
it { should have_many :post_timings }
|
|
|
|
it { should have_many :email_tokens }
|
|
|
|
it { should have_many :views }
|
|
|
|
it { should have_many :user_visits }
|
|
|
|
it { should belong_to :approved_by }
|
2013-03-28 19:24:35 -04:00
|
|
|
it { should have_many :email_logs }
|
|
|
|
it { should have_many :topic_allowed_users }
|
|
|
|
it { should have_many :invites }
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
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) }
|
|
|
|
|
|
|
|
it "adds one to the topics entered" do
|
|
|
|
User.update_view_counts
|
|
|
|
user.reload
|
2013-02-05 21:44:49 -05:00
|
|
|
user.topics_entered.should == 1
|
2013-02-05 14:16:51 -05:00
|
|
|
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
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
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) }
|
2013-02-05 21:44:49 -05:00
|
|
|
let!(:post_timings) do
|
2013-02-05 14:16:51 -05:00
|
|
|
PostTiming.record_timing(msecs: 1234, topic_id: post.topic_id, user_id: user.id, post_number: post.post_number)
|
|
|
|
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) }
|
|
|
|
|
|
|
|
it 'enqueues the system message' do
|
|
|
|
Jobs.expects(:enqueue).with(:send_system_message, user_id: user.id, message_type: 'welcome_user')
|
|
|
|
user.enqueue_welcome_message('welcome_user')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't enqueue the system message when the site settings disable it" do
|
|
|
|
SiteSetting.expects(:send_welcome_message?).returns(false)
|
|
|
|
Jobs.expects(:enqueue).with(:send_system_message, user_id: user.id, message_type: 'welcome_user').never
|
|
|
|
user.enqueue_welcome_message('welcome_user')
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-02-28 08:08:56 -05:00
|
|
|
describe '.approve' do
|
2013-02-05 14:16:51 -05:00
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
let(:admin) { Fabricate(:admin) }
|
|
|
|
|
2013-06-05 23:16:31 -04:00
|
|
|
it "enqueues a 'signup after approval' email" do
|
|
|
|
Jobs.expects(:enqueue).with(
|
|
|
|
:user_email, has_entries(type: :signup_after_approval)
|
|
|
|
)
|
2013-02-05 14:16:51 -05:00
|
|
|
user.approve(admin)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'after approval' do
|
|
|
|
before do
|
|
|
|
user.approve(admin)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'marks the user as approved' do
|
|
|
|
user.should be_approved
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'has the admin as the approved by' do
|
|
|
|
user.approved_by.should == admin
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'has a value for approved_at' do
|
|
|
|
user.approved_at.should be_present
|
|
|
|
end
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
describe 'bookmark' do
|
|
|
|
before do
|
|
|
|
@post = Fabricate(:post)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates a bookmark with the true parameter" do
|
2013-02-05 21:44:49 -05:00
|
|
|
lambda {
|
2013-03-01 07:07:44 -05:00
|
|
|
PostAction.act(@post.user, @post, PostActionType.types[:bookmark])
|
2013-02-05 14:16:51 -05:00
|
|
|
}.should change(PostAction, :count).by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when removing a bookmark' do
|
|
|
|
before do
|
2013-03-01 07:07:44 -05:00
|
|
|
PostAction.act(@post.user, @post, PostActionType.types[:bookmark])
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'reduces the bookmark count of the post' do
|
|
|
|
active = PostAction.where(deleted_at: nil)
|
2013-02-05 21:44:49 -05:00
|
|
|
lambda {
|
2013-03-01 07:07:44 -05:00
|
|
|
PostAction.remove_act(@post.user, @post, PostActionType.types[:bookmark])
|
2013-02-05 14:16:51 -05:00
|
|
|
}.should change(active, :count).by(-1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'change_username' do
|
|
|
|
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
context 'success' do
|
|
|
|
let(:new_username) { "#{user.username}1234" }
|
|
|
|
|
|
|
|
before do
|
|
|
|
@result = user.change_username(new_username)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns true' do
|
|
|
|
@result.should be_true
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should change the username' do
|
|
|
|
user.reload
|
|
|
|
user.username.should == new_username
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should change the username_lower' do
|
|
|
|
user.reload
|
|
|
|
user.username_lower.should == new_username.downcase
|
|
|
|
end
|
2013-03-28 19:24:35 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'failure' do
|
|
|
|
let(:wrong_username) { "" }
|
|
|
|
let(:username_before_change) { user.username }
|
|
|
|
let(:username_lower_before_change) { user.username_lower }
|
|
|
|
|
|
|
|
before do
|
|
|
|
@result = user.change_username(wrong_username)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
@result.should be_false
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should not change the username' do
|
|
|
|
user.reload
|
|
|
|
user.username.should == username_before_change
|
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2013-03-28 19:24:35 -04:00
|
|
|
it 'should not change the username_lower' do
|
|
|
|
user.reload
|
|
|
|
user.username_lower.should == username_lower_before_change
|
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-02-25 11:42:20 -05:00
|
|
|
describe 'delete posts' do
|
|
|
|
before do
|
2013-02-07 02:11:56 -05:00
|
|
|
@post1 = Fabricate(:post)
|
|
|
|
@user = @post1.user
|
|
|
|
@post2 = Fabricate(:post, topic: @post1.topic, user: @user)
|
|
|
|
@post3 = Fabricate(:post, user: @user)
|
|
|
|
@posts = [@post1, @post2, @post3]
|
|
|
|
@guardian = Guardian.new(Fabricate(:admin))
|
|
|
|
end
|
|
|
|
|
2013-02-25 11:42:20 -05:00
|
|
|
it 'allows moderator to delete all posts' do
|
2013-02-07 02:11:56 -05:00
|
|
|
@user.delete_all_posts!(@guardian)
|
2013-06-05 16:00:45 -04:00
|
|
|
expect(Post.where(id: @posts.map(&:id)).all).to be_empty
|
2013-02-07 02:11:56 -05:00
|
|
|
@posts.each do |p|
|
2013-06-05 16:00:45 -04:00
|
|
|
if p.post_number == 1
|
|
|
|
expect(Topic.where(id: p.topic_id).first).to be_nil
|
2013-02-07 02:11:56 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-03-28 19:24:35 -04:00
|
|
|
|
|
|
|
it 'does not allow non moderators to delete all posts' do
|
|
|
|
invalid_guardian = Guardian.new(Fabricate(:user))
|
|
|
|
|
|
|
|
expect do
|
|
|
|
@user.delete_all_posts!(invalid_guardian)
|
|
|
|
end.to raise_error Discourse::InvalidAccess
|
|
|
|
|
|
|
|
@posts.each do |p|
|
|
|
|
p.reload
|
|
|
|
p.should be_present
|
|
|
|
p.topic.should be_present
|
|
|
|
end
|
|
|
|
end
|
2013-02-07 02:11:56 -05:00
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
describe 'new' do
|
|
|
|
|
|
|
|
subject { Fabricate.build(:user) }
|
|
|
|
|
|
|
|
it { should be_valid }
|
|
|
|
it { should_not be_admin }
|
|
|
|
it { should_not be_active }
|
|
|
|
it { should_not be_approved }
|
|
|
|
its(:approved_at) { should be_blank }
|
|
|
|
its(:approved_by_id) { should be_blank }
|
|
|
|
its(:email_digests) { should be_true }
|
|
|
|
its(:email_private_messages) { should be_true }
|
|
|
|
its(:email_direct ) { should be_true }
|
|
|
|
its(:time_read) { should == 0}
|
|
|
|
|
|
|
|
# Default to digests after one week
|
|
|
|
its(:digest_after_days) { should == 7 }
|
|
|
|
|
|
|
|
context 'after_save' do
|
|
|
|
before do
|
2013-02-05 21:44:49 -05:00
|
|
|
subject.save
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
its(:email_tokens) { should be_present }
|
2013-02-05 14:16:51 -05:00
|
|
|
its(:bio_cooked) { should be_present }
|
2013-03-08 15:04:37 -05:00
|
|
|
its(:bio_summary) { should be_present }
|
2013-02-05 14:16:51 -05:00
|
|
|
its(:topics_entered) { should == 0 }
|
|
|
|
its(:posts_read_count) { should == 0 }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "trust levels" do
|
2013-03-20 00:05:19 -04:00
|
|
|
|
2013-05-10 16:58:23 -04:00
|
|
|
# NOTE be sure to use build to avoid db calls
|
2013-04-17 19:11:13 -04:00
|
|
|
let(:user) { Fabricate.build(:user, trust_level: TrustLevel.levels[:newuser]) }
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
it "sets to the default trust level setting" do
|
2013-03-20 00:05:19 -04:00
|
|
|
SiteSetting.expects(:default_trust_level).returns(TrustLevel.levels[:elder])
|
|
|
|
User.new.trust_level.should == TrustLevel.levels[:elder]
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-02-28 08:08:56 -05:00
|
|
|
describe 'has_trust_level?' do
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
it "raises an error with an invalid level" do
|
|
|
|
lambda { user.has_trust_level?(:wat) }.should raise_error
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is true for your basic level" do
|
2013-04-17 19:11:13 -04:00
|
|
|
user.has_trust_level?(:newuser).should be_true
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false for a higher level" do
|
2013-03-20 00:05:19 -04:00
|
|
|
user.has_trust_level?(:regular).should be_false
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is true if you exceed the level" do
|
2013-03-20 00:05:19 -04:00
|
|
|
user.trust_level = TrustLevel.levels[:elder]
|
2013-04-17 19:11:13 -04:00
|
|
|
user.has_trust_level?(:newuser).should be_true
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is true for an admin even with a low trust level" do
|
2013-03-01 07:07:44 -05:00
|
|
|
user.trust_level = TrustLevel.levels[:new]
|
2013-02-05 14:16:51 -05:00
|
|
|
user.admin = true
|
2013-03-20 00:05:19 -04:00
|
|
|
user.has_trust_level?(:elder).should be_true
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'moderator' do
|
|
|
|
it "isn't a moderator by default" do
|
2013-03-20 00:05:19 -04:00
|
|
|
user.moderator?.should be_false
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is a moderator if the user level is moderator" do
|
2013-03-20 00:05:19 -04:00
|
|
|
user.moderator = true
|
|
|
|
user.has_trust_level?(:elder).should be_true
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2013-05-02 03:22:27 -04:00
|
|
|
it "is staff if the user is an admin" do
|
2013-02-05 14:16:51 -05:00
|
|
|
user.admin = true
|
2013-05-02 03:22:27 -04:00
|
|
|
user.staff?.should be_true
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-05-18 04:07:07 -04:00
|
|
|
describe 'staff and regular users' do
|
|
|
|
let(:user) { Fabricate.build(:user) }
|
|
|
|
|
|
|
|
describe '#staff?' do
|
|
|
|
subject { user.staff? }
|
|
|
|
|
|
|
|
it { should be_false }
|
|
|
|
|
|
|
|
context 'for a moderator user' do
|
|
|
|
before { user.moderator = true }
|
|
|
|
|
|
|
|
it { should be_true }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'for an admin user' do
|
|
|
|
before { user.admin = true }
|
|
|
|
|
|
|
|
it { should be_true }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#regular?' do
|
|
|
|
subject { user.regular? }
|
|
|
|
|
|
|
|
it { should be_true }
|
|
|
|
|
|
|
|
context 'for a moderator user' do
|
|
|
|
before { user.moderator = true }
|
|
|
|
|
|
|
|
it { should be_false }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'for an admin user' do
|
|
|
|
before { user.admin = true }
|
|
|
|
|
|
|
|
it { should be_false }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
describe 'temporary_key' do
|
|
|
|
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
let!(:temporary_key) { user.temporary_key}
|
|
|
|
|
|
|
|
it 'has a temporary key' do
|
|
|
|
temporary_key.should be_present
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'User#find_by_temporary_key' do
|
|
|
|
|
|
|
|
it 'can be used to find the user' do
|
|
|
|
User.find_by_temporary_key(temporary_key).should == user
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns nil with an invalid key' do
|
|
|
|
User.find_by_temporary_key('asdfasdf').should be_blank
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
describe 'email_hash' do
|
|
|
|
before do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user = Fabricate(:user)
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
it 'should have a sane email hash' do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user.email_hash.should =~ /^[0-9a-f]{32}$/
|
2013-02-05 21:44:49 -05:00
|
|
|
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
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
describe 'name heuristics' do
|
|
|
|
it 'is able to guess a decent name from an email' do
|
2013-02-05 14:16:51 -05:00
|
|
|
User.suggest_name('sam.saffron@gmail.com').should == 'Sam Saffron'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
describe 'username format' do
|
|
|
|
it "should always be 3 chars or longer" do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user = Fabricate.build(:user)
|
|
|
|
@user.username = 'ss'
|
|
|
|
@user.save.should == false
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
it "should never end with a ." do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user = Fabricate.build(:user)
|
|
|
|
@user.username = 'sam.'
|
|
|
|
@user.save.should == false
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
it "should never contain spaces" do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user = Fabricate.build(:user)
|
|
|
|
@user.username = 'sam s'
|
|
|
|
@user.save.should == false
|
|
|
|
end
|
|
|
|
|
|
|
|
['Bad One', 'Giraf%fe', 'Hello!', '@twitter', 'me@example.com', 'no.dots', 'purple.', '.bilbo', '_nope', 'sa$sy'].each do |bad_nickname|
|
|
|
|
it "should not allow username '#{bad_nickname}'" do
|
|
|
|
@user = Fabricate.build(:user)
|
|
|
|
@user.username = bad_nickname
|
|
|
|
@user.save.should == false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'username uniqueness' do
|
|
|
|
before do
|
|
|
|
@user = Fabricate.build(:user)
|
|
|
|
@user.save!
|
|
|
|
@codinghorror = Fabricate.build(:coding_horror)
|
|
|
|
end
|
2013-02-05 21:44:49 -05:00
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
it "should not allow saving if username is reused" do
|
|
|
|
@codinghorror.username = @user.username
|
|
|
|
@codinghorror.save.should be_false
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
it "should not allow saving if username is reused in different casing" do
|
2013-02-05 14:16:51 -05:00
|
|
|
@codinghorror.username = @user.username.upcase
|
|
|
|
@codinghorror.save.should be_false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context '.username_available?' do
|
|
|
|
it "returns true for a username that is available" do
|
|
|
|
User.username_available?('BruceWayne').should be_true
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false when a username is taken' do
|
|
|
|
User.username_available?(Fabricate(:user).username).should be_false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-13 12:28:23 -05:00
|
|
|
describe 'email_validator' do
|
|
|
|
it 'should allow good emails' do
|
|
|
|
user = Fabricate.build(:user, email: 'good@gmail.com')
|
|
|
|
user.should be_valid
|
|
|
|
end
|
|
|
|
|
2013-02-13 22:24:32 -05:00
|
|
|
it 'should reject some emails based on the email_domains_blacklist site setting' do
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('mailinator.com')
|
2013-02-13 12:28:23 -05:00
|
|
|
Fabricate.build(:user, email: 'notgood@mailinator.com').should_not be_valid
|
|
|
|
Fabricate.build(:user, email: 'mailinator@gmail.com').should be_valid
|
|
|
|
end
|
|
|
|
|
2013-02-13 22:24:32 -05:00
|
|
|
it 'should reject some emails based on the email_domains_blacklist site setting' do
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('mailinator.com|trashmail.net')
|
2013-02-13 12:28:23 -05:00
|
|
|
Fabricate.build(:user, email: 'notgood@mailinator.com').should_not be_valid
|
2013-02-13 22:24:32 -05:00
|
|
|
Fabricate.build(:user, email: 'notgood@trashmail.net').should_not be_valid
|
|
|
|
Fabricate.build(:user, email: 'mailinator.com@gmail.com').should be_valid
|
2013-02-13 12:28:23 -05:00
|
|
|
end
|
2013-03-31 12:51:13 -04:00
|
|
|
|
2013-03-18 15:48:56 -04:00
|
|
|
it 'should not reject partial matches' do
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('mail.com')
|
|
|
|
Fabricate.build(:user, email: 'mailinator@gmail.com').should be_valid
|
|
|
|
end
|
2013-03-31 12:51:13 -04:00
|
|
|
|
2013-02-13 22:24:32 -05:00
|
|
|
it 'should reject some emails based on the email_domains_blacklist site setting ignoring case' do
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('trashmail.net')
|
|
|
|
Fabricate.build(:user, email: 'notgood@TRASHMAIL.NET').should_not be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should not interpret a period as a wildcard' do
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('trashmail.net')
|
|
|
|
Fabricate.build(:user, email: 'good@trashmailinet.com').should be_valid
|
2013-02-13 12:28:23 -05:00
|
|
|
end
|
2013-02-20 12:16:01 -05:00
|
|
|
|
|
|
|
it 'should not be used to validate existing records' do
|
|
|
|
u = Fabricate(:user, email: 'in_before_blacklisted@fakemail.com')
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('fakemail.com')
|
|
|
|
u.should be_valid
|
|
|
|
end
|
2013-02-20 16:24:52 -05:00
|
|
|
|
|
|
|
it 'should be used when email is being changed' do
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('mailinator.com')
|
|
|
|
u = Fabricate(:user, email: 'good@gmail.com')
|
|
|
|
u.email = 'nope@mailinator.com'
|
|
|
|
u.should_not be_valid
|
2013-03-18 15:48:56 -04:00
|
|
|
end
|
2013-03-31 12:51:13 -04:00
|
|
|
|
2013-03-18 15:48:56 -04:00
|
|
|
it 'whitelist should reject some emails based on the email_domains_whitelist site setting' do
|
|
|
|
SiteSetting.stubs(:email_domains_whitelist).returns('vaynermedia.com')
|
|
|
|
Fabricate.build(:user, email: 'notgood@mailinator.com').should_not be_valid
|
|
|
|
Fabricate.build(:user, email: 'sbauch@vaynermedia.com').should be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should reject some emails based on the email_domains_whitelist site setting when whitelisting multiple domains' do
|
|
|
|
SiteSetting.stubs(:email_domains_whitelist).returns('vaynermedia.com|gmail.com')
|
|
|
|
Fabricate.build(:user, email: 'notgood@mailinator.com').should_not be_valid
|
|
|
|
Fabricate.build(:user, email: 'notgood@trashmail.net').should_not be_valid
|
|
|
|
Fabricate.build(:user, email: 'mailinator.com@gmail.com').should be_valid
|
|
|
|
Fabricate.build(:user, email: 'mailinator.com@vaynermedia.com').should be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should accept some emails based on the email_domains_whitelist site setting ignoring case' do
|
|
|
|
SiteSetting.stubs(:email_domains_whitelist).returns('vaynermedia.com')
|
|
|
|
Fabricate.build(:user, email: 'good@VAYNERMEDIA.COM').should be_valid
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'email whitelist should not be used to validate existing records' do
|
|
|
|
u = Fabricate(:user, email: 'in_before_whitelisted@fakemail.com')
|
|
|
|
SiteSetting.stubs(:email_domains_blacklist).returns('vaynermedia.com')
|
|
|
|
u.should be_valid
|
|
|
|
end
|
|
|
|
|
2013-03-31 12:51:13 -04:00
|
|
|
it 'email whitelist should be used when email is being changed' do
|
2013-03-18 15:48:56 -04:00
|
|
|
SiteSetting.stubs(:email_domains_whitelist).returns('vaynermedia.com')
|
|
|
|
u = Fabricate(:user, email: 'good@vaynermedia.com')
|
|
|
|
u.email = 'nope@mailinator.com'
|
|
|
|
u.should_not be_valid
|
2013-02-20 16:24:52 -05:00
|
|
|
end
|
2013-02-13 12:28:23 -05:00
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
describe 'passwords' do
|
|
|
|
before do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user = Fabricate.build(:user)
|
2013-02-05 21:44:49 -05:00
|
|
|
@user.password = "ilovepasta"
|
2013-02-05 14:16:51 -05:00
|
|
|
@user.save!
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
it "should have a valid password after the initial save" do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user.confirm_password?("ilovepasta").should be_true
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
it "should not have an active account after initial save" do
|
2013-02-05 14:16:51 -05:00
|
|
|
@user.active.should be_false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'changing bio' do
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
user.bio_raw = "**turtle power!**"
|
|
|
|
user.save
|
|
|
|
user.reload
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should markdown the raw_bio and put it in cooked_bio" do
|
|
|
|
user.bio_cooked.should == "<p><strong>turtle power!</strong></p>"
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "previous_visit_at" do
|
2013-06-27 17:23:06 -04:00
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
let(:user) { Fabricate(:user) }
|
2013-06-28 01:38:47 -04:00
|
|
|
let!(:first_visit_date) { Time.zone.now }
|
|
|
|
let!(:second_visit_date) { 2.hours.from_now }
|
|
|
|
let!(:third_visit_date) { 5.hours.from_now }
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
before do
|
|
|
|
SiteSetting.stubs(:active_user_rate_limit_secs).returns(0)
|
2013-06-28 02:07:36 -04:00
|
|
|
SiteSetting.stubs(:previous_visit_timeout_hours).returns(1)
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-06-28 01:38:47 -04:00
|
|
|
it "should act correctly" do
|
2013-02-05 14:16:51 -05:00
|
|
|
user.previous_visit_at.should be_nil
|
|
|
|
|
2013-06-28 01:38:47 -04:00
|
|
|
# first visit
|
|
|
|
user.update_last_seen!(first_visit_date)
|
|
|
|
user.previous_visit_at.should be_nil
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2013-06-28 02:07:36 -04:00
|
|
|
# updated same time
|
|
|
|
user.update_last_seen!(first_visit_date)
|
|
|
|
user.reload
|
|
|
|
user.previous_visit_at.should be_nil
|
|
|
|
|
2013-06-28 01:38:47 -04:00
|
|
|
# second visit
|
|
|
|
user.update_last_seen!(second_visit_date)
|
|
|
|
user.reload
|
|
|
|
user.previous_visit_at.should be_within_one_second_of(first_visit_date)
|
2013-02-05 14:16:51 -05:00
|
|
|
|
2013-06-28 01:38:47 -04:00
|
|
|
# third visit
|
|
|
|
user.update_last_seen!(third_visit_date)
|
|
|
|
user.reload
|
|
|
|
user.previous_visit_at.should be_within_one_second_of(second_visit_date)
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-02-05 21:44:49 -05:00
|
|
|
describe "last_seen_at" do
|
2013-02-05 14:16:51 -05:00
|
|
|
let(:user) { Fabricate(:user) }
|
2013-02-05 21:44:49 -05:00
|
|
|
|
|
|
|
it "should have a blank last seen on creation" do
|
2013-02-05 14:16:51 -05:00
|
|
|
user.last_seen_at.should be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should have 0 for days_visited" do
|
|
|
|
user.days_visited.should == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'with no previous values' do
|
2013-06-27 17:23:06 -04:00
|
|
|
let!(:date) { Time.zone.now }
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
before do
|
2013-06-27 17:23:06 -04:00
|
|
|
Timecop.freeze(date)
|
2013-02-05 14:16:51 -05:00
|
|
|
user.update_last_seen!
|
|
|
|
end
|
|
|
|
|
2013-06-27 17:23:06 -04:00
|
|
|
after do
|
|
|
|
Timecop.return
|
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
it "updates last_seen_at" do
|
2013-06-27 17:23:06 -04:00
|
|
|
user.last_seen_at.should be_within_one_second_of(date)
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should have 0 for days_visited" do
|
|
|
|
user.reload
|
|
|
|
user.days_visited.should == 1
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
it "should log a user_visit with the date" do
|
|
|
|
user.user_visits.first.visited_at.should == date.to_date
|
2013-02-05 21:44:49 -05:00
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
|
|
|
|
context "called twice" do
|
|
|
|
|
|
|
|
before do
|
2013-06-27 17:23:06 -04:00
|
|
|
Timecop.freeze(date)
|
2013-02-05 14:16:51 -05:00
|
|
|
user.update_last_seen!
|
|
|
|
user.update_last_seen!
|
|
|
|
user.reload
|
|
|
|
end
|
|
|
|
|
2013-06-27 17:23:06 -04:00
|
|
|
after do
|
|
|
|
Timecop.return
|
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
it "doesn't increase days_visited twice" do
|
|
|
|
user.days_visited.should == 1
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "after 3 days" do
|
|
|
|
let!(:future_date) { 3.days.from_now }
|
|
|
|
|
|
|
|
before do
|
2013-06-27 17:23:06 -04:00
|
|
|
Timecop.freeze(future_date)
|
2013-02-05 14:16:51 -05:00
|
|
|
user.update_last_seen!
|
|
|
|
end
|
|
|
|
|
2013-06-27 17:23:06 -04:00
|
|
|
after do
|
|
|
|
Timecop.return
|
|
|
|
end
|
|
|
|
|
2013-02-05 14:16:51 -05:00
|
|
|
it "should log a second visited_at record when we log an update later" do
|
|
|
|
user.user_visits.count.should == 2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#create_for_email' do
|
2013-03-31 12:51:13 -04:00
|
|
|
let(:subject) { User.create_for_email('walter.white@email.com') }
|
2013-02-05 14:16:51 -05:00
|
|
|
it { should be_present }
|
2013-03-31 12:51:13 -04:00
|
|
|
its(:username) { should == 'walter_white' }
|
|
|
|
its(:name) { should == 'walter_white'}
|
2013-02-05 14:16:51 -05:00
|
|
|
it { should_not be_active }
|
2013-03-31 12:51:13 -04:00
|
|
|
its(:email) { should == 'walter.white@email.com' }
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|
|
|
|
|
2013-02-11 11:18:26 -05:00
|
|
|
describe 'email_confirmed?' do
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
context 'when email has not been confirmed yet' do
|
|
|
|
it 'should return false' do
|
|
|
|
user.email_confirmed?.should be_false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when email has been confirmed' do
|
|
|
|
it 'should return true' do
|
|
|
|
token = user.email_tokens.where(email: user.email).first
|
|
|
|
EmailToken.confirm(token.token)
|
|
|
|
user.email_confirmed?.should be_true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when user has no email tokens for some reason' do
|
|
|
|
it 'should return false' do
|
|
|
|
user.email_tokens.each {|t| t.destroy}
|
|
|
|
user.reload
|
2013-02-12 10:12:32 -05:00
|
|
|
user.email_confirmed?.should be_true
|
2013-02-11 11:18:26 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-05-10 16:58:23 -04:00
|
|
|
describe "flag_linked_posts_as_spam" do
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
let!(:admin) { Fabricate(:admin) }
|
|
|
|
let!(:post) { PostCreator.new(user, title: "this topic contains spam", raw: "this post has a link: http://discourse.org").create }
|
|
|
|
let!(:another_post) { PostCreator.new(user, title: "this topic also contains spam", raw: "this post has a link: http://discourse.org/asdfa").create }
|
|
|
|
let!(:post_without_link) { PostCreator.new(user, title: "this topic shouldn't be spam", raw: "this post has no links in it.").create }
|
|
|
|
|
|
|
|
it "has flagged all the user's posts as spam" do
|
|
|
|
user.flag_linked_posts_as_spam
|
|
|
|
|
|
|
|
post.reload
|
|
|
|
post.spam_count.should == 1
|
|
|
|
|
|
|
|
another_post.reload
|
|
|
|
another_post.spam_count.should == 1
|
|
|
|
|
|
|
|
post_without_link.reload
|
|
|
|
post_without_link.spam_count.should == 0
|
|
|
|
|
|
|
|
# It doesn't raise an exception if called again
|
|
|
|
user.flag_linked_posts_as_spam
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
2013-02-25 02:42:42 -05:00
|
|
|
|
2013-06-05 15:28:10 -04:00
|
|
|
describe "bio link stripping" do
|
2013-06-04 12:05:36 -04:00
|
|
|
|
|
|
|
it "returns an empty string with no bio" do
|
|
|
|
expect(Fabricate.build(:user).bio_excerpt).to be_blank
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with a user that has a link in their bio" do
|
|
|
|
let(:user) { Fabricate.build(:user, bio_raw: "im sissy and i love http://ponycorns.com") }
|
|
|
|
|
|
|
|
before do
|
|
|
|
# Let's cook that bio up good
|
|
|
|
user.send(:cook)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "includes the link if the user is not new" do
|
|
|
|
expect(user.bio_excerpt).to eq("im sissy and i love <a href='http://ponycorns.com' rel='nofollow'>http://ponycorns.com</a>")
|
2013-06-05 15:28:10 -04:00
|
|
|
expect(user.bio_processed).to eq("<p>im sissy and i love <a href=\"http://ponycorns.com\" rel=\"nofollow\">http://ponycorns.com</a></p>")
|
2013-06-04 12:05:36 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "removes the link if the user is new" do
|
|
|
|
user.trust_level = TrustLevel.levels[:newuser]
|
|
|
|
expect(user.bio_excerpt).to eq("im sissy and i love http://ponycorns.com")
|
2013-06-05 15:28:10 -04:00
|
|
|
expect(user.bio_processed).to eq("<p>im sissy and i love http://ponycorns.com</p>")
|
2013-06-04 12:05:36 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2013-02-25 11:42:20 -05:00
|
|
|
describe 'update_time_read!' do
|
2013-02-25 02:42:42 -05:00
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
2013-02-25 11:42:20 -05:00
|
|
|
it 'makes no changes if nothing is cached' do
|
2013-02-25 02:42:42 -05:00
|
|
|
$redis.expects(:get).with("user-last-seen:#{user.id}").returns(nil)
|
|
|
|
user.update_time_read!
|
|
|
|
user.reload
|
|
|
|
user.time_read.should == 0
|
|
|
|
end
|
|
|
|
|
2013-02-25 11:42:20 -05:00
|
|
|
it 'makes a change if time read is below threshold' do
|
2013-02-25 02:42:42 -05:00
|
|
|
$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
|
|
|
|
|
2013-02-25 11:42:20 -05:00
|
|
|
it 'makes no change if time read is above threshold' do
|
2013-02-25 02:42:42 -05:00
|
|
|
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
|
|
|
|
|
2013-02-21 13:20:00 -05:00
|
|
|
describe '#readable_name' do
|
|
|
|
context 'when name is missing' do
|
|
|
|
it 'returns just the username' do
|
|
|
|
Fabricate(:user, username: 'foo', name: nil).readable_name.should == 'foo'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
context 'when name and username are identical' do
|
|
|
|
it 'returns just the username' do
|
|
|
|
Fabricate(:user, username: 'foo', name: 'foo').readable_name.should == 'foo'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
context 'when name and username are not identical' do
|
|
|
|
it 'returns the name and username' do
|
|
|
|
Fabricate(:user, username: 'foo', name: 'Bar Baz').readable_name.should == 'Bar Baz (foo)'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-18 20:31:19 -04:00
|
|
|
describe '#find_by_username_or_email' do
|
|
|
|
it 'works correctly' do
|
|
|
|
bob = Fabricate(:user, username: 'bob', name: 'bobs', email: 'bob@bob.com')
|
|
|
|
bob2 = Fabricate(:user, username: 'bob2', name: 'bobs', email: 'bob2@bob.com')
|
|
|
|
|
|
|
|
expect(User.find_by_username_or_email('bob22@bob.com')).to eq(nil)
|
|
|
|
expect(User.find_by_username_or_email('bobs')).to eq(nil)
|
|
|
|
|
|
|
|
expect(User.find_by_username_or_email('bob2')).to eq(bob2)
|
|
|
|
expect(User.find_by_username_or_email('bob2@BOB.com')).to eq(bob2)
|
|
|
|
|
|
|
|
expect(User.find_by_username_or_email('bob')).to eq(bob)
|
|
|
|
expect(User.find_by_username_or_email('bob@BOB.com')).to eq(bob)
|
|
|
|
end
|
|
|
|
end
|
2013-02-05 14:16:51 -05:00
|
|
|
end
|