PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/spec/controllers/users_controller_spec.rb

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