PageRenderTime 143ms CodeModel.GetById 2ms app.highlight 133ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/controllers/users_controller_spec.rb

https://github.com/dfasolin/discourse
Ruby | 1215 lines | 1085 code | 130 blank | 0 comment | 6 complexity | a94db763df124d7eed15f2e1ead82be4 MD5 | raw file
   1require 'spec_helper'
   2
   3describe UsersController do
   4
   5  describe '.show' do
   6    let!(:user) { log_in }
   7
   8    it 'returns success' do
   9      xhr :get, :show, username: user.username, format: :json
  10      response.should be_success
  11      json = JSON.parse(response.body)
  12
  13      json["user"]["has_title_badges"].should == false
  14
  15    end
  16
  17    it "returns not found when the username doesn't exist" do
  18      xhr :get, :show, username: 'madeuppity'
  19      response.should_not be_success
  20    end
  21
  22    it "raises an error on invalid access" do
  23      Guardian.any_instance.expects(:can_see?).with(user).returns(false)
  24      xhr :get, :show, username: user.username
  25      response.should be_forbidden
  26    end
  27
  28    context "fetching a user by external_id" do
  29      before { user.create_single_sign_on_record(external_id: '997', last_payload: '') }
  30
  31      it "returns fetch for a matching external_id" do
  32        xhr :get, :show, external_id: '997'
  33        response.should be_success
  34      end
  35
  36      it "returns not found when external_id doesn't match" do
  37        xhr :get, :show, external_id: '99'
  38        response.should_not be_success
  39      end
  40    end
  41  end
  42
  43  describe '.user_preferences_redirect' do
  44    it 'requires the user to be logged in' do
  45      lambda { get :user_preferences_redirect }.should raise_error(Discourse::NotLoggedIn)
  46    end
  47
  48    it "redirects to their profile when logged in" do
  49      user = log_in
  50      get :user_preferences_redirect
  51      response.should redirect_to("/users/#{user.username_lower}/preferences")
  52    end
  53  end
  54
  55  describe '.authorize_email' do
  56    it 'errors out for invalid tokens' do
  57      get :authorize_email, token: 'asdfasdf'
  58      response.should be_success
  59      flash[:error].should be_present
  60    end
  61
  62    context 'valid token' do
  63      it 'authorizes with a correct token' do
  64        user = Fabricate(:user)
  65        email_token = user.email_tokens.create(email: user.email)
  66
  67        get :authorize_email, token: email_token.token
  68        response.should be_success
  69        flash[:error].should be_blank
  70        session[:current_user_id].should be_present
  71      end
  72    end
  73  end
  74
  75  describe '.activate_account' do
  76    before do
  77      UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(false)
  78    end
  79
  80    context 'invalid token' do
  81      before do
  82        EmailToken.expects(:confirm).with('asdfasdf').returns(nil)
  83        put :perform_account_activation, token: 'asdfasdf'
  84      end
  85
  86      it 'return success' do
  87        response.should be_success
  88      end
  89
  90      it 'sets a flash error' do
  91        flash[:error].should be_present
  92      end
  93    end
  94
  95    context 'valid token' do
  96      let(:user) { Fabricate(:user) }
  97
  98      context 'welcome message' do
  99        before do
 100          EmailToken.expects(:confirm).with('asdfasdf').returns(user)
 101        end
 102
 103        it 'enqueues a welcome message if the user object indicates so' do
 104          user.send_welcome_message = true
 105          user.expects(:enqueue_welcome_message).with('welcome_user')
 106          put :perform_account_activation, token: 'asdfasdf'
 107        end
 108
 109        it "doesn't enqueue the welcome message if the object returns false" do
 110          user.send_welcome_message = false
 111          user.expects(:enqueue_welcome_message).with('welcome_user').never
 112          put :perform_account_activation, token: 'asdfasdf'
 113        end
 114      end
 115
 116      context "honeypot" do
 117        it "raises an error if the honeypot is invalid" do
 118          UsersController.any_instance.stubs(:honeypot_or_challenge_fails?).returns(true)
 119          put :perform_account_activation, token: 'asdfasdf'
 120          response.should_not be_success
 121        end
 122      end
 123
 124      context 'response' do
 125        before do
 126          Guardian.any_instance.expects(:can_access_forum?).returns(true)
 127          EmailToken.expects(:confirm).with('asdfasdf').returns(user)
 128          put :perform_account_activation, token: 'asdfasdf'
 129        end
 130
 131        it 'returns success' do
 132          response.should be_success
 133        end
 134
 135        it "doesn't set an error" do
 136          flash[:error].should be_blank
 137        end
 138
 139        it 'logs in as the user' do
 140          session[:current_user_id].should be_present
 141        end
 142
 143        it "doesn't set @needs_approval" do
 144          assigns[:needs_approval].should be_blank
 145        end
 146      end
 147
 148      context 'user is not approved' do
 149        before do
 150          Guardian.any_instance.expects(:can_access_forum?).returns(false)
 151          EmailToken.expects(:confirm).with('asdfasdf').returns(user)
 152          put :perform_account_activation, token: 'asdfasdf'
 153        end
 154
 155        it 'returns success' do
 156          response.should be_success
 157        end
 158
 159        it 'sets @needs_approval' do
 160          assigns[:needs_approval].should be_present
 161        end
 162
 163        it "doesn't set an error" do
 164          flash[:error].should be_blank
 165        end
 166
 167        it "doesn't log the user in" do
 168          session[:current_user_id].should be_blank
 169        end
 170      end
 171
 172    end
 173  end
 174
 175  describe '.change_email' do
 176    let(:new_email) { 'bubblegum@adventuretime.ooo' }
 177
 178    it "requires you to be logged in" do
 179      lambda { xhr :put, :change_email, username: 'asdf', email: new_email }.should raise_error(Discourse::NotLoggedIn)
 180    end
 181
 182    context 'when logged in' do
 183      let!(:user) { log_in }
 184
 185      it 'raises an error without an email parameter' do
 186        lambda { xhr :put, :change_email, username: user.username }.should raise_error(ActionController::ParameterMissing)
 187      end
 188
 189      it "raises an error if you can't edit the user's email" do
 190        Guardian.any_instance.expects(:can_edit_email?).with(user).returns(false)
 191        xhr :put, :change_email, username: user.username, email: new_email
 192        response.should be_forbidden
 193      end
 194
 195      context 'when the new email address is taken' do
 196        let!(:other_user) { Fabricate(:coding_horror) }
 197        it 'raises an error' do
 198          lambda { xhr :put, :change_email, username: user.username, email: other_user.email }.should raise_error(Discourse::InvalidParameters)
 199        end
 200
 201        it 'raises an error if there is whitespace too' do
 202          lambda { xhr :put, :change_email, username: user.username, email: other_user.email + ' ' }.should raise_error(Discourse::InvalidParameters)
 203        end
 204      end
 205
 206      context 'when new email is different case of existing email' do
 207        let!(:other_user) { Fabricate(:user, email: 'case.insensitive@gmail.com')}
 208
 209        it 'raises an error' do
 210          lambda { xhr :put, :change_email, username: user.username, email: other_user.email.upcase }.should raise_error(Discourse::InvalidParameters)
 211        end
 212      end
 213
 214      context 'success' do
 215
 216        it 'has an email token' do
 217          lambda { xhr :put, :change_email, username: user.username, email: new_email }.should change(EmailToken, :count)
 218        end
 219
 220        it 'enqueues an email authorization' do
 221          Jobs.expects(:enqueue).with(:user_email, has_entries(type: :authorize_email, user_id: user.id, to_address: new_email))
 222          xhr :put, :change_email, username: user.username, email: new_email
 223        end
 224      end
 225    end
 226
 227  end
 228
 229  describe '.password_reset' do
 230    let(:user) { Fabricate(:user) }
 231
 232    context "you can view it even if login is required" do
 233      it "returns success" do
 234        SiteSetting.login_required = true
 235        get :password_reset, token: 'asdfasdf'
 236        response.should be_success
 237      end
 238    end
 239
 240    context 'invalid token' do
 241      before do
 242        get :password_reset, token: SecureRandom.hex
 243      end
 244
 245      it 'disallows login' do
 246        flash[:error].should be_present
 247        session[:current_user_id].should be_blank
 248        response.should be_success
 249      end
 250
 251    end
 252
 253    context 'valid token' do
 254      it 'returns success' do
 255        user = Fabricate(:user)
 256        token = user.email_tokens.create(email: user.email).token
 257
 258        get :password_reset, token: token
 259        put :password_reset, token: token, password: 'newpassword'
 260        response.should be_success
 261        flash[:error].should be_blank
 262      end
 263    end
 264
 265    context 'submit change' do
 266      before do
 267        EmailToken.expects(:confirm).with('asdfasdf').returns(user)
 268      end
 269
 270      it "logs in the user" do
 271        put :password_reset, token: 'asdfasdf', password: 'newpassword'
 272        session[:current_user_id].should be_present
 273      end
 274
 275      it "doesn't log in the user when not approved" do
 276        SiteSetting.expects(:must_approve_users?).returns(true)
 277        put :password_reset, token: 'asdfasdf', password: 'newpassword'
 278        session[:current_user_id].should be_blank
 279      end
 280    end
 281  end
 282
 283  describe '#create' do
 284
 285    before do
 286      UsersController.any_instance.stubs(:honeypot_value).returns(nil)
 287      UsersController.any_instance.stubs(:challenge_value).returns(nil)
 288      SiteSetting.stubs(:allow_new_registrations).returns(true)
 289      @user = Fabricate.build(:user)
 290      @user.password = "strongpassword"
 291    end
 292
 293    def post_user
 294      xhr :post, :create,
 295        name: @user.name,
 296        username: @user.username,
 297        password: "strongpassword",
 298        email: @user.email
 299    end
 300
 301    context 'when creating a non active user (unconfirmed email)' do
 302
 303      it 'returns a 500 when local logins are disabled' do
 304        SiteSetting.expects(:enable_local_logins).returns(false)
 305        post_user
 306
 307        expect(response.status).to eq(500)
 308      end
 309
 310      it 'returns an error when new registrations are disabled' do
 311        SiteSetting.stubs(:allow_new_registrations).returns(false)
 312        post_user
 313        json = JSON.parse(response.body)
 314        json['success'].should be_false
 315        json['message'].should be_present
 316      end
 317
 318      it 'creates a user correctly' do
 319        Jobs.expects(:enqueue).with(:user_email, has_entries(type: :signup))
 320        User.any_instance.expects(:enqueue_welcome_message).with('welcome_user').never
 321
 322        post_user
 323
 324        expect(JSON.parse(response.body)['active']).to be_false
 325      end
 326
 327      context "and 'must approve users' site setting is enabled" do
 328        before { SiteSetting.expects(:must_approve_users).returns(true) }
 329
 330        it 'does not enqueue an email' do
 331          Jobs.expects(:enqueue).never
 332          post_user
 333        end
 334
 335        it 'does not login the user' do
 336          post_user
 337          expect(session[:current_user_id]).to be_blank
 338        end
 339
 340        it 'indicates the user is not active in the response' do
 341          post_user
 342          expect(JSON.parse(response.body)['active']).to be_false
 343        end
 344
 345        it "shows the 'waiting approval' message" do
 346          post_user
 347          expect(JSON.parse(response.body)['message']).to eq(
 348            I18n.t 'login.wait_approval'
 349          )
 350        end
 351      end
 352    end
 353
 354    context 'when creating an active user (confirmed email)' do
 355      before { User.any_instance.stubs(:active?).returns(true) }
 356
 357      it 'enqueues a welcome email' do
 358        User.any_instance.expects(:enqueue_welcome_message).with('welcome_user')
 359        post_user
 360      end
 361
 362      it "shows the 'active' message" do
 363        User.any_instance.expects(:enqueue_welcome_message)
 364        post_user
 365        expect(JSON.parse(response.body)['message']).to eq(
 366          I18n.t 'login.active'
 367        )
 368      end
 369
 370      it "should be logged in" do
 371        User.any_instance.expects(:enqueue_welcome_message)
 372        post_user
 373        session[:current_user_id].should be_present
 374      end
 375
 376      it 'indicates the user is active in the response' do
 377        User.any_instance.expects(:enqueue_welcome_message)
 378        post_user
 379        expect(JSON.parse(response.body)['active']).to be_true
 380      end
 381
 382      it 'returns 500 status when new registrations are disabled' do
 383        SiteSetting.stubs(:allow_new_registrations).returns(false)
 384        post_user
 385        json = JSON.parse(response.body)
 386        json['success'].should be_false
 387        json['message'].should be_present
 388      end
 389
 390      context 'authentication records for' do
 391
 392        before do
 393          SiteSetting.expects(:must_approve_users).returns(true)
 394        end
 395
 396        it 'should create twitter user info if required' do
 397          SiteSetting.stubs(:enable_twitter_logins?).returns(true)
 398          twitter_auth = { twitter_user_id: 42, twitter_screen_name: "bruce" }
 399          auth = session[:authentication] = {}
 400          auth[:authenticator_name] = 'twitter'
 401          auth[:extra_data] = twitter_auth
 402          TwitterUserInfo.expects(:create)
 403
 404          post_user
 405        end
 406      end
 407    end
 408
 409    context 'after success' do
 410      before { post_user }
 411
 412      it 'should succeed' do
 413        should respond_with(:success)
 414      end
 415
 416      it 'has the proper JSON' do
 417        json = JSON::parse(response.body)
 418        json["success"].should be_true
 419      end
 420
 421      it 'should not result in an active account' do
 422        User.find_by(username: @user.username).active.should be_false
 423      end
 424    end
 425
 426    shared_examples 'honeypot fails' do
 427      it 'should not create a new user' do
 428        expect {
 429          xhr :post, :create, create_params
 430        }.to_not change { User.count }
 431      end
 432
 433      it 'should not send an email' do
 434        User.any_instance.expects(:enqueue_welcome_message).never
 435        xhr :post, :create, create_params
 436      end
 437
 438      it 'should say it was successful' do
 439        xhr :post, :create, create_params
 440        json = JSON::parse(response.body)
 441        json["success"].should be_true
 442      end
 443    end
 444
 445    context 'when honeypot value is wrong' do
 446      before do
 447        UsersController.any_instance.stubs(:honeypot_value).returns('abc')
 448      end
 449      let(:create_params) { {name: @user.name, username: @user.username, password: "strongpassword", email: @user.email, password_confirmation: 'wrong'} }
 450      include_examples 'honeypot fails'
 451    end
 452
 453    context 'when challenge answer is wrong' do
 454      before do
 455        UsersController.any_instance.stubs(:challenge_value).returns('abc')
 456      end
 457      let(:create_params) { {name: @user.name, username: @user.username, password: "strongpassword", email: @user.email, challenge: 'abc'} }
 458      include_examples 'honeypot fails'
 459    end
 460
 461    context "when 'invite only' setting is enabled" do
 462      before { SiteSetting.expects(:invite_only?).returns(true) }
 463
 464      let(:create_params) {{
 465        name: @user.name,
 466        username: @user.username,
 467        password: 'strongpassword',
 468        email: @user.email
 469      }}
 470
 471      include_examples 'honeypot fails'
 472    end
 473
 474    shared_examples 'failed signup' do
 475      it 'should not create a new User' do
 476        expect { xhr :post, :create, create_params }.to_not change { User.count }
 477      end
 478
 479      it 'should report failed' do
 480        xhr :post, :create, create_params
 481        json = JSON::parse(response.body)
 482        json["success"].should_not be_true
 483      end
 484    end
 485
 486    context 'when password is blank' do
 487      let(:create_params) { {name: @user.name, username: @user.username, password: "", email: @user.email} }
 488      include_examples 'failed signup'
 489    end
 490
 491    context 'when password param is missing' do
 492      let(:create_params) { {name: @user.name, username: @user.username, email: @user.email} }
 493      include_examples 'failed signup'
 494    end
 495
 496    context 'when an Exception is raised' do
 497
 498      [ ActiveRecord::StatementInvalid,
 499        RestClient::Forbidden ].each do |exception|
 500        before { User.any_instance.stubs(:save).raises(exception) }
 501
 502        let(:create_params) {
 503          { name: @user.name, username: @user.username,
 504            password: "strongpassword", email: @user.email}
 505        }
 506
 507        include_examples 'failed signup'
 508      end
 509    end
 510
 511  end
 512
 513  context '.username' do
 514    it 'raises an error when not logged in' do
 515      lambda { xhr :put, :username, username: 'somename' }.should raise_error(Discourse::NotLoggedIn)
 516    end
 517
 518    context 'while logged in' do
 519      let!(:user) { log_in }
 520      let(:new_username) { "#{user.username}1234" }
 521
 522      it 'raises an error without a new_username param' do
 523        lambda { xhr :put, :username, username: user.username }.should raise_error(ActionController::ParameterMissing)
 524      end
 525
 526      it 'raises an error when you don\'t have permission to change the username' do
 527        Guardian.any_instance.expects(:can_edit_username?).with(user).returns(false)
 528        xhr :put, :username, username: user.username, new_username: new_username
 529        response.should be_forbidden
 530      end
 531
 532      it 'raises an error when change_username fails' do
 533        User.any_instance.expects(:change_username).with(new_username).returns(false)
 534        lambda { xhr :put, :username, username: user.username, new_username: new_username }.should raise_error(Discourse::InvalidParameters)
 535      end
 536
 537      it 'should succeed when the change_username returns true' do
 538        User.any_instance.expects(:change_username).with(new_username).returns(true)
 539        xhr :put, :username, username: user.username, new_username: new_username
 540        response.should be_success
 541      end
 542
 543    end
 544  end
 545
 546  context '.check_username' do
 547    it 'raises an error without any parameters' do
 548      lambda { xhr :get, :check_username }.should raise_error(ActionController::ParameterMissing)
 549    end
 550
 551    shared_examples 'when username is unavailable' do
 552      it 'should return success' do
 553        response.should be_success
 554      end
 555
 556      it 'should return available as false in the JSON' do
 557        ::JSON.parse(response.body)['available'].should be_false
 558      end
 559
 560      it 'should return a suggested username' do
 561        ::JSON.parse(response.body)['suggestion'].should be_present
 562      end
 563    end
 564
 565    shared_examples 'when username is available' do
 566      it 'should return success' do
 567        response.should be_success
 568      end
 569
 570      it 'should return available in the JSON' do
 571        ::JSON.parse(response.body)['available'].should be_true
 572      end
 573    end
 574
 575    it 'returns nothing when given an email param but no username' do
 576      xhr :get, :check_username, email: 'dood@example.com'
 577      response.should be_success
 578    end
 579
 580    context 'username is available' do
 581      before do
 582        xhr :get, :check_username, username: 'BruceWayne'
 583      end
 584      include_examples 'when username is available'
 585    end
 586
 587    context 'username is unavailable' do
 588      let!(:user) { Fabricate(:user) }
 589      before do
 590        xhr :get, :check_username, username: user.username
 591      end
 592      include_examples 'when username is unavailable'
 593    end
 594
 595    shared_examples 'checking an invalid username' do
 596      it 'should return success' do
 597        response.should be_success
 598      end
 599
 600      it 'should not return an available key' do
 601        ::JSON.parse(response.body)['available'].should be_nil
 602      end
 603
 604      it 'should return an error message' do
 605        ::JSON.parse(response.body)['errors'].should_not be_empty
 606      end
 607    end
 608
 609    context 'has invalid characters' do
 610      before do
 611        xhr :get, :check_username, username: 'bad username'
 612      end
 613      include_examples 'checking an invalid username'
 614
 615      it 'should return the invalid characters message' do
 616        ::JSON.parse(response.body)['errors'].should include(I18n.t(:'user.username.characters'))
 617      end
 618    end
 619
 620    context 'is too long' do
 621      before do
 622        xhr :get, :check_username, username: generate_username(User.username_length.last + 1)
 623      end
 624      include_examples 'checking an invalid username'
 625
 626      it 'should return the "too long" message' do
 627        ::JSON.parse(response.body)['errors'].should include(I18n.t(:'user.username.long', max: User.username_length.end))
 628      end
 629    end
 630
 631    describe 'different case of existing username' do
 632      context "it's my username" do
 633        let!(:user) { Fabricate(:user, username: 'hansolo') }
 634        before do
 635          log_in_user(user)
 636          xhr :get, :check_username, username: 'HanSolo'
 637        end
 638        include_examples 'when username is available'
 639      end
 640
 641      context "it's someone else's username" do
 642        let!(:user) { Fabricate(:user, username: 'hansolo') }
 643        before do
 644          log_in
 645          xhr :get, :check_username, username: 'HanSolo'
 646        end
 647        include_examples 'when username is unavailable'
 648      end
 649
 650      context "an admin changing it for someone else" do
 651        let!(:user) { Fabricate(:user, username: 'hansolo') }
 652        before do
 653          log_in_user(Fabricate(:admin))
 654          xhr :get, :check_username, username: 'HanSolo', for_user_id: user.id
 655        end
 656        include_examples 'when username is available'
 657      end
 658    end
 659  end
 660
 661  describe '#invited' do
 662    it 'returns success' do
 663      user = Fabricate(:user)
 664
 665      xhr :get, :invited, username: user.username
 666
 667      expect(response).to be_success
 668    end
 669
 670    it 'filters by email' do
 671      inviter = Fabricate(:user)
 672      invitee = Fabricate(:user)
 673      invite = Fabricate(
 674        :invite,
 675        email: 'billybob@example.com',
 676        invited_by: inviter,
 677        user: invitee
 678      )
 679      Fabricate(
 680        :invite,
 681        email: 'jimtom@example.com',
 682        invited_by: inviter,
 683        user: invitee
 684      )
 685
 686      xhr :get, :invited, username: inviter.username, filter: 'billybob'
 687
 688      invites = JSON.parse(response.body)['invites']
 689      expect(invites).to have(1).item
 690      expect(invites.first).to include('email' => 'billybob@example.com')
 691    end
 692
 693    it 'filters by username' do
 694      inviter = Fabricate(:user)
 695      invitee = Fabricate(:user, username: 'billybob')
 696      invite = Fabricate(
 697        :invite,
 698        invited_by: inviter,
 699        email: 'billybob@example.com',
 700        user: invitee
 701      )
 702      Fabricate(
 703        :invite,
 704        invited_by: inviter,
 705        user: Fabricate(:user, username: 'jimtom')
 706      )
 707
 708      xhr :get, :invited, username: inviter.username, filter: 'billybob'
 709
 710      invites = JSON.parse(response.body)['invites']
 711      expect(invites).to have(1).item
 712      expect(invites.first).to include('email' => 'billybob@example.com')
 713    end
 714
 715    context 'with guest' do
 716      context 'with pending invites' do
 717        it 'does not return invites' do
 718          inviter = Fabricate(:user)
 719          Fabricate(:invite, invited_by: inviter)
 720
 721          xhr :get, :invited, username: inviter.username
 722
 723          invites = JSON.parse(response.body)['invites']
 724          expect(invites).to be_empty
 725        end
 726      end
 727
 728      context 'with redeemed invites' do
 729        it 'returns invites' do
 730          inviter = Fabricate(:user)
 731          invitee = Fabricate(:user)
 732          invite = Fabricate(:invite, invited_by: inviter, user: invitee)
 733
 734          xhr :get, :invited, username: inviter.username
 735
 736          invites = JSON.parse(response.body)['invites']
 737          expect(invites).to have(1).item
 738          expect(invites.first).to include('email' => invite.email)
 739        end
 740      end
 741    end
 742
 743    context 'with authenticated user' do
 744      context 'with pending invites' do
 745        context 'with permission to see pending invites' do
 746          it 'returns invites' do
 747            user = log_in
 748            inviter = Fabricate(:user)
 749            invite = Fabricate(:invite, invited_by: inviter)
 750            stub_guardian(user) do |guardian|
 751              guardian.stubs(:can_see_invite_details?).
 752                with(inviter).returns(true)
 753            end
 754
 755            xhr :get, :invited, username: inviter.username
 756
 757            invites = JSON.parse(response.body)['invites']
 758            expect(invites).to have(1).item
 759            expect(invites.first).to include("email" => invite.email)
 760          end
 761        end
 762
 763        context 'without permission to see pending invites' do
 764          it 'does not return invites' do
 765            user = log_in
 766            inviter = Fabricate(:user)
 767            invitee = Fabricate(:user)
 768            Fabricate(:invite, invited_by: inviter)
 769            stub_guardian(user) do |guardian|
 770              guardian.stubs(:can_see_invite_details?).
 771                with(inviter).returns(false)
 772            end
 773
 774            xhr :get, :invited, username: inviter.username
 775
 776            json = JSON.parse(response.body)['invites']
 777            expect(json).to be_empty
 778          end
 779        end
 780      end
 781
 782      context 'with redeemed invites' do
 783        it 'returns invites' do
 784          user = log_in
 785          inviter = Fabricate(:user)
 786          invitee = Fabricate(:user)
 787          invite = Fabricate(:invite, invited_by: inviter, user: invitee)
 788
 789          xhr :get, :invited, username: inviter.username
 790
 791          invites = JSON.parse(response.body)['invites']
 792          expect(invites).to have(1).item
 793          expect(invites.first).to include('email' => invite.email)
 794        end
 795      end
 796    end
 797  end
 798
 799  describe '#update' do
 800    context 'with guest' do
 801      it 'raises an error' do
 802        expect do
 803          xhr :put, :update, username: 'guest'
 804        end.to raise_error(Discourse::NotLoggedIn)
 805      end
 806    end
 807
 808    context 'with authenticated user' do
 809      context 'with permission to update' do
 810        it 'allows the update' do
 811          user = Fabricate(:user, name: 'Billy Bob')
 812          log_in_user(user)
 813
 814          put :update, username: user.username, name: 'Jim Tom', custom_fields: {test: :it}
 815
 816          expect(response).to be_success
 817
 818          user.reload
 819
 820          expect(user.name).to eq 'Jim Tom'
 821          expect(user.custom_fields['test']).to eq 'it'
 822        end
 823
 824        it 'returns user JSON' do
 825          user = log_in
 826
 827          put :update, username: user.username
 828
 829          json = JSON.parse(response.body)
 830          expect(json['user']['id']).to eq user.id
 831        end
 832      end
 833
 834      context 'without permission to update' do
 835        it 'does not allow the update' do
 836          user = Fabricate(:user, name: 'Billy Bob')
 837          log_in_user(user)
 838          guardian = Guardian.new(user)
 839          guardian.stubs(:ensure_can_edit!).with(user).raises(Discourse::InvalidAccess.new)
 840          Guardian.stubs(new: guardian).with(user)
 841
 842          put :update, username: user.username, name: 'Jim Tom'
 843
 844          expect(response).to be_forbidden
 845          expect(user.reload.name).not_to eq 'Jim Tom'
 846        end
 847      end
 848    end
 849  end
 850
 851  describe "badge_title" do
 852    let(:user) { Fabricate(:user) }
 853    let(:badge) { Fabricate(:badge) }
 854    let(:user_badge) { BadgeGranter.grant(badge, user) }
 855
 856    it "sets the user's title to the badge name if it is titleable" do
 857      log_in_user user
 858      xhr :put, :badge_title, user_badge_id: user_badge.id, username: user.username
 859      user.reload.title.should_not == badge.name
 860      badge.update_attributes allow_title: true
 861      xhr :put, :badge_title, user_badge_id: user_badge.id, username: user.username
 862      user.reload.title.should == badge.name
 863    end
 864  end
 865
 866  describe "search_users" do
 867
 868    let(:topic) { Fabricate :topic }
 869    let(:user)  { Fabricate :user, username: "joecabot", name: "Lawrence Tierney" }
 870
 871    before do
 872      ActiveRecord::Base.observers.enable :all
 873      Fabricate :post, user: user, topic: topic
 874    end
 875
 876    it "searches when provided the term only" do
 877      xhr :post, :search_users, term: user.name.split(" ").last
 878      response.should be_success
 879      json = JSON.parse(response.body)
 880      json["users"].map { |u| u["username"] }.should include(user.username)
 881    end
 882
 883    it "searches when provided the topic only" do
 884      xhr :post, :search_users, topic_id: topic.id
 885      response.should be_success
 886      json = JSON.parse(response.body)
 887      json["users"].map { |u| u["username"] }.should include(user.username)
 888    end
 889
 890    it "searches when provided the term and topic" do
 891      xhr :post, :search_users, term: user.name.split(" ").last, topic_id: topic.id
 892      response.should be_success
 893      json = JSON.parse(response.body)
 894      json["users"].map { |u| u["username"] }.should include(user.username)
 895    end
 896
 897    context "when `enable_names` is true" do
 898      before do
 899        SiteSetting.enable_names = true
 900      end
 901
 902      it "returns names" do
 903        xhr :post, :search_users, term: user.name
 904        json = JSON.parse(response.body)
 905        json["users"].map { |u| u["name"] }.should include(user.name)
 906      end
 907    end
 908
 909    context "when `enable_names` is false" do
 910      before do
 911        SiteSetting.stubs(:enable_names?).returns(false)
 912      end
 913
 914      it "returns names" do
 915        xhr :post, :search_users, term: user.name
 916        json = JSON.parse(response.body)
 917        json["users"].map { |u| u["name"] }.should_not include(user.name)
 918      end
 919    end
 920
 921  end
 922
 923  describe 'send_activation_email' do
 924    context 'for an existing user' do
 925      let(:user) { Fabricate(:user) }
 926
 927      before do
 928        UsersController.any_instance.stubs(:fetch_user_from_params).returns(user)
 929      end
 930
 931      context 'with a valid email_token' do
 932        it 'should send the activation email' do
 933          Jobs.expects(:enqueue).with(:user_email, has_entries(type: :signup))
 934          xhr :post, :send_activation_email, username: user.username
 935        end
 936      end
 937
 938      context 'without an existing email_token' do
 939        before do
 940          user.email_tokens.each {|t| t.destroy}
 941          user.reload
 942        end
 943
 944        it 'should generate a new token' do
 945          expect {
 946            xhr :post, :send_activation_email, username: user.username
 947          }.to change{ user.email_tokens(true).count }.by(1)
 948        end
 949
 950        it 'should send an email' do
 951          Jobs.expects(:enqueue).with(:user_email, has_entries(type: :signup))
 952          xhr :post, :send_activation_email, username: user.username
 953        end
 954      end
 955    end
 956
 957    context 'when username does not exist' do
 958      it 'should not send an email' do
 959        Jobs.expects(:enqueue).never
 960        xhr :post, :send_activation_email, username: 'nopenopenopenope'
 961      end
 962    end
 963  end
 964
 965  describe '.upload_user_image' do
 966
 967    it 'raises an error when not logged in' do
 968      lambda { xhr :put, :upload_user_image, username: 'asdf' }.should raise_error(Discourse::NotLoggedIn)
 969    end
 970
 971    context 'while logged in' do
 972
 973      let!(:user) { log_in }
 974
 975      let(:logo) { file_from_fixtures("logo.png") }
 976
 977      let(:user_image) do
 978        ActionDispatch::Http::UploadedFile.new({ filename: 'logo.png', tempfile: logo })
 979      end
 980
 981      it 'raises an error without a image_type param' do
 982        lambda { xhr :put, :upload_user_image, username: user.username }.should raise_error(ActionController::ParameterMissing)
 983      end
 984
 985      describe "with uploaded file" do
 986
 987        it 'raises an error when you don\'t have permission to upload an user image' do
 988          Guardian.any_instance.expects(:can_edit?).with(user).returns(false)
 989          xhr :post, :upload_user_image, username: user.username, image_type: "avatar"
 990          response.should be_forbidden
 991        end
 992
 993        it 'rejects large images' do
 994          SiteSetting.stubs(:max_image_size_kb).returns(1)
 995          xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "avatar"
 996          response.status.should eq 422
 997        end
 998
 999        it 'rejects unauthorized images' do
