diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
deleted file mode 100644
index 3b5e60c131d..00000000000
--- a/spec/controllers/users_controller_spec.rb
+++ /dev/null
@@ -1,2466 +0,0 @@
-require 'rails_helper'
-
-describe UsersController do
-
- describe '.show' do
-
- context "anon" do
-
- let(:user) { Discourse.system_user }
-
- it "returns success" do
- get :show, params: { username: user.username }, format: :json
- expect(response).to be_success
- end
-
- it "should redirect to login page for anonymous user when profiles are hidden" do
- SiteSetting.hide_user_profiles_from_public = true
- get :show, params: { username: user.username }, format: :json
- expect(response).to redirect_to '/login'
- end
-
- end
-
- context "logged in" do
-
- let(:user) { log_in }
-
- it 'returns success' do
- get :show, params: { username: user.username, format: :json }, 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
- get :show, params: { username: 'madeuppity' }, format: :json
- expect(response).not_to be_success
- end
-
- it 'returns not found when the user is inactive' do
- inactive = Fabricate(:user, active: false)
- get :show, params: { username: inactive.username }, format: :json
- expect(response).not_to be_success
- end
-
- it 'returns success when show_inactive_accounts is true and user is logged in' do
- SiteSetting.show_inactive_accounts = true
- log_in_user(user)
- inactive = Fabricate(:user, active: false)
- get :show, params: { username: inactive.username }, format: :json
- expect(response).to be_success
- end
-
- it "raises an error on invalid access" do
- Guardian.any_instance.expects(:can_see?).with(user).returns(false)
- get :show, params: { username: user.username }, format: :json
- 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)
- get :show, params: { username: other_user.username }, format: :json
- end
-
- it "should not track a user profile view for a user viewing his own profile" do
- UserProfileView.expects(:add).never
- get :show, params: { username: user.username }, format: :json
- 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)
- get :show, params: { username: other_user.username }, format: :json
- end
-
- it "skips tracking" do
- UserProfileView.expects(:add).never
- get :show, params: { username: user.username, skip_track_visit: true }, format: :json
- 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
- get :show, params: { external_id: '997' }, format: :json
- expect(response).to be_success
- end
-
- it "returns not found when external_id doesn't match" do
- get :show, params: { external_id: '99' }, format: :json
- expect(response).not_to be_success
- end
- end
-
- describe "include_post_count_for" do
-
- let(:admin) { Fabricate(:admin) }
- let(:topic) { Fabricate(:topic) }
-
- before do
- Fabricate(:post, user: user, topic: topic)
- Fabricate(:post, user: admin, topic: topic)
- Fabricate(:post, user: admin, topic: topic, post_type: Post.types[:whisper])
- end
-
- it "includes only visible posts" do
- get :show,
- params: { username: admin.username, include_post_count_for: topic.id },
- format: :json
-
- topic_post_count = JSON.parse(response.body).dig("user", "topic_post_count")
- expect(topic_post_count[topic.id.to_s]).to eq(1)
- end
-
- it "includes all post types for staff members" do
- log_in_user(admin)
-
- get :show,
- params: { username: admin.username, include_post_count_for: topic.id },
- format: :json
-
- topic_post_count = JSON.parse(response.body).dig("user", "topic_post_count")
- expect(topic_post_count[topic.id.to_s]).to eq(2)
- end
- end
- 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, params: { 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, params: { 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, params: { 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, params: { token: 'asdfasdf' }, format: :json
- expect(response).not_to be_success
- end
- end
-
- context 'response' do
- render_views
-
- before do
- Guardian.any_instance.expects(:can_access_forum?).returns(true)
- EmailToken.expects(:confirm).with('asdfasdf').returns(user)
- end
-
- it 'correctly logs on user' do
- events = DiscourseEvent.track_events do
- put :perform_account_activation, params: { token: 'asdfasdf' }
- end
-
- expect(events.map { |event| event[:event_name] }).to include(
- :user_logged_in, :user_first_logged_in
- )
-
- expect(response).to be_success
- expect(flash[:error]).to be_blank
- expect(session[:current_user_id]).to be_present
-
- expect(response).to be_success
-
- expect(CGI.unescapeHTML(response.body))
- .to_not include(I18n.t('activation.approval_required'))
- end
-
- end
-
- context 'user is not approved' do
- render_views
-
- before do
- SiteSetting.must_approve_users = true
- EmailToken.expects(:confirm).with('asdfasdf').returns(user)
- put :perform_account_activation, params: { token: 'asdfasdf' }
- end
-
- it 'should return the right response' do
- expect(response).to be_success
-
- expect(CGI.unescapeHTML(response.body))
- .to include(I18n.t('activation.approval_required'))
-
- expect(response.body).to_not have_tag(:script, with: {
- src: '/assets/application.js'
- })
-
- expect(flash[:error]).to be_blank
- expect(session[:current_user_id]).to be_blank
- end
- end
-
- end
- end
-
- describe '#perform_account_activation' do
- describe 'when cookies contains a destination URL' do
- let(:token) { 'asdadwewq' }
- let(:user) { Fabricate(:user) }
-
- before do
- UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(false)
- EmailToken.expects(:confirm).with(token).returns(user)
- end
-
- it 'should redirect to the URL' do
- destination_url = 'http://thisisasite.com/somepath'
- request.cookies[:destination_url] = destination_url
-
- put :perform_account_activation, params: { token: token }
-
- expect(response).to redirect_to(destination_url)
- 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, params: { token: 'asdfasdf' }
- expect(response).to be_success
- end
- end
-
- context 'missing token' do
- render_views
-
- before do
- get :password_reset, params: { token: SecureRandom.hex }
- end
-
- it 'disallows login' do
- expect(response).to be_success
-
- expect(CGI.unescapeHTML(response.body))
- .to include(I18n.t('password_reset.no_token'))
-
- expect(response.body).to_not have_tag(:script, with: {
- src: '/assets/application.js'
- })
-
- expect(session[:current_user_id]).to be_blank
- end
- end
-
- context 'invalid token' do
- render_views
-
- it 'disallows login' do
- get :password_reset, params: { token: "evil_trout!" }
-
- expect(response).to be_success
-
- expect(CGI.unescapeHTML(response.body))
- .to include(I18n.t('password_reset.no_token'))
-
- expect(response.body).to_not have_tag(:script, with: {
- src: '/assets/application.js'
- })
-
- expect(session[:current_user_id]).to be_blank
- end
-
- it "responds with proper error message" do
- put :password_reset, params: {
- token: "evil_trout!", password: "awesomeSecretPassword"
- }, format: :json
-
- expect(response).to be_success
- expect(JSON.parse(response.body)["message"]).to eq(I18n.t('password_reset.no_token'))
- expect(session[:current_user_id]).to be_blank
- end
- end
-
- context 'valid token' do
- render_views
-
- context 'when rendered' do
- it 'renders referrer never on get requests' do
- user = Fabricate(:user)
- token = user.email_tokens.create(email: user.email).token
- get :password_reset, params: { token: token }
-
- expect(response.body).to include('')
- 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, params: { token: token }
-
- events = DiscourseEvent.track_events do
- put :password_reset,
- params: { token: token, password: 'hg9ow8yhg98o' }
- end
-
- expect(events.map { |event| event[:event_name] }).to include(
- :user_logged_in, :user_first_logged_in
- )
-
- expect(response).to be_success
- expect(response.body).to include('{"is_developer":false,"admin":false,"second_factor_required":false}')
-
- 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, params: { token: token }
-
- put :password_reset,
- params: { token: token, password: 'hg9ow8yHG32O' }
-
- put :password_reset,
- params: { token: token, password: 'test123987AsdfXYZ' }
-
- user.reload
- expect(user.confirm_password?('hg9ow8yHG32O')).to eq(true)
-
- # logged in now
- expect(user.user_auth_tokens.count).to eq(1)
- end
-
- it "doesn't redirect to wizard on get" do
- user = Fabricate(:admin)
- UserAuthToken.generate!(user_id: user.id)
-
- token = user.email_tokens.create(email: user.email).token
- get :password_reset, params: { token: token }, format: :json
- expect(response).not_to redirect_to(wizard_path)
- end
-
- it "redirects to the wizard if you're the first admin" do
- user = Fabricate(:admin)
- UserAuthToken.generate!(user_id: user.id)
-
- token = user.email_tokens.create(email: user.email).token
- get :password_reset, params: { token: token }
-
- put :password_reset, params: {
- token: token, password: 'hg9ow8yhg98oadminlonger'
- }
-
- expect(response).to redirect_to(wizard_path)
- 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, params: { token: email_token.token }, format: :json
-
- email_token.reload
-
- expect(email_token.confirmed).to eq(false)
- expect(UserAuthToken.where(id: user_token.id).count).to eq(1)
- end
-
- context '2 factor authentication required' do
- let!(:second_factor) { Fabricate(:user_second_factor, user: user) }
-
- it 'does not change with an invalid token' do
- token = user.email_tokens.create!(email: user.email).token
-
- get :password_reset, params: { token: token }
-
- expect(response.body).to include('{"is_developer":false,"admin":false,"second_factor_required":true}')
-
- put :password_reset,
- params: { token: token, password: 'hg9ow8yHG32O', second_factor_token: '000000' }
-
- expect(response.body).to include(I18n.t("login.invalid_second_factor_code"))
-
- user.reload
- expect(user.confirm_password?('hg9ow8yHG32O')).not_to eq(true)
- expect(user.user_auth_tokens.count).not_to eq(1)
- end
-
- it 'changes password with valid 2-factor tokens' do
- token = user.email_tokens.create(email: user.email).token
-
- get :password_reset, params: { token: token }
-
- put :password_reset, params: {
- token: token,
- password: 'hg9ow8yHG32O',
- second_factor_token: ROTP::TOTP.new(second_factor.data).now
- }
-
- user.reload
- expect(user.confirm_password?('hg9ow8yHG32O')).to eq(true)
- expect(user.user_auth_tokens.count).to eq(1)
- end
- 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, params: {
- token: token, password: ''
- }, format: :json
-
- expect(response).to be_success
- expect(JSON.parse(response.body)["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, params: {
- token: token, password: ('x' * (User.max_password_length + 1))
- }, format: :json
-
- expect(response).to be_success
- expect(JSON.parse(response.body)["errors"]).to be_present
- expect(session[:current_user_id]).to be_blank
- end
-
- it "logs in the user" do
- put :password_reset, params: {
- token: token, password: 'ksjafh928r'
- }, format: :json
-
- expect(response).to be_success
- expect(JSON.parse(response.body)["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.must_approve_users = true
- put :password_reset, params: {
- token: token, password: 'ksjafh928r'
- }, format: :json
-
- expect(JSON.parse(response.body)["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, params: { 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, params: { 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, params: { email: admin.email }
- end
- end
-
- context 'when email is incorrect' do
- render_views
-
- it 'should return the right response' do
- put :admin_login, params: { email: 'random' }
-
- expect(response.status).to eq(200)
-
- response_body = response.body
-
- expect(response_body).to match(I18n.t("admin_login.errors.unknown_email_address"))
- expect(response_body).to_not match(I18n.t("login.second_factor_description"))
- end
- end
-
- context 'logs in admin' do
- it 'does not log in admin with invalid token' do
- SiteSetting.sso_url = "https://www.example.com/sso"
- SiteSetting.enable_sso = true
- get :admin_login, params: { token: "invalid" }
- expect(session[:current_user_id]).to be_blank
- end
-
- context 'valid token' do
- it 'does log in admin with SSO disabled' do
- SiteSetting.enable_sso = false
- token = admin.email_tokens.create(email: admin.email).token
-
- get :admin_login, params: { token: token }
- expect(response).to redirect_to('/')
- expect(session[:current_user_id]).to eq(admin.id)
- end
-
- it 'logs in admin with SSO enabled' do
- SiteSetting.sso_url = "https://www.example.com/sso"
- SiteSetting.enable_sso = true
- token = admin.email_tokens.create(email: admin.email).token
-
- get :admin_login, params: { token: token }
- expect(response).to redirect_to('/')
- expect(session[:current_user_id]).to eq(admin.id)
- end
- end
-
- describe 'when 2 factor authentication is enabled' do
- let(:second_factor) { Fabricate(:user_second_factor, user: admin) }
- let(:email_token) { Fabricate(:email_token, user: admin) }
- render_views
-
- it 'does not log in when token required' do
- second_factor
- get :admin_login, params: { token: email_token.token }
- expect(response).not_to redirect_to('/')
- expect(session[:current_user_id]).not_to eq(admin.id)
- expect(response.body).to include(I18n.t('login.second_factor_description'));
- end
-
- describe 'invalid 2 factor token' do
- it 'should display the right error' do
- second_factor
-
- put :admin_login, params: {
- token: email_token.token,
- second_factor_token: '13213'
- }
-
- expect(response.status).to eq(200)
- expect(response.body).to include(I18n.t('login.second_factor_description'));
- expect(response.body).to include(I18n.t('login.invalid_second_factor_code'));
- end
- end
-
- it 'logs in when a valid 2-factor token is given' do
- put :admin_login, params: {
- token: email_token.token,
- second_factor_token: ROTP::TOTP.new(second_factor.data).now
- }
-
- expect(response).to redirect_to('/')
- expect(session[:current_user_id]).to eq(admin.id)
- end
- 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, format: :json
- expect(response).to be_success
- expect(session[:current_user_id]).to eq(AnonymousShadowCreator.get(user).id)
-
- post :toggle_anon, format: :json
- 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.allow_new_registrations = 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
- post :create, params: post_user_params, format: :json
- end
-
- context 'when email params is missing' do
- it 'should raise the right error' do
- expect do
- post :create, params: {
- name: @user.name,
- username: @user.username,
- passsword: 'tesing12352343'
- }, format: :json
- end.to raise_error(ActionController::ParameterMissing)
- end
- end
-
- context 'when creating a user' do
- it 'sets the user locale to I18n.locale' do
- SiteSetting.default_locale = '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.enable_local_logins = false
- post_user
-
- expect(response.status).to eq(500)
- end
-
- it 'returns an error when new registrations are disabled' do
- SiteSetting.allow_new_registrations = 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
- expect(session[SessionController::ACTIVATE_USER_KEY]).to be_present
- end
-
- context "`must approve users` site setting is enabled" do
- before { SiteSetting.must_approve_users = true }
-
- 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
- expect(session[SessionController::ACTIVATE_USER_KEY]).to be_present
- end
- end
-
- context 'users already exists with given email' do
- let!(:existing) { Fabricate(:user, email: post_user_params[:email]) }
-
- it 'returns an error if hide_email_address_taken is disabled' do
- SiteSetting.hide_email_address_taken = false
- post_user
- json = JSON.parse(response.body)
- expect(json['success']).to eq(false)
- expect(json['message']).to be_present
- end
-
- it 'returns success if hide_email_address_taken is enabled' do
- SiteSetting.hide_email_address_taken = true
- expect {
- post_user
- }.to_not change { User.count }
- json = JSON.parse(response.body)
- expect(json['active']).to be_falsey
- expect(session["user_created_message"]).to be_present
- end
- end
- end
-
- context "creating as active" do
- it "won't create the user as active" do
- post :create, params: post_user_params.merge(active: true), format: :json
- 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
- post :create,
- params: post_user_params.merge(active: true, api_key: api_key.key),
- format: :json
-
- expect(JSON.parse(response.body)['active']).to be_falsey
- end
- end
-
- context "with an admin api key" do
- let(:admin) { Fabricate(:admin) }
- let(:api_key) { Fabricate(:api_key, user: admin) }
-
- it "creates the user as active with a regular key" do
- SiteSetting.queue_jobs = true
- SiteSetting.send_welcome_message = true
- SiteSetting.must_approve_users = true
-
- Sidekiq::Client.expects(:enqueue).never
-
- post :create,
- params: post_user_params.merge(approved: true, active: true, api_key: api_key.key),
- format: :json
-
- json = JSON.parse(response.body)
-
- new_user = User.find(json["user_id"])
-
- expect(json['active']).to be_truthy
-
- expect(new_user.active).to eq(true)
- expect(new_user.approved).to eq(true)
- expect(new_user.approved_by_id).to eq(admin.id)
- expect(new_user.approved_at).to_not eq(nil)
- end
-
- it "won't create the developer as active" do
- UsernameCheckerService.expects(:is_developer?).returns(true)
-
- post :create,
- params: post_user_params.merge(active: true, api_key: api_key.key),
- format: :json
-
- 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
- post :create,
- params: post_user_params.merge(staged: true),
- format: :json
-
- 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
- post :create,
- params: post_user_params.merge(staged: true, api_key: api_key.key),
- format: :json
-
- 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
- post :create,
- params: post_user_params.merge(staged: true, api_key: api_key.key),
- format: :json
-
- 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)
- post :create,
- params: post_user_params.merge(staged: true, api_key: api_key.key),
- format: :json
-
- 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
- expect(session[SessionController::ACTIVATE_USER_KEY]).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.allow_new_registrations = 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
-
- it 'should create twitter user info if required' do
- SiteSetting.must_approve_users = true
- SiteSetting.enable_twitter_logins = true
- twitter_auth = { twitter_user_id: 42, twitter_screen_name: "bruce" }
- auth = session[:authentication] = {}
- auth[:authenticator_name] = 'twitter'
- auth[:extra_data] = twitter_auth
-
- post_user
-
- expect(TwitterUserInfo.count).to eq(1)
- end
- end
-
- it "returns an error when email has been changed from the validated email address" do
- auth = session[:authentication] = {}
- auth[:email_valid] = 'true'
- auth[:email] = 'therealone@gmail.com'
- post_user
- json = JSON.parse(response.body)
- expect(json['success']).to eq(false)
- expect(json['message']).to be_present
- end
-
- it "will create the user successfully if email validation is required" do
- auth = session[:authentication] = {}
- auth[:email] = post_user_params[:email]
- post_user
- json = JSON.parse(response.body)
- expect(json['success']).to eq(true)
- 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 {
- post :create, params: create_params, format: :json
- }.to_not change { User.count }
- end
-
- it 'should not send an email' do
- User.any_instance.expects(:enqueue_welcome_message).never
- post :create, params: create_params, format: :json
- end
-
- it 'should say it was successful' do
- post :create, params: create_params, format: :json
- json = JSON::parse(response.body)
- expect(json["success"]).to eq(true)
-
- # should not change the session
- expect(session["user_created_message"]).to be_blank
- expect(session[SessionController::ACTIVATE_USER_KEY]).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.invite_only = 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 { post :create, params: create_params, format: :json }.to_not change { User.count }
- end
-
- it 'should report failed' do
- post :create, params: create_params, format: :json
- 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
- expect(session[SessionController::ACTIVATE_USER_KEY]).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
- before { User.any_instance.stubs(:save).raises(ActiveRecord::StatementInvalid.new('Oh no')) }
-
- let(:create_params) {
- { name: @user.name, username: @user.username,
- password: "strongpassword", email: @user.email }
- }
-
- include_examples 'failed signup'
- 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: 'suChS3cuRi7y',
- 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
- post :create, params: create_params, format: :json
- expect(response).to be_success
- inserted = User.find_by_email(@user.email)
- 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'
- post :create, params: create_params.merge(create_params), format: :json
- expect(response).to be_success
- inserted = User.find_by_email(@user.email)
- 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)
- post :create, params: create_params.merge(create_params), format: :json
- expect(response).to be_success
- inserted = User.find_by_email(@user.email)
-
- 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: 'suChS3cuRi7y',
- username: @user.username,
- email: @user.email,
- } }
-
- it "should succeed" do
- post :create, params: create_params, format: :json
- expect(response).to be_success
- inserted = User.find_by_email(@user.email)
- 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
-
- end
-
- context '#username' do
- it 'raises an error when not logged in' do
- put :username, params: { username: 'somename' }, format: :json
- expect(response.status).to eq(403)
- 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 do
- put :username, params: { username: user.username }, format: :json
- end.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)
-
- put :username, params: {
- username: user.username, new_username: new_username
- }, format: :json
-
- expect(response).to be_forbidden
- expect(user.reload.username).to eq(old_username)
- end
-
- it 'raises an error when change_username fails' do
- put :username,
- params: { username: user.username, new_username: '@' },
- format: :json
-
- expect(response).to_not be_success
-
- body = JSON.parse(response.body)
-
- expect(body['errors'].first).to include(I18n.t(
- 'user.username.short', min: User.username_length.begin
- ))
-
- expect(user.reload.username).to eq(old_username)
- end
-
- it 'should succeed in normal circumstances' do
- put :username,
- params: { username: user.username, new_username: new_username },
- format: :json
-
- expect(response).to be_success
- expect(user.reload.username).to eq(new_username)
- end
-
- it 'should fail if the user is old' do
- # Older than the change period and >1 post
- user.created_at = Time.now - (SiteSetting.username_change_period + 1).days
- PostCreator.new(user,
- title: 'This is a test topic',
- raw: 'This is a test this is a test'
- ).create
-
- put :username, params: {
- username: user.username, new_username: new_username
- }, format: :json
-
- 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)
-
- put :username, params: {
- username: user.username, new_username: new_username
- }, format: :json
-
- 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
- put :username, params: {
- username: user.username, new_username: new_username
- }, format: :json
-
- 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 do
- get :check_username, format: :json
- end.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
- get :check_username, params: { email: 'dood@example.com' }, format: :json
- expect(response).to be_success
- end
-
- context 'username is available' do
- before do
- get :check_username, params: { username: 'BruceWayne' }, format: :json
- end
- include_examples 'when username is available'
- end
-
- context 'username is unavailable' do
- let!(:user) { Fabricate(:user) }
- before do
- get :check_username, params: { username: user.username }, format: :json
- 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
- get :check_username, params: {
- username: 'bad username'
- }, format: :json
- 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
- get :check_username, params: {
- username: generate_username(User.username_length.last + 1)
- }, format: :json
- 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)
-
- get :check_username, params: {
- username: 'HanSolo'
- }, format: :json
- 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
-
- get :check_username, params: {
- username: 'HanSolo'
- }, format: :json
- 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))
-
- get :check_username, params: {
- username: 'HanSolo', for_user_id: user.id
- }, format: :json
- end
- include_examples 'when username is available'
- end
- end
- end
-
- describe '#invited' do
- it 'returns success' do
- user = Fabricate(:user)
- get :invited, params: { username: user.username }, format: :json
-
- 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
- )
-
- get :invited, params: {
- username: inviter.username, search: 'billybob'
- }, format: :json
-
- 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')
- )
-
- get :invited, params: {
- username: inviter.username, search: 'billybob'
- }, format: :json
-
- 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)
-
- get :invited,
- params: { username: inviter.username, filter: 'pending' },
- format: :json
-
- 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)
-
- get :invited,
- params: { username: inviter.username },
- format: :json
-
- 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
-
- get :invited, params: {
- username: inviter.username, filter: 'pending'
- }, format: :json
-
- 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
-
- get :invited, params: {
- username: inviter.username, filter: 'pending'
- }, format: :json
-
- 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)
-
- get :invited, params: { username: inviter.username }, format: :json
-
- 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
- put :update, params: { username: 'guest' }, format: :json
- expect(response.status).to eq(403)
- 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, params: {
- username: user.username,
- name: 'Jim Tom',
- title: "foobar",
- user_fields: { user_field.id.to_s => 'happy' }
- }, format: :json
-
- expect(response).to be_success
-
- user.reload
-
- expect(user.user_fields[user_field.id.to_s]).to eq('happy')
- expect(user.title).to eq("foobar")
- 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)
- tags = [Fabricate(:tag), Fabricate(:tag)]
-
- put :update, params: {
- username: user.username,
- name: 'Jim Tom',
- custom_fields: { test: :it },
- muted_usernames: "#{user2.username},#{user3.username}",
- watched_tags: "#{tags[0].name},#{tags[1].name}"
- }, format: :json
-
- 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
- expect(TagUser.where(
- user: user,
- notification_level: TagUser.notification_levels[:watching]
- ).pluck(:tag_id)).to contain_exactly(tags[0].id, tags[1].id)
-
- theme = Theme.create(name: "test", user_selectable: true, user_id: -1)
-
- put :update, params: {
- username: user.username,
- muted_usernames: "",
- theme_key: theme.key,
- email_direct: false
- }, format: :json
-
- user.reload
-
- expect(user.muted_users.pluck(:username).sort).to be_empty
- expect(user.user_option.theme_key).to eq(theme.key)
- expect(user.user_option.email_direct).to eq(false)
- 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, params: {
- username: user.username,
- locale: :fa_IR
- }, format: :json
-
- 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, params: {
- username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
- }, format: :json
-
- 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, params: {
- username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => '' }
- }, format: :json
-
- 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, params: {
- username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => ('x' * 3000) }
- }, format: :json
-
- expect(user.user_fields[user_field.id.to_s].size).to eq(UserField.max_length)
- end
-
- it "should retain existing user fields" do
- put :update, params: {
- username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy', optional_field.id.to_s => 'feet' }
- }, format: :json
-
- expect(response).to be_success
- expect(user.user_fields[user_field.id.to_s]).to eq('happy')
- expect(user.user_fields[optional_field.id.to_s]).to eq('feet')
-
- put :update, params: {
- username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'sad' }
- }, format: :json
-
- expect(response).to be_success
-
- user.reload
-
- expect(user.user_fields[user_field.id.to_s]).to eq('sad')
- expect(user.user_fields[optional_field.id.to_s]).to eq('feet')
- end
- end
-
- context "uneditable field" do
- let!(:user_field) { Fabricate(:user_field, editable: false) }
-
- it "does not update the user field" do
- put :update, params: {
- username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
- }, format: :json
-
- 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, params: { username: user.username }, format: :json
-
- 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,
- params: { username: user.username, name: 'Jim Tom' },
- format: :json
-
- expect(response).to be_forbidden
- expect(user.reload.name).not_to eq 'Jim Tom'
- end
- end
- 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
-
- put :badge_title, params: {
- user_badge_id: user_badge.id, username: user.username
- }, format: :json
-
- expect(user.reload.title).not_to eq(badge.display_name)
- badge.update_attributes allow_title: true
-
- put :badge_title, params: {
- user_badge_id: user_badge.id, username: user.username
- }, format: :json
-
- expect(user.reload.title).to eq(badge.display_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 "badge_title with overrided name" do
- let(:user) { Fabricate(:user) }
- let(:badge) { Fabricate(:badge, name: 'Demogorgon', allow_title: true) }
- let(:user_badge) { BadgeGranter.grant(badge, user) }
-
- before do
- TranslationOverride.upsert!('en', 'badges.demogorgon.name', 'Boss')
- end
-
- after do
- TranslationOverride.revert!('en', ['badges.demogorgon.name'])
- end
-
- it "uses the badge display name as user title" do
- log_in_user user
-
- put :badge_title, params: {
- user_badge_id: user_badge.id, username: user.username
- }, format: :json
-
- expect(user.reload.title).to eq(badge.display_name)
- end
- end
-
- describe 'send_activation_email' do
- context 'for an existing user' do
- let(:user) { Fabricate(:user, active: false) }
-
- context 'for an activated account with email confirmed' do
- it 'fails' do
- active_user = Fabricate(:user, active: true)
- email_token = active_user.email_tokens.create(email: active_user.email).token
- EmailToken.confirm(email_token)
- session[SessionController::ACTIVATE_USER_KEY] = active_user.id
-
- post :send_activation_email, params: {
- username: active_user.username
- }, format: :json
-
- expect(response.status).to eq(409)
-
- expect(JSON.parse(response.body)['errors']).to include(I18n.t(
- 'activation.activated'
- ))
-
- expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
- end
- end
-
- context 'for an activated account with unconfirmed email' do
- it 'should send an email' do
- unconfirmed_email_user = Fabricate(:user, active: true)
- unconfirmed_email_user.email_tokens.create(email: unconfirmed_email_user.email)
- session[SessionController::ACTIVATE_USER_KEY] = unconfirmed_email_user.id
- Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup, to_address: unconfirmed_email_user.email))
-
- post :send_activation_email, params: {
- username: unconfirmed_email_user.username
- }, format: :json
-
- expect(response.status).to eq(200)
-
- expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
- end
- end
-
- context "approval is enabled" do
- before do
- SiteSetting.must_approve_users = true
- end
-
- it "should raise an error" do
- unconfirmed_email_user = Fabricate(:user, active: true)
- unconfirmed_email_user.email_tokens.create(email: unconfirmed_email_user.email)
- session[SessionController::ACTIVATE_USER_KEY] = unconfirmed_email_user.id
- post :send_activation_email, params: {
- username: unconfirmed_email_user.username
- }, format: :json
-
- expect(response.status).to eq(403)
- end
- end
-
- describe 'when user does not have a valid session' do
- it 'should not be valid' do
- user = Fabricate(:user)
- post :send_activation_email, params: {
- username: user.username
- }, format: :json
-
- expect(response.status).to eq(403)
- end
-
- it 'should allow staff regardless' do
- log_in :admin
- user = Fabricate(:user, active: false)
-
- post :send_activation_email, params: {
- username: user.username
- }, format: :json
-
- expect(response.status).to eq(200)
- end
- end
-
- context 'with a valid email_token' do
- it 'should send the activation email' do
- session[SessionController::ACTIVATE_USER_KEY] = user.id
- Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
-
- post :send_activation_email, params: {
- username: user.username
- }, format: :json
-
- expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
- 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 {
- session[SessionController::ACTIVATE_USER_KEY] = user.id
-
- post :send_activation_email,
- params: { username: user.username },
- format: :json
- }.to change { user.reload.email_tokens.count }.by(1)
- end
-
- it 'should send an email' do
- session[SessionController::ACTIVATE_USER_KEY] = user.id
- Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
-
- post :send_activation_email,
- params: { username: user.username },
- format: :json
-
- expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
- end
- end
- end
-
- context 'when username does not exist' do
- it 'should not send an email' do
- Jobs.expects(:enqueue).never
-
- post :send_activation_email,
- params: { username: 'nopenopenopenope' },
- format: :json
- end
- end
- end
-
- describe '.pick_avatar' do
-
- it 'raises an error when not logged in' do
- put :pick_avatar, params: {
- username: 'asdf', avatar_id: 1, type: "custom"
- }, format: :json
- expect(response.status).to eq(403)
- 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)
- put :pick_avatar, params: {
- username: another_user.username, upload_id: upload.id, type: "custom"
- }, format: :json
-
- expect(response).to be_forbidden
- end
-
- it "raises an error when sso_overrides_avatar is disabled" do
- SiteSetting.sso_overrides_avatar = true
- put :pick_avatar, params: {
- username: user.username, upload_id: upload.id, type: "custom"
- }, format: :json
-
- 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.allow_uploaded_avatars = false
- put :pick_avatar, params: {
- username: user.username, upload_id: upload.id, type: "custom"
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it 'can successfully pick the system avatar' do
- put :pick_avatar, params: {
- username: user.username
- }, format: :json
-
- expect(response).to be_success
- expect(user.reload.uploaded_avatar_id).to eq(nil)
- end
-
- it 'can successfully pick a gravatar' do
- put :pick_avatar, params: {
- username: user.username, upload_id: upload.id, type: "gravatar"
- }, format: :json
-
- 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
- put :pick_avatar, params: {
- username: user.username, upload_id: upload.id, type: "custom"
- }, format: :json
-
- 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
- delete :destroy_user_image,
- params: { type: 'profile_background', username: 'asdf' },
- format: :json
- expect(response.status).to eq(403)
- 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)
-
- delete :destroy_user_image,
- params: { username: user.username, type: 'profile_background' },
- format: :json
-
- expect(response).to be_forbidden
- end
-
- it "requires the `type` param" do
- expect do
- delete :destroy_user_image, params: { username: user.username }, format: :json
- end.to raise_error(ActionController::ParameterMissing)
- end
-
- it "only allows certain `types`" do
- delete :destroy_user_image,
- params: { username: user.username, type: 'wat' },
- format: :json
- expect(response.status).to eq(400)
- end
-
- it 'can clear the profile background' do
- delete :destroy_user_image, params: {
- type: 'profile_background', username: user.username
- }, format: :json
-
- 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
- delete :destroy, params: { username: 'nobody' }, format: :json
- expect(response.status).to eq(403)
- 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
- delete :destroy, params: { username: user.username }, format: :json
- 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
- delete :destroy, params: { username: Fabricate(:user).username }, format: :json
- 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)
- delete :destroy, params: { username: user.username }, format: :json
- 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, params: { path: "wat" }, format: :json
- 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, params: { path: "wat/..password.txt" }, format: :json
- expect(response).not_to be_redirect
- end
-
- it "will redirect to an valid path" do
- get :my_redirect, params: { path: "preferences" }, format: :json
- expect(response).to be_redirect
- end
-
- it "permits forward slashes" do
- get :my_redirect, params: { path: "activity/posts" }, format: :json
- expect(response).to be_redirect
- end
- end
- end
-
- describe '.check_emails' do
-
- it 'raises an error when not logged in' do
- put :check_emails, params: { username: 'zogstrip' }, format: :json
- expect(response.status).to eq(403)
- 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)
-
- put :check_emails,
- params: { username: Fabricate(:user).username },
- format: :json
-
- 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)
-
- put :check_emails,
- params: { username: Fabricate(:user).username },
- format: :json
-
- 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)
-
- put :check_emails, params: {
- username: inactive_user.username
- }, format: :json
-
- 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
- get :is_local_username, params: {
- username: user.username
- }, format: :json
-
- expect(response).to be_success
- json = JSON.parse(response.body)
- expect(json["valid"][0]).to eq(user.username)
- end
-
- it "finds the group" do
- get :is_local_username, params: {
- username: group.name
- }, format: :json
-
- 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
- get :is_local_username, params: {
- usernames: [user.username, "system"]
- }, format: :json
-
- 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)
-
- get :is_local_username, params: {
- usernames: [staged.username]
- }, format: :json
-
- 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)
-
- get :is_local_username, params: {
- usernames: [user.username], topic_id: topic.id
- }, format: :json
-
- 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)
-
- get :is_local_username, params: {
- usernames: [user.username], topic_id: topic.id
- }, format: :json
-
- 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)
-
- get :is_local_username, params: {
- usernames: [user.username], topic_id: private_topic.id
- }, format: :json
-
- 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)
-
- get :is_local_username, params: {
- usernames: [allowed_user.username], topic_id: private_topic.id
- }, format: :json
-
- 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
- get :topic_tracking_state, params: { username: user.username }, format: :json
- expect(response.status).to eq(403)
- end
- end
-
- context 'logged on' do
- it "detects new topic" do
- log_in_user(user)
-
- topic = Fabricate(:topic)
- get :topic_tracking_state, params: { 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)
-
- get :summary, params: { username: user.username_lower }, format: :json
- 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(0)
- end
- end
-
- describe ".confirm_admin" do
- it "fails without a valid token" do
- expect {
- get :confirm_admin, params: { token: 'invalid-token' }, format: :json
- }.to raise_error(ActionController::UrlGenerationError)
- end
-
- it "fails with a missing token" do
- get :confirm_admin, params: { token: 'a0a0a0a0a0' }, format: :json
- expect(response).to_not be_success
- end
-
- it "succeeds with a valid code as anonymous" do
- user = Fabricate(:user)
- ac = AdminConfirmation.new(user, Fabricate(:admin))
- ac.create_confirmation
- get :confirm_admin, params: { token: ac.token }
- expect(response).to be_success
-
- user.reload
- expect(user.admin?).to eq(false)
- end
-
- it "succeeds with a valid code when logged in as that user" do
- admin = log_in(:admin)
- user = Fabricate(:user)
-
- ac = AdminConfirmation.new(user, admin)
- ac.create_confirmation
- get :confirm_admin, params: { token: ac.token }
- expect(response).to be_success
-
- user.reload
- expect(user.admin?).to eq(false)
- end
-
- it "fails if you're logged in as a different account" do
- log_in(:admin)
- user = Fabricate(:user)
-
- ac = AdminConfirmation.new(user, Fabricate(:admin))
- ac.create_confirmation
- get :confirm_admin, params: { token: ac.token }, format: :json
- expect(response).to_not be_success
-
- user.reload
- expect(user.admin?).to eq(false)
- end
-
- describe "post" do
- it "gives the user admin access when POSTed" do
- user = Fabricate(:user)
- ac = AdminConfirmation.new(user, Fabricate(:admin))
- ac.create_confirmation
- post :confirm_admin, params: { token: ac.token }
- expect(response).to be_success
-
- user.reload
- expect(user.admin?).to eq(true)
- end
- end
-
- end
-
- describe '.update_activation_email' do
-
- context "with a session variable" do
-
- it "raises an error with an invalid session value" do
- session[SessionController::ACTIVATE_USER_KEY] = 1234
-
- put :update_activation_email, params: {
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error for an active user" do
- user = Fabricate(:walter_white)
- session[SessionController::ACTIVATE_USER_KEY] = user.id
-
- put :update_activation_email, params: {
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error when logged in" do
- moderator = log_in(:moderator)
- session[SessionController::ACTIVATE_USER_KEY] = moderator.id
-
- put :update_activation_email, params: {
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error when the new email is taken" do
- active_user = Fabricate(:user)
- user = Fabricate(:inactive_user)
- session[SessionController::ACTIVATE_USER_KEY] = user.id
-
- put :update_activation_email, params: {
- email: active_user.email
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error when the email is blacklisted" do
- user = Fabricate(:inactive_user)
- SiteSetting.email_domains_blacklist = 'example.com'
- session[SessionController::ACTIVATE_USER_KEY] = user.id
- put :update_activation_email, params: { email: 'test@example.com' }, format: :json
- expect(response).to_not be_success
- end
-
- it "can be updated" do
- user = Fabricate(:inactive_user)
- token = user.email_tokens.first
-
- session[SessionController::ACTIVATE_USER_KEY] = user.id
-
- put :update_activation_email, params: {
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to be_success
-
- user.reload
- expect(user.email).to eq('updatedemail@example.com')
- expect(user.email_tokens.where(email: 'updatedemail@example.com', expired: false)).to be_present
-
- token.reload
- expect(token.expired?).to eq(true)
- end
- end
-
- context "with a username and password" do
- it "raises an error with an invalid username" do
- put :update_activation_email, params: {
- username: 'eviltrout',
- password: 'invalid-password',
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error with an invalid password" do
- put :update_activation_email, params: {
- username: Fabricate(:inactive_user).username,
- password: 'invalid-password',
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error for an active user" do
- put :update_activation_email, params: {
- username: Fabricate(:walter_white).username,
- password: 'letscook',
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error when logged in" do
- log_in(:moderator)
-
- put :update_activation_email, params: {
- username: Fabricate(:inactive_user).username,
- password: 'qwerqwer123',
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "raises an error when the new email is taken" do
- user = Fabricate(:user)
-
- put :update_activation_email, params: {
- username: Fabricate(:inactive_user).username,
- password: 'qwerqwer123',
- email: user.email
- }, format: :json
-
- expect(response).to_not be_success
- end
-
- it "can be updated" do
- user = Fabricate(:inactive_user)
- token = user.email_tokens.first
-
- put :update_activation_email, params: {
- username: user.username,
- password: 'qwerqwer123',
- email: 'updatedemail@example.com'
- }, format: :json
-
- expect(response).to be_success
-
- user.reload
- expect(user.email).to eq('updatedemail@example.com')
- expect(user.email_tokens.where(email: 'updatedemail@example.com', expired: false)).to be_present
-
- token.reload
- expect(token.expired?).to eq(true)
- end
- end
- end
-end
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index 6f8be029cf7..8414e90a0d6 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -1,19 +1,978 @@
require 'rails_helper'
-RSpec.describe UsersController do
+describe UsersController do
let(:user) { Fabricate(:user) }
- def honeypot_magic(params)
- get '/u/hp.json'
- json = JSON.parse(response.body)
- params[:password_confirmation] = json["value"]
- params[:challenge] = json["challenge"].reverse
- params
+ describe '#activate_account' do
+ let(:token) { "asdfasdf" }
+ before do
+ UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(false)
+ end
+
+ context 'invalid token' do
+ it 'return success' do
+ put "/u/activate-account/#{token}"
+ 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("#{token}").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 "/u/activate-account/#{token}"
+ 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 "/u/activate-account/#{token}"
+ 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 "/u/activate-account/#{token}"
+ 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("#{token}").returns(user)
+ end
+
+ it 'correctly logs on user' do
+ events = DiscourseEvent.track_events do
+ put "/u/activate-account/#{token}"
+ end
+
+ expect(events.map { |event| event[:event_name] }).to include(
+ :user_logged_in, :user_first_logged_in
+ )
+
+ expect(response).to be_success
+ expect(flash[:error]).to be_blank
+ expect(session[:current_user_id]).to be_present
+
+ expect(response).to be_success
+
+ expect(CGI.unescapeHTML(response.body))
+ .to_not include(I18n.t('activation.approval_required'))
+ end
+ end
+
+ context 'user is not approved' do
+ before do
+ SiteSetting.must_approve_users = true
+ EmailToken.expects(:confirm).with("#{token}").returns(user)
+ put "/u/activate-account/#{token}"
+ end
+
+ it 'should return the right response' do
+ expect(response).to be_success
+
+ expect(CGI.unescapeHTML(response.body))
+ .to include(I18n.t('activation.approval_required'))
+
+ expect(response.body).to_not have_tag(:script, with: {
+ src: '/assets/application.js'
+ })
+
+ expect(flash[:error]).to be_blank
+ expect(session[:current_user_id]).to be_blank
+ end
+ end
+ end
+ end
+
+ describe '#perform_account_activation' do
+ describe 'when cookies contains a destination URL' do
+ let(:token) { 'asdadwewq' }
+ let(:user) { Fabricate(:user) }
+
+ before do
+ UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(false)
+ EmailToken.expects(:confirm).with(token).returns(user)
+ end
+
+ it 'should redirect to the URL' do
+ destination_url = 'http://thisisasite.com/somepath'
+ cookies[:destination_url] = destination_url
+
+ put "/u/activate-account/#{token}"
+
+ expect(response).to redirect_to(destination_url)
+ end
+ end
+ end
+
+ describe '#password_reset' do
+ let(:user) { Fabricate(:user) }
+ let(:token) { SecureRandom.hex }
+
+ context "you can view it even if login is required" do
+ it "returns success" do
+ SiteSetting.login_required = true
+ get "/u/password-reset/#{token}"
+ expect(response).to be_success
+ end
+ end
+
+ context 'missing token' do
+ before do
+ get "/u/password-reset/#{token}"
+ end
+
+ it 'disallows login' do
+ expect(response).to be_success
+
+ expect(CGI.unescapeHTML(response.body))
+ .to include(I18n.t('password_reset.no_token'))
+
+ expect(response.body).to_not have_tag(:script, with: {
+ src: '/assets/application.js'
+ })
+
+ expect(session[:current_user_id]).to be_blank
+ end
+ end
+
+ context 'invalid token' do
+ it 'disallows login' do
+ get "/u/password-reset/ev!l_trout@!"
+
+ expect(response).to be_success
+
+ expect(CGI.unescapeHTML(response.body))
+ .to include(I18n.t('password_reset.no_token'))
+
+ expect(response.body).to_not have_tag(:script, with: {
+ src: '/assets/application.js'
+ })
+
+ expect(session[:current_user_id]).to be_blank
+ end
+
+ it "responds with proper error message" do
+ put "/u/password-reset/evil_trout!.json", params: { password: "awesomeSecretPassword" }
+
+ expect(response).to be_success
+ expect(JSON.parse(response.body)["message"]).to eq(I18n.t('password_reset.no_token'))
+ expect(session[:current_user_id]).to be_blank
+ end
+ end
+
+ context 'valid token' do
+ context 'when rendered' do
+ it 'renders referrer never on get requests' do
+ user = Fabricate(:user)
+ token = user.email_tokens.create(email: user.email).token
+ get "/u/password-reset/#{token}"
+
+ expect(response.body).to include('')
+ 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 "/u/password-reset/#{token}"
+
+ events = DiscourseEvent.track_events do
+ put "/u/password-reset/#{token}", params: { password: 'hg9ow8yhg98o' }
+ end
+
+ expect(events.map { |event| event[:event_name] }).to include(
+ :user_logged_in, :user_first_logged_in
+ )
+
+ expect(response).to be_success
+ expect(response.body).to include('{"is_developer":false,"admin":false,"second_factor_required":false}')
+
+ 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 "/u/password-reset/#{token}"
+
+ put "/u/password-reset/#{token}", params: { password: 'hg9ow8yHG32O' }
+
+ put "/u/password-reset/#{token}", params: { password: 'test123987AsdfXYZ' }
+
+ user.reload
+ expect(user.confirm_password?('hg9ow8yHG32O')).to eq(true)
+
+ # logged in now
+ expect(user.user_auth_tokens.count).to eq(1)
+ end
+
+ it "doesn't redirect to wizard on get" do
+ user = Fabricate(:admin)
+ UserAuthToken.generate!(user_id: user.id)
+
+ token = user.email_tokens.create(email: user.email).token
+ get "/u/password-reset/#{token}.json"
+ expect(response).not_to redirect_to(wizard_path)
+ end
+
+ it "redirects to the wizard if you're the first admin" do
+ user = Fabricate(:admin)
+ UserAuthToken.generate!(user_id: user.id)
+
+ token = user.email_tokens.create(email: user.email).token
+ get "/u/password-reset/#{token}"
+
+ put "/u/password-reset/#{token}", params: { password: 'hg9ow8yhg98oadminlonger' }
+
+ expect(response).to redirect_to(wizard_path)
+ 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 "/u/password-reset/#{email_token.token}.json"
+
+ email_token.reload
+
+ expect(email_token.confirmed).to eq(false)
+ expect(UserAuthToken.where(id: user_token.id).count).to eq(1)
+ end
+
+ context '2 factor authentication required' do
+ let!(:second_factor) { Fabricate(:user_second_factor, user: user) }
+
+ it 'does not change with an invalid token' do
+ token = user.email_tokens.create!(email: user.email).token
+
+ get "/u/password-reset/#{token}"
+
+ expect(response.body).to include('{"is_developer":false,"admin":false,"second_factor_required":true}')
+
+ put "/u/password-reset/#{token}", params: { password: 'hg9ow8yHG32O', second_factor_token: '000000' }
+
+ expect(response.body).to include(I18n.t("login.invalid_second_factor_code"))
+
+ user.reload
+ expect(user.confirm_password?('hg9ow8yHG32O')).not_to eq(true)
+ expect(user.user_auth_tokens.count).not_to eq(1)
+ end
+
+ it 'changes password with valid 2-factor tokens' do
+ token = user.email_tokens.create(email: user.email).token
+
+ get "/u/password-reset/#{token}"
+
+ put "/u/password-reset/#{token}", params: {
+ password: 'hg9ow8yHG32O',
+ second_factor_token: ROTP::TOTP.new(second_factor.data).now
+ }
+
+ user.reload
+ expect(user.confirm_password?('hg9ow8yHG32O')).to eq(true)
+ expect(user.user_auth_tokens.count).to eq(1)
+ end
+ 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 "/u/password-reset/#{token}.json", params: { password: '' }
+
+ expect(response).to be_success
+ expect(JSON.parse(response.body)["errors"]).to be_present
+ expect(session[:current_user_id]).to be_blank
+ end
+
+ it "fails when the password is too long" do
+ put "/u/password-reset/#{token}.json", params: { password: ('x' * (User.max_password_length + 1)) }
+
+ expect(response).to be_success
+ expect(JSON.parse(response.body)["errors"]).to be_present
+ expect(session[:current_user_id]).to be_blank
+ end
+
+ it "logs in the user" do
+ put "/u/password-reset/#{token}.json", params: { password: 'ksjafh928r' }
+
+ expect(response).to be_success
+ expect(JSON.parse(response.body)["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.must_approve_users = true
+ put "/u/password-reset/#{token}.json", params: { password: 'ksjafh928r' }
+
+ expect(JSON.parse(response.body)["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 "/u/confirm-email-token/#{SecureRandom.hex}.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 "/u/confirm-email-token/#{email_token.token}.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 "/u/admin-login", params: { email: admin.email }
+ end
+ end
+
+ context 'when email is incorrect' do
+ it 'should return the right response' do
+ put "/u/admin-login", params: { email: 'random' }
+
+ expect(response.status).to eq(200)
+
+ response_body = response.body
+
+ expect(response_body).to match(I18n.t("admin_login.errors.unknown_email_address"))
+ expect(response_body).to_not match(I18n.t("login.second_factor_description"))
+ end
+ end
+
+ context 'logs in admin' do
+ it 'does not log in admin with invalid token' do
+ SiteSetting.sso_url = "https://www.example.com/sso"
+ SiteSetting.enable_sso = true
+ get "/u/admin-login/invalid"
+ expect(session[:current_user_id]).to be_blank
+ end
+
+ context 'valid token' do
+ it 'does log in admin with SSO disabled' do
+ SiteSetting.enable_sso = false
+ token = admin.email_tokens.create(email: admin.email).token
+
+ get "/u/admin-login/#{token}"
+ expect(response).to redirect_to('/')
+ expect(session[:current_user_id]).to eq(admin.id)
+ end
+
+ it 'logs in admin with SSO enabled' do
+ SiteSetting.sso_url = "https://www.example.com/sso"
+ SiteSetting.enable_sso = true
+ token = admin.email_tokens.create(email: admin.email).token
+
+ get "/u/admin-login/#{token}"
+ expect(response).to redirect_to('/')
+ expect(session[:current_user_id]).to eq(admin.id)
+ end
+ end
+
+ describe 'when 2 factor authentication is enabled' do
+ let(:second_factor) { Fabricate(:user_second_factor, user: admin) }
+ let(:email_token) { Fabricate(:email_token, user: admin) }
+
+ it 'does not log in when token required' do
+ second_factor
+ get "/u/admin-login/#{email_token.token}"
+ expect(response).not_to redirect_to('/')
+ expect(session[:current_user_id]).not_to eq(admin.id)
+ expect(response.body).to include(I18n.t('login.second_factor_description'));
+ end
+
+ describe 'invalid 2 factor token' do
+ it 'should display the right error' do
+ second_factor
+
+ put "/u/admin-login/#{email_token.token}", params: { second_factor_token: '13213' }
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include(I18n.t('login.second_factor_description'));
+ expect(response.body).to include(I18n.t('login.invalid_second_factor_code'));
+ end
+ end
+
+ it 'logs in when a valid 2-factor token is given' do
+ put "/u/admin-login/#{email_token.token}", params: { second_factor_token: ROTP::TOTP.new(second_factor.data).now }
+
+ expect(response).to redirect_to('/')
+ expect(session[:current_user_id]).to eq(admin.id)
+ end
+ end
+ end
+ end
+
+ describe '#toggle_anon' do
+ it 'allows you to toggle anon if enabled' do
+ SiteSetting.allow_anonymous_posting = true
+
+ user = sign_in(Fabricate(:user))
+ user.trust_level = 1
+ user.save!
+
+ post "/u/toggle-anon.json"
+ expect(response).to be_success
+ expect(session[:current_user_id]).to eq(AnonymousShadowCreator.get(user).id)
+
+ post "/u/toggle-anon.json"
+ expect(response).to be_success
+ expect(session[:current_user_id]).to eq(user.id)
+ end
end
describe '#create' do
+ def honeypot_magic(params)
+ get '/u/hp.json'
+ json = JSON.parse(response.body)
+ params[:password_confirmation] = json["value"]
+ params[:challenge] = json["challenge"].reverse
+ params
+ end
+
+ before do
+ UsersController.any_instance.stubs(:honeypot_value).returns(nil)
+ UsersController.any_instance.stubs(:challenge_value).returns(nil)
+ SiteSetting.allow_new_registrations = 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
+ post "/u.json", params: post_user_params
+ end
+
+ context 'when email params is missing' do
+ it 'should raise the right error' do
+ post "/u.json", params: {
+ name: @user.name,
+ username: @user.username,
+ passsword: 'tesing12352343'
+ }
+ expect(response.status).to eq(400)
+ end
+ end
+
+ context 'when creating a user' do
+ it 'sets the user locale to I18n.locale' do
+ SiteSetting.default_locale = '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.enable_local_logins = false
+ post_user
+
+ expect(response.status).to eq(500)
+ end
+
+ it 'returns an error when new registrations are disabled' do
+ SiteSetting.allow_new_registrations = 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
+ expect(session[SessionController::ACTIVATE_USER_KEY]).to be_present
+ end
+
+ context "`must approve users` site setting is enabled" do
+ before { SiteSetting.must_approve_users = true }
+
+ 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
+ expect(session[SessionController::ACTIVATE_USER_KEY]).to be_present
+ end
+ end
+
+ context 'users already exists with given email' do
+ let!(:existing) { Fabricate(:user, email: post_user_params[:email]) }
+
+ it 'returns an error if hide_email_address_taken is disabled' do
+ SiteSetting.hide_email_address_taken = false
+ post_user
+ json = JSON.parse(response.body)
+ expect(json['success']).to eq(false)
+ expect(json['message']).to be_present
+ end
+
+ it 'returns success if hide_email_address_taken is enabled' do
+ SiteSetting.hide_email_address_taken = true
+ expect {
+ post_user
+ }.to_not change { User.count }
+ json = JSON.parse(response.body)
+ expect(json['active']).to be_falsey
+ expect(session["user_created_message"]).to be_present
+ end
+ end
+ end
+
+ context "creating as active" do
+ it "won't create the user as active" do
+ post "/u.json", params: 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
+ post "/u.json",
+ params: 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(:admin) { Fabricate(:admin) }
+ let(:api_key) { Fabricate(:api_key, user: admin) }
+
+ it "creates the user as active with a regular key" do
+ SiteSetting.queue_jobs = true
+ SiteSetting.send_welcome_message = true
+ SiteSetting.must_approve_users = true
+
+ Sidekiq::Client.expects(:enqueue).never
+
+ post "/u.json", params: post_user_params.merge(approved: true, active: true, api_key: api_key.key)
+
+ json = JSON.parse(response.body)
+
+ new_user = User.find(json["user_id"])
+
+ expect(json['active']).to be_truthy
+
+ expect(new_user.active).to eq(true)
+ expect(new_user.approved).to eq(true)
+ expect(new_user.approved_by_id).to eq(admin.id)
+ expect(new_user.approved_at).to_not eq(nil)
+ end
+
+ it "won't create the developer as active" do
+ UsernameCheckerService.expects(:is_developer?).returns(true)
+
+ post "/u.json", params: 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
+ post "/u.json", params: 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
+ post "/u.json", params: 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
+ post "/u.json", params: 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)
+ post "/u.json", params: 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
+ expect(session[SessionController::ACTIVATE_USER_KEY]).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.allow_new_registrations = 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
+ let(:user) { Fabricate(:user) }
+ before do
+ OmniAuth.config.mock_auth[:twitter] = OmniAuth::AuthHash.new(
+ provider: 'twitter',
+ uid: '123545',
+ info: OmniAuth::AuthHash::InfoHash.new(
+ email: "osama@mail.com",
+ nickname: "testosama"
+ )
+ )
+
+ Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:twitter]
+ SiteSetting.enable_twitter_logins = true
+ get "/auth/twitter/callback.json"
+ end
+
+ it 'should create twitter user info if required' do
+ post "/u.json", params: {
+ name: "Test Osama",
+ username: "testosama",
+ password: "strongpassword",
+ email: "osama@mail.com"
+ }
+
+ expect(TwitterUserInfo.count).to eq(1)
+ end
+
+ it "returns an error when email has been changed from the validated email address" do
+ post "/u.json", params: {
+ name: "Test Osama",
+ username: "testosama",
+ password: "strongpassword",
+ email: "unvalidatedemail@mail.com"
+ }
+
+ json = JSON.parse(response.body)
+ expect(json['success']).to eq(false)
+ expect(json['message']).to be_present
+ end
+
+ it "will create the user successfully if email validation is required" do
+ post "/u.json", params: {
+ name: "Test Osama",
+ username: "testosama",
+ password: "strongpassword",
+ email: "osama@mail.com"
+ }
+
+ json = JSON.parse(response.body)
+ expect(json['success']).to eq(true)
+ end
+ end
+ end
+
+ context 'after success' do
+ before { post_user }
+
+ it 'should succeed' do
+ expect(response).to be_success
+ #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 {
+ post "/u.json", params: create_params
+ }.to_not change { User.count }
+ end
+
+ it 'should not send an email' do
+ User.any_instance.expects(:enqueue_welcome_message).never
+ post "/u.json", params: create_params
+ end
+
+ it 'should say it was successful' do
+ post "/u.json", params: 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
+ expect(session[SessionController::ACTIVATE_USER_KEY]).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.invite_only = 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 { post "/u.json", params: create_params }.to_not change { User.count }
+ end
+
+ it 'should report failed' do
+ post "/u.json", params: 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
+ expect(session[SessionController::ACTIVATE_USER_KEY]).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
+ before { User.any_instance.stubs(:save).raises(ActiveRecord::StatementInvalid.new('Oh no')) }
+
+ let(:create_params) {
+ { name: @user.name, username: @user.username,
+ password: "strongpassword", email: @user.email }
+ }
+
+ include_examples 'failed signup'
+ 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: 'suChS3cuRi7y',
+ 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
+ post "/u.json", params: create_params
+ expect(response).to be_success
+ inserted = User.find_by_email(@user.email)
+ 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'
+ post "/u.json", params: create_params.merge(create_params)
+ expect(response).to be_success
+ inserted = User.find_by_email(@user.email)
+ 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)
+ post "/u.json", params: create_params.merge(create_params)
+ expect(response).to be_success
+ inserted = User.find_by_email(@user.email)
+
+ 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: 'suChS3cuRi7y',
+ username: @user.username,
+ email: @user.email,
+ } }
+
+ it "should succeed" do
+ post "/u.json", params: create_params
+ expect(response).to be_success
+ inserted = User.find_by_email(@user.email)
+ 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
+ before do
+ UsersController.any_instance.stubs(:honeypot_value).returns("abc")
+ UsersController.any_instance.stubs(:challenge_value).returns("efg")
+ end
+
let!(:staged) { Fabricate(:staged, email: "staged@account.com", active: true) }
it "succeeds" do
@@ -42,10 +1001,1402 @@ RSpec.describe UsersController do
expect(response.status).not_to eq(200)
end
end
+ end
+ describe '#username' do
+ it 'raises an error when not logged in' do
+ put "/u/somename/preferences/username.json"
+ expect(response.status).to eq(403)
+ 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
+ sign_in(user)
+ end
+
+ it 'raises an error without a new_username param' do
+ put "/u/#{user.username}/preferences/username.json", params: { username: user.username }
+ expect(response).not_to be_success
+ 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)
+
+ put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username }
+
+ expect(response).to be_forbidden
+ expect(user.reload.username).to eq(old_username)
+ end
+
+ it 'raises an error when change_username fails' do
+ put "/u/#{user.username}/preferences/username.json", params: { new_username: '@' }
+
+ expect(response).to_not be_success
+
+ body = JSON.parse(response.body)
+
+ expect(body['errors'].first).to include(I18n.t(
+ 'user.username.short', min: User.username_length.begin
+ ))
+
+ expect(user.reload.username).to eq(old_username)
+ end
+
+ it 'should succeed in normal circumstances' do
+ put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username }
+
+ expect(response).to be_success
+ expect(user.reload.username).to eq(new_username)
+ end
+
+ it 'should fail if the user is old' do
+ # Older than the change period and >1 post
+ user.created_at = Time.now - (SiteSetting.username_change_period + 1).days
+ PostCreator.new(user,
+ title: 'This is a test topic',
+ raw: 'This is a test this is a test'
+ ).create
+
+ put "/u/#{user.username}/preferences/username.json", params: { 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)
+ sign_in(acting_user)
+
+ put "/u/#{user.username}/preferences/username.json", params: { 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
+ put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username }
+
+ expect(::JSON.parse(response.body)['username']).to eq(new_username)
+ end
+ end
+ end
+
+ describe '#check_username' do
+ it 'raises an error without any parameters' do
+ get "/u/check_username.json"
+ expect(response).not_to be_success
+ 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
+ get "/u/check_username.json", params: { email: 'dood@example.com' }
+ expect(response).to be_success
+ end
+
+ context 'username is available' do
+ before do
+ get "/u/check_username.json", params: { username: 'BruceWayne' }
+ end
+ include_examples 'when username is available'
+ end
+
+ context 'username is unavailable' do
+ let!(:user) { Fabricate(:user) }
+ before do
+ get "/u/check_username.json", params: { 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
+ get "/u/check_username.json", params: { 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
+ get "/u/check_username.json", params: { 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
+ sign_in(user)
+
+ get "/u/check_username.json", params: { 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
+ sign_in(Fabricate(:user))
+
+ get "/u/check_username.json", params: { 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
+ sign_in(Fabricate(:admin))
+
+ get "/u/check_username.json", params: { 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)
+ get "/u/#{user.username}/invited.json", params: { 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
+ )
+
+ get "/u/#{inviter.username}/invited.json", params: { 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')
+ )
+
+ get "/u/#{inviter.username}/invited.json", params: { 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)
+
+ get "/u/#{user.username}/invited/pending.json"
+
+ 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)
+
+ get "/u/#{inviter.username}/invited.json"
+
+ 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
+ inviter = Fabricate(:user)
+ invite = Fabricate(:invite, invited_by: inviter)
+ sign_in(inviter)
+
+ get "/u/#{inviter.username}/invited/pending.json"
+
+ 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 = sign_in(Fabricate(:user))
+ 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
+
+ get "/u/#{inviter.username}/invited/pending.json"
+
+ json = JSON.parse(response.body)['invites']
+ expect(json).to be_empty
+ end
+ end
+ end
+
+ context 'with redeemed invites' do
+ it 'returns invites' do
+ _user = sign_in(Fabricate(:user))
+ inviter = Fabricate(:user)
+ invitee = Fabricate(:user)
+ invite = Fabricate(:invite, invited_by: inviter, user: invitee)
+
+ get "/u/#{inviter.username}/invited.json"
+
+ 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
+ put "/u/guest.json"
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context "when username contains a period" do
+ before do
+ sign_in(user)
+ end
+ let(:user) { Fabricate(:user) }
+
+ it "should be able to update a user" do
+ put "/u/#{user.username}.json", params: { name: 'test.test' }
+
+ expect(response).to be_success
+ expect(user.reload.name).to eq('test.test')
+ end
+
+ it "should be able to update a user" do
+ put "/u/#{user.username}.json", params: { name: 'testing123' }
+
+ expect(response).to be_success
+ expect(user.reload.name).to eq('testing123')
+ end
+ end
+
+ context "as a staff user" do
+ context "uneditable field" do
+ let!(:user_field) { Fabricate(:user_field, editable: false) }
+
+ it "allows staff to edit the field" do
+ sign_in(Fabricate(:admin))
+ user = Fabricate(:user)
+ put "/u/#{user.username}.json", params: {
+ name: 'Jim Tom',
+ title: "foobar",
+ user_fields: { user_field.id.to_s => 'happy' }
+ }
+
+ expect(response).to be_success
+
+ user.reload
+
+ expect(user.user_fields[user_field.id.to_s]).to eq('happy')
+ expect(user.title).to eq("foobar")
+ end
+ end
+ end
+
+ context 'with authenticated user' do
+ context 'with permission to update' do
+ let!(:user) { sign_in(Fabricate(:user)) }
+
+ it 'allows the update' do
+ user2 = Fabricate(:user)
+ user3 = Fabricate(:user)
+ tags = [Fabricate(:tag), Fabricate(:tag)]
+
+ put "/u/#{user.username}.json", params: {
+ name: 'Jim Tom',
+ custom_fields: { test: :it },
+ muted_usernames: "#{user2.username},#{user3.username}",
+ watched_tags: "#{tags[0].name},#{tags[1].name}"
+ }
+
+ 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
+ expect(TagUser.where(
+ user: user,
+ notification_level: TagUser.notification_levels[:watching]
+ ).pluck(:tag_id)).to contain_exactly(tags[0].id, tags[1].id)
+
+ theme = Theme.create(name: "test", user_selectable: true, user_id: -1)
+
+ put "/u/#{user.username}.json", params: {
+ muted_usernames: "",
+ theme_key: theme.key,
+ email_direct: false
+ }
+
+ user.reload
+
+ expect(user.muted_users.pluck(:username).sort).to be_empty
+ expect(user.user_option.theme_key).to eq(theme.key)
+ expect(user.user_option.email_direct).to eq(false)
+ 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 "/u/#{user.username}.json", params: { 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 "/u/#{user.username}.json", params: { 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 "/u/#{user.username}.json", params: { 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 "/u/#{user.username}.json", params: { 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
+
+ it "should retain existing user fields" do
+ put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy', optional_field.id.to_s => 'feet' } }
+
+ expect(response).to be_success
+ expect(user.user_fields[user_field.id.to_s]).to eq('happy')
+ expect(user.user_fields[optional_field.id.to_s]).to eq('feet')
+
+ put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'sad' } }
+
+ expect(response).to be_success
+
+ user.reload
+
+ expect(user.user_fields[user_field.id.to_s]).to eq('sad')
+ expect(user.user_fields[optional_field.id.to_s]).to eq('feet')
+ end
+ end
+
+ context "uneditable field" do
+ let!(:user_field) { Fabricate(:user_field, editable: false) }
+
+ it "does not update the user field" do
+ put "/u/#{user.username}.json", params: { 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 "/u/#{user.username}.json"
+
+ 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')
+ sign_in(Fabricate(:user))
+ #Guardian.any_instance.expects(:can_edit?).with(user).returns(false)
+
+ put "/u/#{user.username}.json", params: { name: 'Jim Tom' }
+
+ expect(response).to be_forbidden
+ expect(user.reload.name).not_to eq 'Jim Tom'
+ end
+ end
+ 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
+ sign_in(user)
+
+ put "/u/#{user.username}/preferences/badge_title.json", params: { user_badge_id: user_badge.id }
+
+ expect(user.reload.title).not_to eq(badge.display_name)
+ badge.update_attributes allow_title: true
+
+ put "/u/#{user.username}/preferences/badge_title.json", params: { user_badge_id: user_badge.id }
+
+ expect(user.reload.title).to eq(badge.display_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
+
+ context "with overrided name" do
+ let(:badge) { Fabricate(:badge, name: 'Demogorgon', allow_title: true) }
+ let(:user_badge) { BadgeGranter.grant(badge, user) }
+
+ before do
+ TranslationOverride.upsert!('en', 'badges.demogorgon.name', 'Boss')
+ end
+
+ after do
+ TranslationOverride.revert!('en', ['badges.demogorgon.name'])
+ end
+
+ it "uses the badge display name as user title" do
+ sign_in(user)
+
+ put "/u/#{user.username}/preferences/badge_title.json", params: { user_badge_id: user_badge.id }
+ expect(user.reload.title).to eq(badge.display_name)
+ end
+ end
+ end
+
+ describe '#send_activation_email' do
+ before do
+ UsersController.any_instance.stubs(:honeypot_value).returns(nil)
+ UsersController.any_instance.stubs(:challenge_value).returns(nil)
+ end
+
+ let(:post_user) do
+ post "/u.json", params: {
+ username: "osamatest",
+ password: "strongpassword",
+ email: "dsdsds@sasa.com"
+ }
+ User.where(username: "osamatest").first
+ end
+
+ context 'for an existing user' do
+ context 'for an activated account with email confirmed' do
+ it 'fails' do
+ user = post_user
+ email_token = user.email_tokens.create(email: user.email).token
+ EmailToken.confirm(email_token)
+
+ post "/u/action/send_activation_email.json", params: { username: user.username }
+
+ expect(response.status).to eq(409)
+ expect(JSON.parse(response.body)['errors']).to include(I18n.t(
+ 'activation.activated'
+ ))
+ expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
+ end
+ end
+
+ context 'for an activated account with unconfirmed email' do
+ it 'should send an email' do
+ user = post_user
+ user.update(active: true)
+ user.save!
+ user.email_tokens.create(email: user.email)
+ Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup, to_address: user.email))
+
+ post "/u/action/send_activation_email.json", params: {
+ username: user.username
+ }
+
+ expect(response.status).to eq(200)
+
+ expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
+ end
+ end
+
+ context "approval is enabled" do
+ before do
+ SiteSetting.must_approve_users = true
+ end
+
+ it "should raise an error" do
+ user = post_user
+ user.update(active: true)
+ user.save!
+ user.email_tokens.create(email: user.email)
+ post "/u/action/send_activation_email.json", params: {
+ username: user.username
+ }
+
+ expect(response.status).to eq(403)
+ end
+ end
+
+ describe 'when user does not have a valid session' do
+ it 'should not be valid' do
+ user = Fabricate(:user)
+ post "/u/action/send_activation_email.json", params: {
+ username: user.username
+ }
+ expect(response.status).to eq(403)
+ end
+
+ it 'should allow staff regardless' do
+ sign_in(Fabricate(:admin))
+ user = Fabricate(:user, active: false)
+ post "/u/action/send_activation_email.json", params: {
+ username: user.username
+ }
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context 'with a valid email_token' do
+ it 'should send the activation email' do
+ user = post_user
+ Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
+ post "/u/action/send_activation_email.json", params: {
+ username: user.username
+ }
+ expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
+ end
+ end
+
+ context 'without an existing email_token' do
+ let(:user) { post_user }
+ before do
+ user.email_tokens.each { |t| t.destroy }
+ user.reload
+ end
+
+ it 'should generate a new token' do
+ expect {
+ post "/u/action/send_activation_email.json", params: { username: user.username }
+ }.to change { user.reload.email_tokens.count }.by(1)
+ end
+
+ it 'should send an email' do
+ Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup))
+ post "/u/action/send_activation_email.json", params: { username: user.username }
+ expect(session[SessionController::ACTIVATE_USER_KEY]).to eq(nil)
+ end
+ end
+ end
+
+ context 'when username does not exist' do
+ it 'should not send an email' do
+ Jobs.expects(:enqueue).never
+
+ post "/u/action/send_activation_email.json", params: { username: 'nopenopenopenope' }
+ end
+ end
+ end
+
+ describe '#pick_avatar' do
+ it 'raises an error when not logged in' do
+ put "/u/asdf/preferences/avatar/pick.json", params: { avatar_id: 1, type: "custom" }
+ expect(response.status).to eq(403)
+ end
+
+ context 'while logged in' do
+
+ let!(:user) { sign_in(Fabricate(:user)) }
+ let(:upload) { Fabricate(:upload) }
+
+ it "raises an error when you don't have permission to toggle the avatar" do
+ another_user = Fabricate(:user)
+ put "/u/#{another_user.username}/preferences/avatar/pick.json", params: {
+ upload_id: upload.id, type: "custom"
+ }
+
+ expect(response).to be_forbidden
+ end
+
+ it "raises an error when sso_overrides_avatar is disabled" do
+ SiteSetting.sso_overrides_avatar = true
+ put "/u/#{user.username}/preferences/avatar/pick.json", params: {
+ 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.allow_uploaded_avatars = false
+ put "/u/#{user.username}/preferences/avatar/pick.json", params: {
+ upload_id: upload.id, type: "custom"
+ }
+
+ expect(response).to_not be_success
+ end
+
+ it 'can successfully pick the system avatar' do
+ put "/u/#{user.username}/preferences/avatar/pick.json"
+
+ expect(response).to be_success
+ expect(user.reload.uploaded_avatar_id).to eq(nil)
+ end
+
+ it 'can successfully pick a gravatar' do
+ put "/u/#{user.username}/preferences/avatar/pick.json", params: {
+ 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
+ put "/u/#{user.username}/preferences/avatar/pick.json", params: {
+ 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
+ delete "/u/asdf/preferences/user_image.json", params: { type: 'profile_background' }
+ expect(response.status).to eq(403)
+ end
+
+ context 'while logged in' do
+ let(:another_user) { Fabricate(:user) }
+ let(:user) { Fabricate(:user) }
+ before do
+ sign_in(user)
+ end
+
+ it 'raises an error when you don\'t have permission to clear the profile background' do
+ delete "/u/#{another_user.username}/preferences/user_image.json", params: { type: 'profile_background' }
+ expect(response).to be_forbidden
+ end
+
+ it "requires the `type` param" do
+ delete "/u/#{user.username}/preferences/user_image.json"
+ expect(response.status).to eq(400)
+ end
+
+ it "only allows certain `types`" do
+ delete "/u/#{user.username}/preferences/user_image.json", params: { type: 'wat' }
+ expect(response.status).to eq(400)
+ end
+
+ it 'can clear the profile background' do
+ delete "/u/#{user.username}/preferences/user_image.json", params: { type: 'profile_background' }
+
+ 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
+ delete "/u/nobody.json"
+ expect(response.status).to eq(403)
+ end
+
+ context 'while logged in' do
+ let(:user) { Fabricate(:user) }
+ let(:another_user) { Fabricate(:user) }
+ before do
+ sign_in(user)
+ end
+
+ it 'raises an error when you cannot delete your account' do
+ UserDestroyer.any_instance.expects(:destroy).never
+ stat = user.user_stat
+ stat.post_count = 3
+ stat.save!
+ delete "/u/#{user.username}.json"
+ 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
+ delete "/u/#{another_user.username}.json"
+ expect(response).to be_forbidden
+ end
+
+ it "deletes your account when you're allowed to" do
+ UserDestroyer.any_instance.expects(:destroy).with(user, anything).returns(user)
+ delete "/u/#{user.username}.json"
+ expect(response).to be_success
+ end
+ end
+ end
+
+ describe '#my_redirect' do
+ it "redirects if the user is not logged in" do
+ get "/my/wat.json"
+ expect(response).not_to be_success
+ expect(response).to be_redirect
+ end
+
+ context "when the user is logged in" do
+ let!(:user) { sign_in(Fabricate(:user)) }
+
+ it "will not redirect to an invalid path" do
+ get "/my/wat/..password.txt"
+ expect(response).not_to be_redirect
+ end
+
+ it "will redirect to an valid path" do
+ get "/my/preferences.json"
+ expect(response).to be_redirect
+ end
+
+ it "permits forward slashes" do
+ get "/my/activity/posts.json"
+ expect(response).to be_redirect
+ end
+ end
+ end
+
+ describe '#check_emails' do
+ it 'raises an error when not logged in' do
+ get "/u/zogstrip/emails.json"
+ expect(response.status).to eq(403)
+ end
+
+ context 'while logged in' do
+ let(:sign_in_admin) { sign_in(Fabricate(:admin)) }
+
+ it "raises an error when you aren't allowed to check emails" do
+ sign_in(Fabricate(:user))
+ get "/u/#{Fabricate(:user).username}/emails.json"
+ expect(response).to be_forbidden
+ end
+
+ it "returns both email and associated_accounts when you're allowed to see them" do
+ sign_in_admin
+
+ get "/u/#{Fabricate(:user).username}/emails.json"
+
+ 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)
+ sign_in_admin
+
+ get "/u/#{inactive_user.username}/emails.json"
+
+ 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
+ get "/u/is_local_username.json", params: { 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
+ get "/u/is_local_username.json", params: { 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
+ get "/u/is_local_username.json", params: { 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)
+
+ get "/u/is_local_username.json", params: { 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)
+
+ get "/u/is_local_username.json", params: {
+ 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)
+
+ get "/u/is_local_username.json", params: {
+ 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)
+
+ get "/u/is_local_username.json", params: {
+ 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)
+
+ get "/u/is_local_username.json", params: {
+ 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
+ get "/u/#{user.username}/topic-tracking-state.json"
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'logged on' do
+ it "detects new topic" do
+ sign_in(user)
+
+ topic = Fabricate(:topic)
+ get "/u/#{user.username}/topic-tracking-state.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)
+
+ get "/u/#{user.username_lower}/summary.json"
+ 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(0)
+ end
+ end
+
+ describe '#confirm_admin' do
+ it "fails without a valid token" do
+ get "/u/confirm-admin/invalid-token.josn"
+ expect(response).not_to be_success
+ end
+
+ it "fails with a missing token" do
+ get "/u/confirm-admin/a0a0a0a0a0.josn"
+ expect(response).to_not be_success
+ end
+
+ it "succeeds with a valid code as anonymous" do
+ user = Fabricate(:user)
+ ac = AdminConfirmation.new(user, Fabricate(:admin))
+ ac.create_confirmation
+ get "/u/confirm-admin/#{ac.token}.josn"
+ expect(response).to be_success
+
+ user.reload
+ expect(user.admin?).to eq(false)
+ end
+
+ it "succeeds with a valid code when logged in as that user" do
+ admin = sign_in(Fabricate(:admin))
+ user = Fabricate(:user)
+
+ ac = AdminConfirmation.new(user, admin)
+ ac.create_confirmation
+ get "/u/confirm-admin/#{ac.token}.josn", params: { token: ac.token }
+ expect(response).to be_success
+
+ user.reload
+ expect(user.admin?).to eq(false)
+ end
+
+ it "fails if you're logged in as a different account" do
+ sign_in(Fabricate(:admin))
+ user = Fabricate(:user)
+
+ ac = AdminConfirmation.new(user, Fabricate(:admin))
+ ac.create_confirmation
+ get "/u/confirm-admin/#{ac.token}.josn"
+ expect(response).to_not be_success
+
+ user.reload
+ expect(user.admin?).to eq(false)
+ end
+
+ describe "post" do
+ it "gives the user admin access when POSTed" do
+ user = Fabricate(:user)
+ ac = AdminConfirmation.new(user, Fabricate(:admin))
+ ac.create_confirmation
+ post "/u/confirm-admin/#{ac.token}.josn"
+ expect(response).to be_success
+
+ user.reload
+ expect(user.admin?).to eq(true)
+ end
+ end
+ end
+
+ describe '#update_activation_email' do
+ before do
+ UsersController.any_instance.stubs(:honeypot_value).returns(nil)
+ UsersController.any_instance.stubs(:challenge_value).returns(nil)
+ end
+
+ let(:post_user) do
+ post "/u.json", params: {
+ username: "osamatest",
+ password: "strongpassword",
+ email: "osama@example.com"
+ }
+ user = User.where(username: "osamatest").first
+ user.active = false
+ user.save!
+ user
+ end
+
+ context "with a session variable" do
+ it "raises an error with an invalid session value" do
+ post_user
+
+ post "/u.json", params: {
+ username: "osamatest2",
+ password: "strongpassword2",
+ email: "osama22@example.com"
+ }
+ user = User.where(username: "osamatest2").first
+ user.destroy
+
+ put "/u/update-activation-email.json", params: {
+ email: 'osamaupdated@example.com'
+ }
+
+ expect(response.status).to eq(403)
+ end
+
+ it "raises an error for an active user" do
+ user = post_user
+ user.update(active: true)
+ user.save!
+
+ put "/u/update-activation-email.json", params: {
+ email: 'osama@example.com'
+ }
+
+ expect(response.status).to eq(403)
+ end
+
+ it "raises an error when logged in" do
+ moderator = sign_in(Fabricate(:moderator))
+ post_user
+
+ put "/u/update-activation-email.json", params: {
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response.status).to eq(403)
+ end
+
+ it "raises an error when the new email is taken" do
+ active_user = Fabricate(:user)
+ user = post_user
+
+ put "/u/update-activation-email.json", params: {
+ email: active_user.email
+ }
+
+ expect(response.status).to eq(422)
+ end
+
+ it "raises an error when the email is blacklisted" do
+ user = post_user
+ SiteSetting.email_domains_blacklist = 'example.com'
+ put "/u/update-activation-email.json", params: { email: 'test@example.com' }
+ expect(response.status).to eq(422)
+ end
+
+ it "can be updated" do
+ user = post_user
+ token = user.email_tokens.first
+
+ put "/u/update-activation-email.json", params: {
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response).to be_success
+
+ user.reload
+ expect(user.email).to eq('updatedemail@example.com')
+ expect(user.email_tokens.where(email: 'updatedemail@example.com', expired: false)).to be_present
+
+ token.reload
+ expect(token.expired?).to eq(true)
+ end
+ end
+
+ context "with a username and password" do
+ it "raises an error with an invalid username" do
+ put "/u/update-activation-email.json", params: {
+ username: 'eviltrout',
+ password: 'invalid-password',
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response).to_not be_success
+ end
+
+ it "raises an error with an invalid password" do
+ put "/u/update-activation-email.json", params: {
+ username: Fabricate(:inactive_user).username,
+ password: 'invalid-password',
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response).to_not be_success
+ end
+
+ it "raises an error for an active user" do
+ put "/u/update-activation-email.json", params: {
+ username: Fabricate(:walter_white).username,
+ password: 'letscook',
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response).to_not be_success
+ end
+
+ it "raises an error when logged in" do
+ sign_in(Fabricate(:moderator))
+
+ put "/u/update-activation-email.json", params: {
+ username: Fabricate(:inactive_user).username,
+ password: 'qwerqwer123',
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response).to_not be_success
+ end
+
+ it "raises an error when the new email is taken" do
+ user = Fabricate(:user)
+
+ put "/u/update-activation-email.json", params: {
+ username: Fabricate(:inactive_user).username,
+ password: 'qwerqwer123',
+ email: user.email
+ }
+
+ expect(response).to_not be_success
+ end
+
+ it "can be updated" do
+ user = Fabricate(:inactive_user)
+ token = user.email_tokens.first
+
+ put "/u/update-activation-email.json", params: {
+ username: user.username,
+ password: 'qwerqwer123',
+ email: 'updatedemail@example.com'
+ }
+
+ expect(response).to be_success
+
+ user.reload
+ expect(user.email).to eq('updatedemail@example.com')
+ expect(user.email_tokens.where(email: 'updatedemail@example.com', expired: false)).to be_present
+
+ token.reload
+ expect(token.expired?).to eq(true)
+ end
+ end
end
describe '#show' do
+ context "anon" do
+ let(:user) { Discourse.system_user }
+ let(:other_user) { Fabricate(:user) }
+
+ it "returns success" do
+ get "/u/#{user.username}.json"
+ expect(response).to be_success
+ expect(JSON.parse(response.body)["user"]["username"]).to eq(user.username)
+ end
+
+ it "should redirect to login page for anonymous user when profiles are hidden" do
+ SiteSetting.hide_user_profiles_from_public = true
+ get "/u/#{user.username}.json"
+ expect(response).to redirect_to '/login'
+ end
+
+ describe "user profile views" do
+ let(:other_user) { Fabricate(:user) }
+
+ it "should track a user profile view for an anon user" do
+ get "/"
+ UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, nil)
+ get "/u/#{other_user.username}.json"
+ end
+
+ it "skips tracking" do
+ UserProfileView.expects(:add).never
+ get "/u/#{user.username}.json", params: { skip_track_visit: true }
+ end
+ end
+ end
+
+ context "logged in" do
+ before do
+ sign_in(user)
+ end
+
+ let(:user) { Fabricate(:user) }
+
+ it 'returns success' do
+ get "/u/#{user.username}.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
+ get "/u/madeuppity.json"
+ expect(response).not_to be_success
+ end
+
+ it 'returns not found when the user is inactive' do
+ inactive = Fabricate(:user, active: false)
+ get "/u/#{inactive.username}.json"
+ expect(response).not_to be_success
+ end
+
+ it 'returns success when show_inactive_accounts is true and user is logged in' do
+ SiteSetting.show_inactive_accounts = true
+ inactive = Fabricate(:user, active: false)
+ get "/u/#{inactive.username}.json"
+ expect(response).to be_success
+ end
+
+ it "raises an error on invalid access" do
+ Guardian.any_instance.expects(:can_see?).with(user).returns(false)
+ get "/u/#{user.username}.json"
+ 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)
+ get "/u/#{other_user.username}.json"
+ end
+
+ it "should not track a user profile view for a user viewing his own profile" do
+ UserProfileView.expects(:add).never
+ get "/u/#{user.username}.json"
+ end
+
+ it "skips tracking" do
+ UserProfileView.expects(:add).never
+ get "/u/#{user.username}.json", params: { 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
+ get "/u/by-external/997.json"
+ expect(response).to be_success
+ expect(JSON.parse(response.body)["user"]["username"]).to eq(user.username)
+ end
+
+ it "returns not found when external_id doesn't match" do
+ get "/u/by-external/99.json"
+ expect(response).not_to be_success
+ end
+ end
+
+ describe "include_post_count_for" do
+
+ let(:admin) { Fabricate(:admin) }
+ let(:topic) { Fabricate(:topic) }
+
+ before do
+ Fabricate(:post, user: user, topic: topic)
+ Fabricate(:post, user: admin, topic: topic)
+ Fabricate(:post, user: admin, topic: topic, post_type: Post.types[:whisper])
+ end
+
+ it "includes only visible posts" do
+ get "/u/#{admin.username}.json", params: { include_post_count_for: topic.id }
+ topic_post_count = JSON.parse(response.body).dig("user", "topic_post_count")
+ expect(topic_post_count[topic.id.to_s]).to eq(1)
+ end
+
+ it "includes all post types for staff members" do
+ sign_in(admin)
+
+ get "/u/#{admin.username}.json", params: { include_post_count_for: topic.id }
+ topic_post_count = JSON.parse(response.body).dig("user", "topic_post_count")
+ expect(topic_post_count[topic.id.to_s]).to eq(2)
+ end
+ end
+ end
it "should be able to view a user" do
get "/u/#{user.username}"
@@ -68,7 +2419,7 @@ RSpec.describe UsersController do
end
end
- describe "#badges" do
+ describe '#badges' do
it "renders fine by default" do
get "/u/#{user.username}/badges"
expect(response).to be_success
@@ -81,33 +2432,7 @@ RSpec.describe UsersController do
end
end
- describe "updating a user" do
- before do
- sign_in(user)
- end
-
- it "should be able to update a user" do
- put "/u/#{user.username}.json", params: { name: 'test.test' }
-
- expect(response).to be_success
- expect(user.reload.name).to eq('test.test')
- end
-
- describe 'when username contains a period' do
- before do
- user.update!(username: 'test.test')
- end
-
- it "should be able to update a user" do
- put "/u/#{user.username}.json", params: { name: 'testing123' }
-
- expect(response).to be_success
- expect(user.reload.name).to eq('testing123')
- end
- end
- end
-
- describe "#account_created" do
+ describe '#account_created' do
it "returns a message when no session is present" do
get "/u/account-created"
@@ -141,7 +2466,7 @@ RSpec.describe UsersController do
end
end
- describe "search_users" do
+ describe '#search_users' do
let(:topic) { Fabricate :topic }
let(:user) { Fabricate :user, username: "joecabot", name: "Lawrence Tierney" }
let(:post1) { Fabricate(:post, user: user, topic: topic) }
@@ -328,7 +2653,7 @@ RSpec.describe UsersController do
end
end
- describe '.user_preferences_redirect' do
+ describe '#user_preferences_redirect' do
it 'requires the user to be logged in' do
get '/user_preferences'
expect(response.status).to eq(404)