PageRenderTime 137ms CodeModel.GetById 2ms app.highlight 127ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/controllers/users_controller_spec.rb

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