1000          SiteSetting.stubs(:authorized_extensions).returns(".txt")
1001          xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "avatar"
1002          response.status.should eq 422
1003        end
1004
1005        it 'is successful for avatars' do
1006          upload = Fabricate(:upload)
1007          Upload.expects(:create_for).returns(upload)
1008          # enqueues the user_image generator job
1009          xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "avatar"
1010          # returns the url, width and height of the uploaded image
1011          json = JSON.parse(response.body)
1012          json['url'].should == "/uploads/default/1/1234567890123456.png"
1013          json['width'].should == 100
1014          json['height'].should == 200
1015          json['upload_id'].should == upload.id
1016        end
1017
1018        it 'is successful for profile backgrounds' do
1019          upload = Fabricate(:upload)
1020          Upload.expects(:create_for).returns(upload)
1021          xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "profile_background"
1022          user.reload
1023
1024          user.user_profile.profile_background.should == "/uploads/default/1/1234567890123456.png"
1025
1026          # returns the url, width and height of the uploaded image
1027          json = JSON.parse(response.body)
1028          json['url'].should == "/uploads/default/1/1234567890123456.png"
1029          json['width'].should == 100
1030          json['height'].should == 200
1031        end
1032
1033      end
1034
1035      describe "with url" do
1036        let(:user_image_url) { "http://cdn.discourse.org/assets/logo.png" }
1037
1038        before { UsersController.any_instance.stubs(:is_api?).returns(true) }
1039
1040        describe "correct urls" do
1041
1042          before { FileHelper.stubs(:download).returns(logo) }
1043
1044          it 'rejects large images' do
1045            SiteSetting.stubs(:max_image_size_kb).returns(1)
1046            xhr :post, :upload_user_image, username: user.username, file: user_image_url, image_type: "profile_background"
1047            response.status.should eq 422
1048          end
1049
1050          it 'rejects unauthorized images' do
1051            SiteSetting.stubs(:authorized_extensions).returns(".txt")
1052            xhr :post, :upload_user_image, username: user.username, file: user_image_url, image_type: "profile_background"
1053            response.status.should eq 422
1054          end
1055
1056          it 'is successful for avatars' do
1057            upload = Fabricate(:upload)
1058            Upload.expects(:create_for).returns(upload)
1059            # enqueues the user_image generator job
1060            xhr :post, :upload_avatar, username: user.username, file: user_image_url, image_type: "avatar"
1061            json = JSON.parse(response.body)
1062            json['url'].should == "/uploads/default/1/1234567890123456.png"
1063            json['width'].should == 100
1064            json['height'].should == 200
1065            json['upload_id'].should == upload.id
1066          end
1067
1068          it 'is successful for profile backgrounds' do
1069            upload = Fabricate(:upload)
1070            Upload.expects(:create_for).returns(upload)
1071            xhr :post, :upload_user_image, username: user.username, file: user_image_url, image_type: "profile_background"
1072            user.reload
1073            user.user_profile.profile_background.should == "/uploads/default/1/1234567890123456.png"
1074
1075            # returns the url, width and height of the uploaded image
1076            json = JSON.parse(response.body)
1077            json['url'].should == "/uploads/default/1/1234567890123456.png"
1078            json['width'].should == 100
1079            json['height'].should == 200
1080          end
1081        end
1082
1083        it "should handle malformed urls" do
1084          xhr :post, :upload_user_image, username: user.username, file: "foobar", image_type: "profile_background"
1085          response.status.should eq 422
1086        end
1087
1088      end
1089
1090    end
1091
1092  end
1093
1094  describe '.pick_avatar' do
1095
1096    it 'raises an error when not logged in' do
1097      lambda { xhr :put, :pick_avatar, username: 'asdf', avatar_id: 1}.should raise_error(Discourse::NotLoggedIn)
1098    end
1099
1100    context 'while logged in' do
1101
1102      let!(:user) { log_in }
1103
1104      it 'raises an error when you don\'t have permission to toggle the avatar' do
1105        another_user = Fabricate(:user)
1106        xhr :put, :pick_avatar, username: another_user.username, upload_id: 1
1107        response.should be_forbidden
1108      end
1109
1110      it 'it successful' do
1111        xhr :put, :pick_avatar, username: user.username, upload_id: 111
1112        user.reload.uploaded_avatar_id.should == 111
1113        response.should be_success
1114
1115        xhr :put, :pick_avatar, username: user.username
1116        user.reload.uploaded_avatar_id.should == nil
1117        response.should be_success
1118      end
1119
1120    end
1121
1122  end
1123
1124  describe '.destroy_user_image' do
1125
1126    it 'raises an error when not logged in' do
1127      lambda { xhr :delete, :destroy_user_image, type: 'profile_background', username: 'asdf' }.should raise_error(Discourse::NotLoggedIn)
1128    end
1129
1130    context 'while logged in' do
1131
1132      let!(:user) { log_in }
1133
1134      it 'raises an error when you don\'t have permission to clear the profile background' do
1135        Guardian.any_instance.expects(:can_edit?).with(user).returns(false)
1136        xhr :delete, :destroy_user_image, username: user.username, image_type: 'profile_background'
1137        response.should be_forbidden
1138      end
1139
1140      it "requires the `image_type` param" do
1141        -> { xhr :delete, :destroy_user_image, username: user.username }.should raise_error(ActionController::ParameterMissing)
1142      end
1143
1144      it "only allows certain `image_types`" do
1145        -> { xhr :delete, :destroy_user_image, username: user.username, image_type: 'wat' }.should raise_error(Discourse::InvalidParameters)
1146      end
1147
1148      it 'can clear the profile background' do
1149        xhr :delete, :destroy_user_image, image_type: 'profile_background', username: user.username
1150        user.reload.user_profile.profile_background.should == ""
1151        response.should be_success
1152      end
1153
1154    end
1155  end
1156
1157  describe '.destroy' do
1158    it 'raises an error when not logged in' do
1159      lambda { xhr :delete, :destroy, username: 'nobody' }.should raise_error(Discourse::NotLoggedIn)
1160    end
1161
1162    context 'while logged in' do
1163      let!(:user) { log_in }
1164
1165      it 'raises an error when you cannot delete your account' do
1166        Guardian.any_instance.stubs(:can_delete_user?).returns(false)
1167        UserDestroyer.any_instance.expects(:destroy).never
1168        xhr :delete, :destroy, username: user.username
1169        response.should be_forbidden
1170      end
1171
1172      it "raises an error when you try to delete someone else's account" do
1173        UserDestroyer.any_instance.expects(:destroy).never
1174        xhr :delete, :destroy, username: Fabricate(:user).username
1175        response.should be_forbidden
1176      end
1177
1178      it "deletes your account when you're allowed to" do
1179        Guardian.any_instance.stubs(:can_delete_user?).returns(true)
1180        UserDestroyer.any_instance.expects(:destroy).with(user, anything).returns(user)
1181        xhr :delete, :destroy, username: user.username
1182        response.should be_success
1183      end
1184    end
1185  end
1186
1187  describe '.my_redirect' do
1188
1189    it "returns 404 if the user is not logged in" do
1190      get :my_redirect, path: "wat"
1191      response.should_not be_success
1192      response.should_not be_redirect
1193    end
1194
1195    context "when the user is logged in" do
1196      let!(:user) { log_in }
1197
1198      it "will not redirect to an invalid path" do
1199        get :my_redirect, path: "wat/..password.txt"
1200        response.should_not be_redirect
1201      end
1202
1203      it "will redirect to an valid path" do
1204        get :my_redirect, path: "preferences"
1205        response.should be_redirect
1206      end
1207
1208      it "permits forward slashes" do
1209        get :my_redirect, path: "activity/posts"
1210        response.should be_redirect
1211      end
1212    end
1213  end
1214
1215end