PageRenderTime 55ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/controllers/users_controller_spec.rb

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