mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 23:54:16 +08:00
ff49f72ad9
Revamped system for managing authentication tokens. - Every user has 1 token per client (web browser) - Tokens are rotated every 10 minutes New system migrates the old tokens to "legacy" tokens, so users still remain logged on. Also introduces weekly job to expire old auth tokens.
1737 lines
57 KiB
Ruby
1737 lines
57 KiB
Ruby
require 'rails_helper'
|
|
|
|
describe UsersController do
|
|
|
|
describe '.show' do
|
|
|
|
context "anon" do
|
|
|
|
let(:user) { Discourse.system_user }
|
|
|
|
it "returns success" do
|
|
xhr :get, :show, username: user.username, format: :json
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it "raises an error for anon when profiles are hidden" do
|
|
SiteSetting.stubs(:hide_user_profiles_from_public).returns(true)
|
|
xhr :get, :show, username: user.username, format: :json
|
|
expect(response).not_to be_success
|
|
end
|
|
|
|
end
|
|
|
|
context "logged in" do
|
|
|
|
let(:user) { log_in }
|
|
|
|
it 'returns success' do
|
|
xhr :get, :show, username: user.username, format: :json
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
|
|
expect(json["user"]["has_title_badges"]).to eq(false)
|
|
end
|
|
|
|
it "returns not found when the username doesn't exist" do
|
|
xhr :get, :show, username: 'madeuppity'
|
|
expect(response).not_to be_success
|
|
end
|
|
|
|
it 'returns not found when the user is inactive' do
|
|
inactive = Fabricate(:user, active: false)
|
|
xhr :get, :show, username: inactive.username
|
|
expect(response).not_to be_success
|
|
end
|
|
|
|
it "raises an error on invalid access" do
|
|
Guardian.any_instance.expects(:can_see?).with(user).returns(false)
|
|
xhr :get, :show, username: user.username
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
describe "user profile views" do
|
|
let(:other_user) { Fabricate(:user) }
|
|
|
|
it "should track a user profile view for a signed in user" do
|
|
UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, user.id)
|
|
xhr :get, :show, username: other_user.username
|
|
end
|
|
|
|
it "should not track a user profile view for a user viewing his own profile" do
|
|
UserProfileView.expects(:add).never
|
|
xhr :get, :show, username: user.username
|
|
end
|
|
|
|
it "should track a user profile view for an anon user" do
|
|
UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, nil)
|
|
xhr :get, :show, username: other_user.username
|
|
end
|
|
|
|
it "skips tracking" do
|
|
UserProfileView.expects(:add).never
|
|
xhr :get, :show, { username: user.username, skip_track_visit: true }
|
|
end
|
|
end
|
|
|
|
context "fetching a user by external_id" do
|
|
before { user.create_single_sign_on_record(external_id: '997', last_payload: '') }
|
|
|
|
it "returns fetch for a matching external_id" do
|
|
xhr :get, :show, external_id: '997'
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it "returns not found when external_id doesn't match" do
|
|
xhr :get, :show, external_id: '99'
|
|
expect(response).not_to be_success
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
describe '.user_preferences_redirect' do
|
|
it 'requires the user to be logged in' do
|
|
expect { get :user_preferences_redirect }.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
|
|
it "redirects to their profile when logged in" do
|
|
user = log_in
|
|
get :user_preferences_redirect
|
|
expect(response).to redirect_to("/users/#{user.username_lower}/preferences")
|
|
end
|
|
end
|
|
|
|
describe '.activate_account' do
|
|
before do
|
|
UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(false)
|
|
end
|
|
|
|
context 'invalid token' do
|
|
|
|
it 'return success' do
|
|
EmailToken.expects(:confirm).with('asdfasdf').returns(nil)
|
|
put :perform_account_activation, token: 'asdfasdf'
|
|
expect(response).to be_success
|
|
expect(flash[:error]).to be_present
|
|
end
|
|
end
|
|
|
|
context 'valid token' do
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
context 'welcome message' do
|
|
before do
|
|
EmailToken.expects(:confirm).with('asdfasdf').returns(user)
|
|
end
|
|
|
|
it 'enqueues a welcome message if the user object indicates so' do
|
|
user.send_welcome_message = true
|
|
user.expects(:enqueue_welcome_message).with('welcome_user')
|
|
put :perform_account_activation, token: 'asdfasdf'
|
|
end
|
|
|
|
it "doesn't enqueue the welcome message if the object returns false" do
|
|
user.send_welcome_message = false
|
|
user.expects(:enqueue_welcome_message).with('welcome_user').never
|
|
put :perform_account_activation, token: 'asdfasdf'
|
|
end
|
|
end
|
|
|
|
context "honeypot" do
|
|
it "raises an error if the honeypot is invalid" do
|
|
UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(true)
|
|
put :perform_account_activation, token: 'asdfasdf'
|
|
expect(response).not_to be_success
|
|
end
|
|
end
|
|
|
|
context 'response' do
|
|
before do
|
|
Guardian.any_instance.expects(:can_access_forum?).returns(true)
|
|
EmailToken.expects(:confirm).with('asdfasdf').returns(user)
|
|
put :perform_account_activation, token: 'asdfasdf'
|
|
end
|
|
|
|
it 'correctly logs on user' do
|
|
expect(response).to be_success
|
|
expect(flash[:error]).to be_blank
|
|
expect(session[:current_user_id]).to be_present
|
|
expect(assigns[:needs_approval]).to be_blank
|
|
end
|
|
|
|
end
|
|
|
|
context 'user is not approved' do
|
|
before do
|
|
Guardian.any_instance.expects(:can_access_forum?).returns(false)
|
|
EmailToken.expects(:confirm).with('asdfasdf').returns(user)
|
|
put :perform_account_activation, token: 'asdfasdf'
|
|
end
|
|
|
|
it 'returns success' do
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it 'sets @needs_approval' do
|
|
expect(assigns[:needs_approval]).to be_present
|
|
end
|
|
|
|
it "doesn't set an error" do
|
|
expect(flash[:error]).to be_blank
|
|
end
|
|
|
|
it "doesn't log the user in" do
|
|
expect(session[:current_user_id]).to be_blank
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
describe '.password_reset' do
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
context "you can view it even if login is required" do
|
|
it "returns success" do
|
|
SiteSetting.login_required = true
|
|
get :password_reset, token: 'asdfasdf'
|
|
expect(response).to be_success
|
|
end
|
|
end
|
|
|
|
context 'missing token' do
|
|
before do
|
|
get :password_reset, token: SecureRandom.hex
|
|
end
|
|
|
|
it 'disallows login' do
|
|
expect(assigns[:error]).to be_present
|
|
expect(session[:current_user_id]).to be_blank
|
|
expect(response).to be_success
|
|
expect(response).to render_template(layout: 'no_ember')
|
|
end
|
|
end
|
|
|
|
context 'invalid token' do
|
|
before do
|
|
get :password_reset, token: "evil_trout!"
|
|
end
|
|
|
|
it 'disallows login' do
|
|
expect(assigns[:error]).to be_present
|
|
expect(session[:current_user_id]).to be_blank
|
|
expect(response).to be_success
|
|
expect(response).to render_template(layout: 'no_ember')
|
|
end
|
|
end
|
|
|
|
context 'valid token' do
|
|
context 'when rendered' do
|
|
render_views
|
|
|
|
it 'renders referrer never on get requests' do
|
|
user = Fabricate(:user)
|
|
token = user.email_tokens.create(email: user.email).token
|
|
get :password_reset, token: token
|
|
|
|
expect(response.body).to include('<meta name="referrer" content="never">')
|
|
end
|
|
end
|
|
|
|
it 'returns success' do
|
|
user = Fabricate(:user)
|
|
user_auth_token = UserAuthToken.generate!(user_id: user.id)
|
|
token = user.email_tokens.create(email: user.email).token
|
|
|
|
get :password_reset, token: token
|
|
put :password_reset, token: token, password: 'hg9ow8yhg98o'
|
|
|
|
expect(response).to be_success
|
|
expect(assigns[:error]).to be_blank
|
|
|
|
user.reload
|
|
|
|
expect(session["password-#{token}"]).to be_blank
|
|
|
|
expect(UserAuthToken.where(id: user_auth_token.id).count).to eq(0)
|
|
end
|
|
|
|
it 'disallows double password reset' do
|
|
user = Fabricate(:user)
|
|
token = user.email_tokens.create(email: user.email).token
|
|
|
|
get :password_reset, token: token
|
|
put :password_reset, token: token, password: 'hg9ow8yhg98o'
|
|
put :password_reset, token: token, password: 'test123123Asdfsdf'
|
|
|
|
user.reload
|
|
expect(user.confirm_password?('hg9ow8yhg98o')).to eq(true)
|
|
|
|
# logged in now
|
|
expect(user.user_auth_tokens.count).to eq(1)
|
|
end
|
|
|
|
it "redirects to the wizard if you're the first admin" do
|
|
user = Fabricate(:admin)
|
|
token = user.email_tokens.create(email: user.email).token
|
|
get :password_reset, token: token
|
|
put :password_reset, token: token, password: 'hg9ow8yhg98oadminlonger'
|
|
expect(response).to be_redirect
|
|
end
|
|
|
|
it "doesn't invalidate the token when loading the page" do
|
|
user = Fabricate(:user)
|
|
user_token = UserAuthToken.generate!(user_id: user.id)
|
|
|
|
email_token = user.email_tokens.create(email: user.email)
|
|
|
|
get :password_reset, token: email_token.token
|
|
|
|
email_token.reload
|
|
|
|
expect(email_token.confirmed).to eq(false)
|
|
expect(UserAuthToken.where(id: user_token.id).count).to eq(1)
|
|
end
|
|
end
|
|
|
|
context 'submit change' do
|
|
let(:token) { EmailToken.generate_token }
|
|
before do
|
|
EmailToken.expects(:confirm).with(token).returns(user)
|
|
end
|
|
|
|
it "fails when the password is blank" do
|
|
put :password_reset, token: token, password: ''
|
|
expect(assigns(:user).errors).to be_present
|
|
expect(session[:current_user_id]).to be_blank
|
|
end
|
|
|
|
it "fails when the password is too long" do
|
|
put :password_reset, token: token, password: ('x' * (User.max_password_length + 1))
|
|
expect(assigns(:user).errors).to be_present
|
|
expect(session[:current_user_id]).to be_blank
|
|
end
|
|
|
|
it "logs in the user" do
|
|
put :password_reset, token: token, password: 'ksjafh928r'
|
|
expect(assigns(:user).errors).to be_blank
|
|
expect(session[:current_user_id]).to be_present
|
|
end
|
|
|
|
it "doesn't log in the user when not approved" do
|
|
SiteSetting.expects(:must_approve_users?).returns(true)
|
|
put :password_reset, token: token, password: 'ksjafh928r'
|
|
expect(assigns(:user).errors).to be_blank
|
|
expect(session[:current_user_id]).to be_blank
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.confirm_email_token' do
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
it "token doesn't match any records" do
|
|
email_token = user.email_tokens.create(email: user.email)
|
|
get :confirm_email_token, token: SecureRandom.hex, format: :json
|
|
expect(response).to be_success
|
|
expect(email_token.reload.confirmed).to eq(false)
|
|
end
|
|
|
|
it "token matches" do
|
|
email_token = user.email_tokens.create(email: user.email)
|
|
get :confirm_email_token, token: email_token.token, format: :json
|
|
expect(response).to be_success
|
|
expect(email_token.reload.confirmed).to eq(true)
|
|
end
|
|
end
|
|
|
|
describe '.admin_login' do
|
|
let(:admin) { Fabricate(:admin) }
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
context 'enqueues mail' do
|
|
it 'enqueues mail with admin email and sso enabled' do
|
|
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :admin_login, user_id: admin.id))
|
|
put :admin_login, email: admin.email
|
|
end
|
|
end
|
|
|
|
context 'logs in admin' do
|
|
it 'does not log in admin with invalid token' do
|
|
SiteSetting.enable_sso = true
|
|
get :admin_login, token: "invalid"
|
|
expect(session[:current_user_id]).to be_blank
|
|
end
|
|
|
|
it 'does log in admin with valid token and SSO disabled' do
|
|
SiteSetting.enable_sso = false
|
|
token = admin.email_tokens.create(email: admin.email).token
|
|
|
|
get :admin_login, token: token
|
|
expect(response).to redirect_to('/')
|
|
expect(session[:current_user_id]).to eq(admin.id)
|
|
end
|
|
|
|
it 'logs in admin with valid token and SSO enabled' do
|
|
SiteSetting.enable_sso = true
|
|
token = admin.email_tokens.create(email: admin.email).token
|
|
|
|
get :admin_login, token: token
|
|
expect(response).to redirect_to('/')
|
|
expect(session[:current_user_id]).to eq(admin.id)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#toggle_anon' do
|
|
it 'allows you to toggle anon if enabled' do
|
|
SiteSetting.allow_anonymous_posting = true
|
|
|
|
user = log_in
|
|
user.trust_level = 1
|
|
user.save
|
|
|
|
post :toggle_anon
|
|
expect(response).to be_success
|
|
expect(session[:current_user_id]).to eq(AnonymousShadowCreator.get(user).id)
|
|
|
|
post :toggle_anon
|
|
expect(response).to be_success
|
|
expect(session[:current_user_id]).to eq(user.id)
|
|
|
|
end
|
|
end
|
|
|
|
describe '#create' do
|
|
|
|
before do
|
|
UsersController.any_instance.stubs(:honeypot_value).returns(nil)
|
|
UsersController.any_instance.stubs(:challenge_value).returns(nil)
|
|
SiteSetting.stubs(:allow_new_registrations).returns(true)
|
|
@user = Fabricate.build(:user)
|
|
@user.password = "strongpassword"
|
|
end
|
|
|
|
let(:post_user_params) do
|
|
{ name: @user.name,
|
|
username: @user.username,
|
|
password: "strongpassword",
|
|
email: @user.email }
|
|
end
|
|
|
|
def post_user
|
|
xhr :post, :create, post_user_params
|
|
end
|
|
|
|
context 'when creating a user' do
|
|
it 'sets the user locale to I18n.locale' do
|
|
SiteSetting.stubs(:default_locale).returns('en')
|
|
I18n.stubs(:locale).returns(:fr)
|
|
post_user
|
|
expect(User.find_by(username: @user.username).locale).to eq('fr')
|
|
end
|
|
end
|
|
|
|
context 'when creating a non active user (unconfirmed email)' do
|
|
|
|
it 'returns a 500 when local logins are disabled' do
|
|
SiteSetting.expects(:enable_local_logins).returns(false)
|
|
post_user
|
|
|
|
expect(response.status).to eq(500)
|
|
end
|
|
|
|
it 'returns an error when new registrations are disabled' do
|
|
SiteSetting.stubs(:allow_new_registrations).returns(false)
|
|
post_user
|
|
json = JSON.parse(response.body)
|
|
expect(json['success']).to eq(false)
|
|
expect(json['message']).to be_present
|
|
end
|
|
|
|
it 'creates a user correctly' do
|
|
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
|
User.any_instance.expects(:enqueue_welcome_message).with('welcome_user').never
|
|
|
|
post_user
|
|
|
|
expect(JSON.parse(response.body)['active']).to be_falsey
|
|
|
|
# should save user_created_message in session
|
|
expect(session["user_created_message"]).to be_present
|
|
end
|
|
|
|
context "and 'must approve users' site setting is enabled" do
|
|
before { SiteSetting.expects(:must_approve_users).returns(true) }
|
|
|
|
it 'does not enqueue an email' do
|
|
Jobs.expects(:enqueue).never
|
|
post_user
|
|
end
|
|
|
|
it 'does not login the user' do
|
|
post_user
|
|
expect(session[:current_user_id]).to be_blank
|
|
end
|
|
|
|
it 'indicates the user is not active in the response' do
|
|
post_user
|
|
expect(JSON.parse(response.body)['active']).to be_falsey
|
|
end
|
|
|
|
it "shows the 'waiting approval' message" do
|
|
post_user
|
|
expect(JSON.parse(response.body)['message']).to eq(I18n.t 'login.wait_approval')
|
|
end
|
|
end
|
|
end
|
|
|
|
context "creating as active" do
|
|
it "won't create the user as active" do
|
|
xhr :post, :create, post_user_params.merge(active: true)
|
|
expect(JSON.parse(response.body)['active']).to be_falsey
|
|
end
|
|
|
|
context "with a regular api key" do
|
|
let(:user) { Fabricate(:user) }
|
|
let(:api_key) { Fabricate(:api_key, user: user) }
|
|
|
|
it "won't create the user as active with a regular key" do
|
|
xhr :post, :create, post_user_params.merge(active: true, api_key: api_key.key)
|
|
expect(JSON.parse(response.body)['active']).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "with an admin api key" do
|
|
let(:user) { Fabricate(:admin) }
|
|
let(:api_key) { Fabricate(:api_key, user: user) }
|
|
|
|
it "creates the user as active with a regular key" do
|
|
xhr :post, :create, post_user_params.merge(active: true, api_key: api_key.key)
|
|
expect(JSON.parse(response.body)['active']).to be_truthy
|
|
end
|
|
|
|
it "won't create the developer as active" do
|
|
UsernameCheckerService.expects(:is_developer?).returns(true)
|
|
|
|
xhr :post, :create, post_user_params.merge(active: true, api_key: api_key.key)
|
|
expect(JSON.parse(response.body)['active']).to be_falsy
|
|
end
|
|
end
|
|
end
|
|
|
|
context "creating as staged" do
|
|
it "won't create the user as staged" do
|
|
xhr :post, :create, post_user_params.merge(staged: true)
|
|
new_user = User.where(username: post_user_params[:username]).first
|
|
expect(new_user.staged?).to eq(false)
|
|
end
|
|
|
|
context "with a regular api key" do
|
|
let(:user) { Fabricate(:user) }
|
|
let(:api_key) { Fabricate(:api_key, user: user) }
|
|
|
|
it "won't create the user as staged with a regular key" do
|
|
xhr :post, :create, post_user_params.merge(staged: true, api_key: api_key.key)
|
|
new_user = User.where(username: post_user_params[:username]).first
|
|
expect(new_user.staged?).to eq(false)
|
|
end
|
|
end
|
|
|
|
context "with an admin api key" do
|
|
let(:user) { Fabricate(:admin) }
|
|
let(:api_key) { Fabricate(:api_key, user: user) }
|
|
|
|
it "creates the user as staged with a regular key" do
|
|
xhr :post, :create, post_user_params.merge(staged: true, api_key: api_key.key)
|
|
|
|
new_user = User.where(username: post_user_params[:username]).first
|
|
expect(new_user.staged?).to eq(true)
|
|
end
|
|
|
|
it "won't create the developer as staged" do
|
|
UsernameCheckerService.expects(:is_developer?).returns(true)
|
|
xhr :post, :create, post_user_params.merge(staged: true, api_key: api_key.key)
|
|
|
|
new_user = User.where(username: post_user_params[:username]).first
|
|
expect(new_user.staged?).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when creating an active user (confirmed email)' do
|
|
before { User.any_instance.stubs(:active?).returns(true) }
|
|
|
|
it 'enqueues a welcome email' do
|
|
User.any_instance.expects(:enqueue_welcome_message).with('welcome_user')
|
|
post_user
|
|
|
|
# should save user_created_message in session
|
|
expect(session["user_created_message"]).to be_present
|
|
end
|
|
|
|
it "shows the 'active' message" do
|
|
User.any_instance.expects(:enqueue_welcome_message)
|
|
post_user
|
|
expect(JSON.parse(response.body)['message']).to eq(
|
|
I18n.t 'login.active'
|
|
)
|
|
end
|
|
|
|
it "should be logged in" do
|
|
User.any_instance.expects(:enqueue_welcome_message)
|
|
post_user
|
|
expect(session[:current_user_id]).to be_present
|
|
end
|
|
|
|
it 'indicates the user is active in the response' do
|
|
User.any_instance.expects(:enqueue_welcome_message)
|
|
post_user
|
|
expect(JSON.parse(response.body)['active']).to be_truthy
|
|
end
|
|
|
|
it 'returns 500 status when new registrations are disabled' do
|
|
SiteSetting.stubs(:allow_new_registrations).returns(false)
|
|
post_user
|
|
json = JSON.parse(response.body)
|
|
expect(json['success']).to eq(false)
|
|
expect(json['message']).to be_present
|
|
end
|
|
|
|
context 'authentication records for' do
|
|
|
|
before do
|
|
SiteSetting.expects(:must_approve_users).returns(true)
|
|
end
|
|
|
|
it 'should create twitter user info if required' do
|
|
SiteSetting.stubs(:enable_twitter_logins?).returns(true)
|
|
twitter_auth = { twitter_user_id: 42, twitter_screen_name: "bruce" }
|
|
auth = session[:authentication] = {}
|
|
auth[:authenticator_name] = 'twitter'
|
|
auth[:extra_data] = twitter_auth
|
|
TwitterUserInfo.expects(:create)
|
|
|
|
post_user
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'after success' do
|
|
before { post_user }
|
|
|
|
it 'should succeed' do
|
|
is_expected.to respond_with(:success)
|
|
end
|
|
|
|
it 'has the proper JSON' do
|
|
json = JSON::parse(response.body)
|
|
expect(json["success"]).to eq(true)
|
|
end
|
|
|
|
it 'should not result in an active account' do
|
|
expect(User.find_by(username: @user.username).active).to eq(false)
|
|
end
|
|
end
|
|
|
|
shared_examples 'honeypot fails' do
|
|
it 'should not create a new user' do
|
|
expect {
|
|
xhr :post, :create, create_params
|
|
}.to_not change { User.count }
|
|
end
|
|
|
|
it 'should not send an email' do
|
|
User.any_instance.expects(:enqueue_welcome_message).never
|
|
xhr :post, :create, create_params
|
|
end
|
|
|
|
it 'should say it was successful' do
|
|
xhr :post, :create, create_params
|
|
json = JSON::parse(response.body)
|
|
expect(json["success"]).to eq(true)
|
|
|
|
# should not change the session
|
|
expect(session["user_created_message"]).to be_blank
|
|
end
|
|
end
|
|
|
|
context 'when honeypot value is wrong' do
|
|
before do
|
|
UsersController.any_instance.stubs(:honeypot_value).returns('abc')
|
|
end
|
|
let(:create_params) { {name: @user.name, username: @user.username, password: "strongpassword", email: @user.email, password_confirmation: 'wrong'} }
|
|
include_examples 'honeypot fails'
|
|
end
|
|
|
|
context 'when challenge answer is wrong' do
|
|
before do
|
|
UsersController.any_instance.stubs(:challenge_value).returns('abc')
|
|
end
|
|
let(:create_params) { {name: @user.name, username: @user.username, password: "strongpassword", email: @user.email, challenge: 'abc'} }
|
|
include_examples 'honeypot fails'
|
|
end
|
|
|
|
context "when 'invite only' setting is enabled" do
|
|
before { SiteSetting.expects(:invite_only?).returns(true) }
|
|
|
|
let(:create_params) {{
|
|
name: @user.name,
|
|
username: @user.username,
|
|
password: 'strongpassword',
|
|
email: @user.email
|
|
}}
|
|
|
|
include_examples 'honeypot fails'
|
|
end
|
|
|
|
shared_examples 'failed signup' do
|
|
it 'should not create a new User' do
|
|
expect { xhr :post, :create, create_params }.to_not change { User.count }
|
|
end
|
|
|
|
it 'should report failed' do
|
|
xhr :post, :create, create_params
|
|
json = JSON::parse(response.body)
|
|
expect(json["success"]).not_to eq(true)
|
|
|
|
# should not change the session
|
|
expect(session["user_created_message"]).to be_blank
|
|
end
|
|
end
|
|
|
|
context 'when password is blank' do
|
|
let(:create_params) { {name: @user.name, username: @user.username, password: "", email: @user.email} }
|
|
include_examples 'failed signup'
|
|
end
|
|
|
|
context 'when password is too long' do
|
|
let(:create_params) { {name: @user.name, username: @user.username, password: "x" * (User.max_password_length + 1), email: @user.email} }
|
|
include_examples 'failed signup'
|
|
end
|
|
|
|
context 'when password param is missing' do
|
|
let(:create_params) { {name: @user.name, username: @user.username, email: @user.email} }
|
|
include_examples 'failed signup'
|
|
end
|
|
|
|
context 'with a reserved username' do
|
|
let(:create_params) { {name: @user.name, username: 'Reserved', email: @user.email, password: "x" * 20} }
|
|
before { SiteSetting.reserved_usernames = 'a|reserved|b' }
|
|
after { SiteSetting.reserved_usernames = nil }
|
|
include_examples 'failed signup'
|
|
end
|
|
|
|
context 'when an Exception is raised' do
|
|
[ ActiveRecord::StatementInvalid,
|
|
RestClient::Forbidden ].each do |exception|
|
|
before { User.any_instance.stubs(:save).raises(exception) }
|
|
|
|
let(:create_params) {
|
|
{ name: @user.name, username: @user.username,
|
|
password: "strongpassword", email: @user.email}
|
|
}
|
|
|
|
include_examples 'failed signup'
|
|
end
|
|
end
|
|
|
|
context "with custom fields" do
|
|
let!(:user_field) { Fabricate(:user_field) }
|
|
let!(:another_field) { Fabricate(:user_field) }
|
|
let!(:optional_field) { Fabricate(:user_field, required: false) }
|
|
|
|
context "without a value for the fields" do
|
|
let(:create_params) { {name: @user.name, password: 'watwatwat', username: @user.username, email: @user.email} }
|
|
include_examples 'failed signup'
|
|
end
|
|
|
|
context "with values for the fields" do
|
|
let(:create_params) { {
|
|
name: @user.name,
|
|
password: 'watwatwatwat',
|
|
username: @user.username,
|
|
email: @user.email,
|
|
user_fields: {
|
|
user_field.id.to_s => 'value1',
|
|
another_field.id.to_s => 'value2',
|
|
}
|
|
} }
|
|
|
|
it "should succeed without the optional field" do
|
|
xhr :post, :create, create_params
|
|
expect(response).to be_success
|
|
inserted = User.where(email: @user.email).first
|
|
expect(inserted).to be_present
|
|
expect(inserted.custom_fields).to be_present
|
|
expect(inserted.custom_fields["user_field_#{user_field.id}"]).to eq('value1')
|
|
expect(inserted.custom_fields["user_field_#{another_field.id}"]).to eq('value2')
|
|
expect(inserted.custom_fields["user_field_#{optional_field.id}"]).to be_blank
|
|
end
|
|
|
|
it "should succeed with the optional field" do
|
|
create_params[:user_fields][optional_field.id.to_s] = 'value3'
|
|
xhr :post, :create, create_params.merge(create_params)
|
|
expect(response).to be_success
|
|
inserted = User.where(email: @user.email).first
|
|
expect(inserted).to be_present
|
|
expect(inserted.custom_fields).to be_present
|
|
expect(inserted.custom_fields["user_field_#{user_field.id}"]).to eq('value1')
|
|
expect(inserted.custom_fields["user_field_#{another_field.id}"]).to eq('value2')
|
|
expect(inserted.custom_fields["user_field_#{optional_field.id}"]).to eq('value3')
|
|
end
|
|
|
|
it "trims excessively long fields" do
|
|
create_params[:user_fields][optional_field.id.to_s] = ('x' * 3000)
|
|
xhr :post, :create, create_params.merge(create_params)
|
|
expect(response).to be_success
|
|
inserted = User.where(email: @user.email).first
|
|
|
|
val = inserted.custom_fields["user_field_#{optional_field.id}"]
|
|
expect(val.length).to eq(UserField.max_length)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with only optional custom fields" do
|
|
let!(:user_field) { Fabricate(:user_field, required: false) }
|
|
|
|
context "without values for the fields" do
|
|
let(:create_params) { {
|
|
name: @user.name,
|
|
password: 'watwatwatwat',
|
|
username: @user.username,
|
|
email: @user.email,
|
|
} }
|
|
|
|
it "should succeed" do
|
|
xhr :post, :create, create_params
|
|
expect(response).to be_success
|
|
inserted = User.where(email: @user.email).first
|
|
expect(inserted).to be_present
|
|
expect(inserted.custom_fields).not_to be_present
|
|
expect(inserted.custom_fields["user_field_#{user_field.id}"]).to be_blank
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when taking over a staged account" do
|
|
let!(:staged) { Fabricate(:staged, email: "staged@account.com") }
|
|
|
|
it "succeeds" do
|
|
xhr :post, :create, email: staged.email, username: "zogstrip", password: "P4ssw0rd$$"
|
|
result = ::JSON.parse(response.body)
|
|
expect(result["success"]).to eq(true)
|
|
expect(User.find_by(email: staged.email).staged).to eq(false)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
context '.username' do
|
|
it 'raises an error when not logged in' do
|
|
expect { xhr :put, :username, username: 'somename' }.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
|
|
context 'while logged in' do
|
|
let(:old_username) { "OrigUsrname" }
|
|
let(:new_username) { "#{old_username}1234" }
|
|
let(:user) { Fabricate(:user, username: old_username) }
|
|
|
|
before do
|
|
user.username = old_username
|
|
log_in_user(user)
|
|
end
|
|
|
|
it 'raises an error without a new_username param' do
|
|
expect { xhr :put, :username, username: user.username }.to raise_error(ActionController::ParameterMissing)
|
|
expect(user.reload.username).to eq(old_username)
|
|
end
|
|
|
|
it 'raises an error when you don\'t have permission to change the username' do
|
|
Guardian.any_instance.expects(:can_edit_username?).with(user).returns(false)
|
|
xhr :put, :username, username: user.username, new_username: new_username
|
|
expect(response).to be_forbidden
|
|
expect(user.reload.username).to eq(old_username)
|
|
end
|
|
|
|
# Bad behavior, this should give a real JSON error, not an InvalidParameters
|
|
it 'raises an error when change_username fails' do
|
|
User.any_instance.expects(:save).returns(false)
|
|
expect { xhr :put, :username, username: user.username, new_username: new_username }.to raise_error(Discourse::InvalidParameters)
|
|
expect(user.reload.username).to eq(old_username)
|
|
end
|
|
|
|
it 'should succeed in normal circumstances' do
|
|
xhr :put, :username, username: user.username, new_username: new_username
|
|
expect(response).to be_success
|
|
expect(user.reload.username).to eq(new_username)
|
|
end
|
|
|
|
skip 'should fail if the user is old', 'ensure_can_edit_username! is not throwing' do
|
|
# Older than the change period and >1 post
|
|
user.created_at = Time.now - (SiteSetting.username_change_period + 1).days
|
|
user.stubs(:post_count).returns(200)
|
|
expect(Guardian.new(user).can_edit_username?(user)).to eq(false)
|
|
|
|
xhr :put, :username, username: user.username, new_username: new_username
|
|
|
|
expect(response).to be_forbidden
|
|
expect(user.reload.username).to eq(old_username)
|
|
end
|
|
|
|
it 'should create a staff action log when a staff member changes the username' do
|
|
acting_user = Fabricate(:admin)
|
|
log_in_user(acting_user)
|
|
xhr :put, :username, username: user.username, new_username: new_username
|
|
expect(response).to be_success
|
|
expect(UserHistory.where(action: UserHistory.actions[:change_username], target_user_id: user.id, acting_user_id: acting_user.id)).to be_present
|
|
expect(user.reload.username).to eq(new_username)
|
|
end
|
|
|
|
it 'should return a JSON response with the updated username' do
|
|
xhr :put, :username, username: user.username, new_username: new_username
|
|
expect(::JSON.parse(response.body)['username']).to eq(new_username)
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
context '.check_username' do
|
|
it 'raises an error without any parameters' do
|
|
expect { xhr :get, :check_username }.to raise_error(ActionController::ParameterMissing)
|
|
end
|
|
|
|
shared_examples 'when username is unavailable' do
|
|
it 'should return success' do
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it 'should return available as false in the JSON' do
|
|
expect(::JSON.parse(response.body)['available']).to eq(false)
|
|
end
|
|
|
|
it 'should return a suggested username' do
|
|
expect(::JSON.parse(response.body)['suggestion']).to be_present
|
|
end
|
|
end
|
|
|
|
shared_examples 'when username is available' do
|
|
it 'should return success' do
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it 'should return available in the JSON' do
|
|
expect(::JSON.parse(response.body)['available']).to eq(true)
|
|
end
|
|
end
|
|
|
|
it 'returns nothing when given an email param but no username' do
|
|
xhr :get, :check_username, email: 'dood@example.com'
|
|
expect(response).to be_success
|
|
end
|
|
|
|
context 'username is available' do
|
|
before do
|
|
xhr :get, :check_username, username: 'BruceWayne'
|
|
end
|
|
include_examples 'when username is available'
|
|
end
|
|
|
|
context 'username is unavailable' do
|
|
let!(:user) { Fabricate(:user) }
|
|
before do
|
|
xhr :get, :check_username, username: user.username
|
|
end
|
|
include_examples 'when username is unavailable'
|
|
end
|
|
|
|
shared_examples 'checking an invalid username' do
|
|
it 'should return success' do
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it 'should not return an available key' do
|
|
expect(::JSON.parse(response.body)['available']).to eq(nil)
|
|
end
|
|
|
|
it 'should return an error message' do
|
|
expect(::JSON.parse(response.body)['errors']).not_to be_empty
|
|
end
|
|
end
|
|
|
|
context 'has invalid characters' do
|
|
before do
|
|
xhr :get, :check_username, username: 'bad username'
|
|
end
|
|
include_examples 'checking an invalid username'
|
|
|
|
it 'should return the invalid characters message' do
|
|
expect(::JSON.parse(response.body)['errors']).to include(I18n.t(:'user.username.characters'))
|
|
end
|
|
end
|
|
|
|
context 'is too long' do
|
|
before do
|
|
xhr :get, :check_username, username: generate_username(User.username_length.last + 1)
|
|
end
|
|
include_examples 'checking an invalid username'
|
|
|
|
it 'should return the "too long" message' do
|
|
expect(::JSON.parse(response.body)['errors']).to include(I18n.t(:'user.username.long', max: User.username_length.end))
|
|
end
|
|
end
|
|
|
|
describe 'different case of existing username' do
|
|
context "it's my username" do
|
|
let!(:user) { Fabricate(:user, username: 'hansolo') }
|
|
before do
|
|
log_in_user(user)
|
|
xhr :get, :check_username, username: 'HanSolo'
|
|
end
|
|
include_examples 'when username is available'
|
|
end
|
|
|
|
context "it's someone else's username" do
|
|
let!(:user) { Fabricate(:user, username: 'hansolo') }
|
|
before do
|
|
log_in
|
|
xhr :get, :check_username, username: 'HanSolo'
|
|
end
|
|
include_examples 'when username is unavailable'
|
|
end
|
|
|
|
context "an admin changing it for someone else" do
|
|
let!(:user) { Fabricate(:user, username: 'hansolo') }
|
|
before do
|
|
log_in_user(Fabricate(:admin))
|
|
xhr :get, :check_username, username: 'HanSolo', for_user_id: user.id
|
|
end
|
|
include_examples 'when username is available'
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#invited' do
|
|
it 'returns success' do
|
|
user = Fabricate(:user)
|
|
|
|
xhr :get, :invited, username: user.username
|
|
|
|
expect(response).to be_success
|
|
end
|
|
|
|
it 'filters by email' do
|
|
inviter = Fabricate(:user)
|
|
invitee = Fabricate(:user)
|
|
_invite = Fabricate(
|
|
:invite,
|
|
email: 'billybob@example.com',
|
|
invited_by: inviter,
|
|
user: invitee
|
|
)
|
|
Fabricate(
|
|
:invite,
|
|
email: 'jimtom@example.com',
|
|
invited_by: inviter,
|
|
user: invitee
|
|
)
|
|
|
|
xhr :get, :invited, username: inviter.username, search: 'billybob'
|
|
|
|
invites = JSON.parse(response.body)['invites']
|
|
expect(invites.size).to eq(1)
|
|
expect(invites.first).to include('email' => 'billybob@example.com')
|
|
end
|
|
|
|
it 'filters by username' do
|
|
inviter = Fabricate(:user)
|
|
invitee = Fabricate(:user, username: 'billybob')
|
|
_invite = Fabricate(
|
|
:invite,
|
|
invited_by: inviter,
|
|
email: 'billybob@example.com',
|
|
user: invitee
|
|
)
|
|
Fabricate(
|
|
:invite,
|
|
invited_by: inviter,
|
|
user: Fabricate(:user, username: 'jimtom')
|
|
)
|
|
|
|
xhr :get, :invited, username: inviter.username, search: 'billybob'
|
|
|
|
invites = JSON.parse(response.body)['invites']
|
|
expect(invites.size).to eq(1)
|
|
expect(invites.first).to include('email' => 'billybob@example.com')
|
|
end
|
|
|
|
context 'with guest' do
|
|
context 'with pending invites' do
|
|
it 'does not return invites' do
|
|
inviter = Fabricate(:user)
|
|
Fabricate(:invite, invited_by: inviter)
|
|
|
|
xhr :get, :invited, username: inviter.username, filter: 'pending'
|
|
|
|
invites = JSON.parse(response.body)['invites']
|
|
expect(invites).to be_empty
|
|
end
|
|
end
|
|
|
|
context 'with redeemed invites' do
|
|
it 'returns invites' do
|
|
inviter = Fabricate(:user)
|
|
invitee = Fabricate(:user)
|
|
invite = Fabricate(:invite, invited_by: inviter, user: invitee)
|
|
|
|
xhr :get, :invited, username: inviter.username
|
|
|
|
invites = JSON.parse(response.body)['invites']
|
|
expect(invites.size).to eq(1)
|
|
expect(invites.first).to include('email' => invite.email)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with authenticated user' do
|
|
context 'with pending invites' do
|
|
context 'with permission to see pending invites' do
|
|
it 'returns invites' do
|
|
user = log_in
|
|
inviter = Fabricate(:user)
|
|
invite = Fabricate(:invite, invited_by: inviter)
|
|
stub_guardian(user) do |guardian|
|
|
guardian.stubs(:can_see_invite_details?).
|
|
with(inviter).returns(true)
|
|
end
|
|
|
|
xhr :get, :invited, username: inviter.username, filter: 'pending'
|
|
|
|
invites = JSON.parse(response.body)['invites']
|
|
expect(invites.size).to eq(1)
|
|
expect(invites.first).to include("email" => invite.email)
|
|
end
|
|
end
|
|
|
|
context 'without permission to see pending invites' do
|
|
it 'does not return invites' do
|
|
user = log_in
|
|
inviter = Fabricate(:user)
|
|
_invitee = Fabricate(:user)
|
|
Fabricate(:invite, invited_by: inviter)
|
|
stub_guardian(user) do |guardian|
|
|
guardian.stubs(:can_see_invite_details?).
|
|
with(inviter).returns(false)
|
|
end
|
|
|
|
xhr :get, :invited, username: inviter.username, filter: 'pending'
|
|
|
|
json = JSON.parse(response.body)['invites']
|
|
expect(json).to be_empty
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with redeemed invites' do
|
|
it 'returns invites' do
|
|
_user = log_in
|
|
inviter = Fabricate(:user)
|
|
invitee = Fabricate(:user)
|
|
invite = Fabricate(:invite, invited_by: inviter, user: invitee)
|
|
|
|
xhr :get, :invited, username: inviter.username
|
|
|
|
invites = JSON.parse(response.body)['invites']
|
|
expect(invites.size).to eq(1)
|
|
expect(invites.first).to include('email' => invite.email)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#update' do
|
|
context 'with guest' do
|
|
it 'raises an error' do
|
|
expect do
|
|
xhr :put, :update, username: 'guest'
|
|
end.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
end
|
|
|
|
context "as a staff user" do
|
|
let!(:user) { log_in(:admin) }
|
|
|
|
context "uneditable field" do
|
|
let!(:user_field) { Fabricate(:user_field, editable: false) }
|
|
|
|
it "allows staff to edit the field" do
|
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
|
expect(response).to be_success
|
|
expect(user.user_fields[user_field.id.to_s]).to eq('happy')
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
context 'with authenticated user' do
|
|
context 'with permission to update' do
|
|
let!(:user) { log_in(:user) }
|
|
|
|
it 'allows the update' do
|
|
|
|
user2 = Fabricate(:user)
|
|
user3 = Fabricate(:user)
|
|
|
|
put :update,
|
|
username: user.username,
|
|
name: 'Jim Tom',
|
|
custom_fields: {test: :it},
|
|
muted_usernames: "#{user2.username},#{user3.username}"
|
|
|
|
expect(response).to be_success
|
|
|
|
user.reload
|
|
|
|
expect(user.name).to eq 'Jim Tom'
|
|
expect(user.custom_fields['test']).to eq 'it'
|
|
expect(user.muted_users.pluck(:username).sort).to eq [user2.username,user3.username].sort
|
|
|
|
put :update,
|
|
username: user.username,
|
|
muted_usernames: ""
|
|
|
|
user.reload
|
|
|
|
expect(user.muted_users.pluck(:username).sort).to be_empty
|
|
|
|
end
|
|
|
|
context 'a locale is chosen that differs from I18n.locale' do
|
|
it "updates the user's locale" do
|
|
I18n.stubs(:locale).returns('fr')
|
|
|
|
put :update,
|
|
username: user.username,
|
|
locale: :fa_IR
|
|
|
|
expect(User.find_by(username: user.username).locale).to eq('fa_IR')
|
|
end
|
|
|
|
end
|
|
|
|
context "with user fields" do
|
|
context "an editable field" do
|
|
let!(:user_field) { Fabricate(:user_field) }
|
|
let!(:optional_field) { Fabricate(:user_field, required: false ) }
|
|
|
|
it "should update the user field" do
|
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
|
expect(response).to be_success
|
|
expect(user.user_fields[user_field.id.to_s]).to eq 'happy'
|
|
end
|
|
|
|
it "cannot be updated to blank" do
|
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => '' }
|
|
expect(response).not_to be_success
|
|
expect(user.user_fields[user_field.id.to_s]).not_to eq('happy')
|
|
end
|
|
|
|
it "trims excessively large fields" do
|
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => ('x' * 3000) }
|
|
expect(user.user_fields[user_field.id.to_s].size).to eq(UserField.max_length)
|
|
end
|
|
end
|
|
|
|
context "uneditable field" do
|
|
let!(:user_field) { Fabricate(:user_field, editable: false) }
|
|
|
|
it "does not update the user field" do
|
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
|
expect(response).to be_success
|
|
expect(user.user_fields[user_field.id.to_s]).to be_blank
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
it 'returns user JSON' do
|
|
put :update, username: user.username
|
|
|
|
json = JSON.parse(response.body)
|
|
expect(json['user']['id']).to eq user.id
|
|
end
|
|
|
|
end
|
|
|
|
context 'without permission to update' do
|
|
it 'does not allow the update' do
|
|
user = Fabricate(:user, name: 'Billy Bob')
|
|
log_in_user(user)
|
|
Guardian.any_instance.expects(:can_edit?).with(user).returns(false)
|
|
|
|
put :update, username: user.username, name: 'Jim Tom'
|
|
|
|
expect(response).to be_forbidden
|
|
expect(user.reload.name).not_to eq 'Jim Tom'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "badge_card" do
|
|
let(:user) { Fabricate(:user) }
|
|
let(:badge) { Fabricate(:badge) }
|
|
let(:user_badge) { BadgeGranter.grant(badge, user) }
|
|
|
|
it "sets the user's card image to the badge" do
|
|
log_in_user user
|
|
xhr :put, :update_card_badge, user_badge_id: user_badge.id, username: user.username
|
|
expect(user.user_profile.reload.card_image_badge_id).to be_blank
|
|
badge.update_attributes image: "wat.com/wat.jpg"
|
|
|
|
xhr :put, :update_card_badge, user_badge_id: user_badge.id, username: user.username
|
|
expect(user.user_profile.reload.card_image_badge_id).to eq(badge.id)
|
|
|
|
# Can set to nothing
|
|
xhr :put, :update_card_badge, username: user.username
|
|
expect(user.user_profile.reload.card_image_badge_id).to be_blank
|
|
end
|
|
end
|
|
|
|
describe "badge_title" do
|
|
let(:user) { Fabricate(:user) }
|
|
let(:badge) { Fabricate(:badge) }
|
|
let(:user_badge) { BadgeGranter.grant(badge, user) }
|
|
|
|
it "sets the user's title to the badge name if it is titleable" do
|
|
log_in_user user
|
|
xhr :put, :badge_title, user_badge_id: user_badge.id, username: user.username
|
|
expect(user.reload.title).not_to eq(badge.name)
|
|
badge.update_attributes allow_title: true
|
|
xhr :put, :badge_title, user_badge_id: user_badge.id, username: user.username
|
|
expect(user.reload.title).to eq(badge.name)
|
|
expect(user.user_profile.badge_granted_title).to eq(true)
|
|
|
|
user.title = "testing"
|
|
user.save
|
|
user.user_profile.reload
|
|
expect(user.user_profile.badge_granted_title).to eq(false)
|
|
|
|
end
|
|
end
|
|
|
|
describe "search_users" do
|
|
|
|
let(:topic) { Fabricate :topic }
|
|
let(:user) { Fabricate :user, username: "joecabot", name: "Lawrence Tierney" }
|
|
|
|
before do
|
|
SearchIndexer.enable
|
|
Fabricate :post, user: user, topic: topic
|
|
end
|
|
|
|
it "searches when provided the term only" do
|
|
xhr :post, :search_users, term: user.name.split(" ").last
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["users"].map { |u| u["username"] }).to include(user.username)
|
|
end
|
|
|
|
it "searches when provided the topic only" do
|
|
xhr :post, :search_users, topic_id: topic.id
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["users"].map { |u| u["username"] }).to include(user.username)
|
|
end
|
|
|
|
it "searches when provided the term and topic" do
|
|
xhr :post, :search_users, term: user.name.split(" ").last, topic_id: topic.id
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["users"].map { |u| u["username"] }).to include(user.username)
|
|
end
|
|
|
|
it "searches only for users who have access to private topic" do
|
|
privileged_user = Fabricate(:user, trust_level: 4, username: "joecabit", name: "Lawrence Tierney")
|
|
privileged_group = Fabricate(:group)
|
|
privileged_group.add(privileged_user)
|
|
privileged_group.save
|
|
|
|
category = Fabricate(:category)
|
|
category.set_permissions(privileged_group => :readonly)
|
|
category.save
|
|
|
|
private_topic = Fabricate(:topic, category: category)
|
|
|
|
xhr :post, :search_users, term: user.name.split(" ").last, topic_id: private_topic.id, topic_allowed_users: "true"
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["users"].map { |u| u["username"] }).to_not include(user.username)
|
|
expect(json["users"].map { |u| u["username"] }).to include(privileged_user.username)
|
|
end
|
|
|
|
context "when `enable_names` is true" do
|
|
before do
|
|
SiteSetting.enable_names = true
|
|
end
|
|
|
|
it "returns names" do
|
|
xhr :post, :search_users, term: user.name
|
|
json = JSON.parse(response.body)
|
|
expect(json["users"].map { |u| u["name"] }).to include(user.name)
|
|
end
|
|
end
|
|
|
|
context "when `enable_names` is false" do
|
|
before do
|
|
SiteSetting.stubs(:enable_names?).returns(false)
|
|
end
|
|
|
|
it "returns names" do
|
|
xhr :post, :search_users, term: user.name
|
|
json = JSON.parse(response.body)
|
|
expect(json["users"].map { |u| u["name"] }).not_to include(user.name)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
describe 'send_activation_email' do
|
|
context 'for an existing user' do
|
|
let(:user) { Fabricate(:user, active: false) }
|
|
|
|
context 'with a valid email_token' do
|
|
it 'should send the activation email' do
|
|
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
|
xhr :post, :send_activation_email, username: user.username
|
|
end
|
|
end
|
|
|
|
context 'without an existing email_token' do
|
|
before do
|
|
user.email_tokens.each {|t| t.destroy}
|
|
user.reload
|
|
end
|
|
|
|
it 'should generate a new token' do
|
|
expect {
|
|
xhr :post, :send_activation_email, username: user.username
|
|
}.to change{ user.email_tokens(true).count }.by(1)
|
|
end
|
|
|
|
it 'should send an email' do
|
|
Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
|
|
xhr :post, :send_activation_email, username: user.username
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when username does not exist' do
|
|
it 'should not send an email' do
|
|
Jobs.expects(:enqueue).never
|
|
xhr :post, :send_activation_email, username: 'nopenopenopenope'
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.pick_avatar' do
|
|
|
|
it 'raises an error when not logged in' do
|
|
expect {
|
|
xhr :put, :pick_avatar, username: 'asdf', avatar_id: 1, type: "custom"
|
|
}.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
|
|
context 'while logged in' do
|
|
|
|
let!(:user) { log_in }
|
|
let(:upload) { Fabricate(:upload) }
|
|
|
|
it "raises an error when you don't have permission to toggle the avatar" do
|
|
another_user = Fabricate(:user)
|
|
xhr :put, :pick_avatar, username: another_user.username, upload_id: upload.id, type: "custom"
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
it "raises an error when sso_overrides_avatar is disabled" do
|
|
SiteSetting.stubs(:sso_overrides_avatar).returns(true)
|
|
xhr :put, :pick_avatar, username: user.username, upload_id: upload.id, type: "custom"
|
|
expect(response).to_not be_success
|
|
end
|
|
|
|
it "raises an error when selecting the custom/uploaded avatar and allow_uploaded_avatars is disabled" do
|
|
SiteSetting.stubs(:allow_uploaded_avatars).returns(false)
|
|
xhr :put, :pick_avatar, username: user.username, upload_id: upload.id, type: "custom"
|
|
expect(response).to_not be_success
|
|
end
|
|
|
|
it 'can successfully pick the system avatar' do
|
|
xhr :put, :pick_avatar, username: user.username
|
|
expect(response).to be_success
|
|
expect(user.reload.uploaded_avatar_id).to eq(nil)
|
|
end
|
|
|
|
it 'can successfully pick a gravatar' do
|
|
xhr :put, :pick_avatar, username: user.username, upload_id: upload.id, type: "gravatar"
|
|
expect(response).to be_success
|
|
expect(user.reload.uploaded_avatar_id).to eq(upload.id)
|
|
expect(user.user_avatar.reload.gravatar_upload_id).to eq(upload.id)
|
|
end
|
|
|
|
it 'can successfully pick a custom avatar' do
|
|
xhr :put, :pick_avatar, username: user.username, upload_id: upload.id, type: "custom"
|
|
expect(response).to be_success
|
|
expect(user.reload.uploaded_avatar_id).to eq(upload.id)
|
|
expect(user.user_avatar.reload.custom_upload_id).to eq(upload.id)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
describe '.destroy_user_image' do
|
|
|
|
it 'raises an error when not logged in' do
|
|
expect { xhr :delete, :destroy_user_image, type: 'profile_background', username: 'asdf' }.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
|
|
context 'while logged in' do
|
|
|
|
let!(:user) { log_in }
|
|
|
|
it 'raises an error when you don\'t have permission to clear the profile background' do
|
|
Guardian.any_instance.expects(:can_edit?).with(user).returns(false)
|
|
xhr :delete, :destroy_user_image, username: user.username, type: 'profile_background'
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
it "requires the `type` param" do
|
|
expect { xhr :delete, :destroy_user_image, username: user.username }.to raise_error(ActionController::ParameterMissing)
|
|
end
|
|
|
|
it "only allows certain `types`" do
|
|
expect { xhr :delete, :destroy_user_image, username: user.username, type: 'wat' }.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
|
|
it 'can clear the profile background' do
|
|
xhr :delete, :destroy_user_image, type: 'profile_background', username: user.username
|
|
expect(user.reload.user_profile.profile_background).to eq("")
|
|
expect(response).to be_success
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
describe '.destroy' do
|
|
it 'raises an error when not logged in' do
|
|
expect { xhr :delete, :destroy, username: 'nobody' }.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
|
|
context 'while logged in' do
|
|
let!(:user) { log_in }
|
|
|
|
it 'raises an error when you cannot delete your account' do
|
|
Guardian.any_instance.stubs(:can_delete_user?).returns(false)
|
|
UserDestroyer.any_instance.expects(:destroy).never
|
|
xhr :delete, :destroy, username: user.username
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
it "raises an error when you try to delete someone else's account" do
|
|
UserDestroyer.any_instance.expects(:destroy).never
|
|
xhr :delete, :destroy, username: Fabricate(:user).username
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
it "deletes your account when you're allowed to" do
|
|
Guardian.any_instance.stubs(:can_delete_user?).returns(true)
|
|
UserDestroyer.any_instance.expects(:destroy).with(user, anything).returns(user)
|
|
xhr :delete, :destroy, username: user.username
|
|
expect(response).to be_success
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.my_redirect' do
|
|
|
|
it "redirects if the user is not logged in" do
|
|
get :my_redirect, path: "wat"
|
|
expect(response).not_to be_success
|
|
expect(response).to be_redirect
|
|
end
|
|
|
|
context "when the user is logged in" do
|
|
let!(:user) { log_in }
|
|
|
|
it "will not redirect to an invalid path" do
|
|
get :my_redirect, path: "wat/..password.txt"
|
|
expect(response).not_to be_redirect
|
|
end
|
|
|
|
it "will redirect to an valid path" do
|
|
get :my_redirect, path: "preferences"
|
|
expect(response).to be_redirect
|
|
end
|
|
|
|
it "permits forward slashes" do
|
|
get :my_redirect, path: "activity/posts"
|
|
expect(response).to be_redirect
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.check_emails' do
|
|
|
|
it 'raises an error when not logged in' do
|
|
expect { xhr :put, :check_emails, username: 'zogstrip' }.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
|
|
context 'while logged in' do
|
|
let!(:user) { log_in }
|
|
|
|
it "raises an error when you aren't allowed to check emails" do
|
|
Guardian.any_instance.expects(:can_check_emails?).returns(false)
|
|
xhr :put, :check_emails, username: Fabricate(:user).username
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
it "returns both email and associated_accounts when you're allowed to see them" do
|
|
Guardian.any_instance.expects(:can_check_emails?).returns(true)
|
|
xhr :put, :check_emails, username: Fabricate(:user).username
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["email"]).to be_present
|
|
expect(json["associated_accounts"]).to be_present
|
|
end
|
|
|
|
it "works on inactive users" do
|
|
inactive_user = Fabricate(:user, active: false)
|
|
Guardian.any_instance.expects(:can_check_emails?).returns(true)
|
|
xhr :put, :check_emails, username: inactive_user.username
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["email"]).to be_present
|
|
expect(json["associated_accounts"]).to be_present
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
describe ".is_local_username" do
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
let(:group) { Fabricate(:group, name: "Discourse") }
|
|
let(:topic) { Fabricate(:topic) }
|
|
let(:allowed_user) { Fabricate(:user) }
|
|
let(:private_topic) { Fabricate(:private_message_topic, user: allowed_user) }
|
|
|
|
it "finds the user" do
|
|
xhr :get, :is_local_username, username: user.username
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["valid"][0]).to eq(user.username)
|
|
end
|
|
|
|
it "finds the group" do
|
|
xhr :get, :is_local_username, username: group.name
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["valid_groups"][0]).to eq(group.name)
|
|
end
|
|
|
|
it "supports multiples usernames" do
|
|
xhr :get, :is_local_username, usernames: [user.username, "system"]
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["valid"].size).to eq(2)
|
|
end
|
|
|
|
it "never includes staged accounts" do
|
|
staged = Fabricate(:user, staged: true)
|
|
xhr :get, :is_local_username, usernames: [staged.username]
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["valid"].size).to eq(0)
|
|
end
|
|
|
|
it "returns user who cannot see topic" do
|
|
Guardian.any_instance.expects(:can_see?).with(topic).returns(false)
|
|
xhr :get, :is_local_username, usernames: [user.username], topic_id: topic.id
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["cannot_see"].size).to eq(1)
|
|
end
|
|
|
|
it "never returns a user who can see the topic" do
|
|
Guardian.any_instance.expects(:can_see?).with(topic).returns(true)
|
|
xhr :get, :is_local_username, usernames: [user.username], topic_id: topic.id
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["cannot_see"].size).to eq(0)
|
|
end
|
|
|
|
it "returns user who cannot see a private topic" do
|
|
Guardian.any_instance.expects(:can_see?).with(private_topic).returns(false)
|
|
xhr :get, :is_local_username, usernames: [user.username], topic_id: private_topic.id
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["cannot_see"].size).to eq(1)
|
|
end
|
|
|
|
it "never returns a user who can see the topic" do
|
|
Guardian.any_instance.expects(:can_see?).with(private_topic).returns(true)
|
|
xhr :get, :is_local_username, usernames: [allowed_user.username], topic_id: private_topic.id
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
expect(json["cannot_see"].size).to eq(0)
|
|
end
|
|
|
|
end
|
|
|
|
describe '.topic_tracking_state' do
|
|
let(:user){Fabricate(:user)}
|
|
|
|
context 'anon' do
|
|
it "raises an error on anon for topic_tracking_state" do
|
|
expect{
|
|
xhr :get, :topic_tracking_state, username: user.username, format: :json
|
|
}.to raise_error(Discourse::NotLoggedIn)
|
|
end
|
|
end
|
|
|
|
context 'logged on' do
|
|
it "detects new topic" do
|
|
log_in_user(user)
|
|
|
|
topic = Fabricate(:topic)
|
|
xhr :get, :topic_tracking_state, username: user.username, format: :json
|
|
|
|
states = JSON.parse(response.body)
|
|
|
|
expect(states[0]["topic_id"]).to eq(topic.id)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.summary' do
|
|
|
|
it "generates summary info" do
|
|
user = Fabricate(:user)
|
|
create_post(user: user)
|
|
|
|
xhr :get, :summary, username: user.username_lower
|
|
expect(response).to be_success
|
|
json = JSON.parse(response.body)
|
|
|
|
expect(json["user_summary"]["topic_count"]).to eq(1)
|
|
expect(json["user_summary"]["post_count"]).to eq(1)
|
|
end
|
|
end
|
|
|
|
end
|