PageRenderTime 106ms CodeModel.GetById 28ms RepoModel.GetById 2ms app.codeStats 0ms

/spec/controllers/users_controller_spec.rb

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