You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

attachments_controller_test.rb 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. # encoding: utf-8
  2. #
  3. # Redmine - project management software
  4. # Copyright (C) 2006-2017 Jean-Philippe Lang
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License
  8. # as published by the Free Software Foundation; either version 2
  9. # of the License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. require File.expand_path('../../test_helper', __FILE__)
  20. class AttachmentsControllerTest < Redmine::ControllerTest
  21. fixtures :users, :projects, :roles, :members, :member_roles,
  22. :enabled_modules, :issues, :trackers, :attachments,
  23. :versions, :wiki_pages, :wikis, :documents
  24. def setup
  25. User.current = nil
  26. set_fixtures_attachments_directory
  27. end
  28. def teardown
  29. set_tmp_attachments_directory
  30. end
  31. def test_show_diff
  32. ['inline', 'sbs'].each do |dt|
  33. # 060719210727_changeset_utf8.diff
  34. get :show, :params => {
  35. :id => 14,
  36. :type => dt
  37. }
  38. assert_response :success
  39. assert_equal 'text/html', @response.content_type
  40. assert_select 'th.filename', :text => /issues_controller.rb\t\(révision 1484\)/
  41. assert_select 'td.line-code', :text => /Demande créée avec succès/
  42. end
  43. set_tmp_attachments_directory
  44. end
  45. def test_show_diff_replace_cannot_convert_content
  46. with_settings :repositories_encodings => 'UTF-8' do
  47. ['inline', 'sbs'].each do |dt|
  48. # 060719210727_changeset_iso8859-1.diff
  49. get :show, :params => {
  50. :id => 5,
  51. :type => dt
  52. }
  53. assert_response :success
  54. assert_equal 'text/html', @response.content_type
  55. assert_select 'th.filename', :text => /issues_controller.rb\t\(r\?vision 1484\)/
  56. assert_select 'td.line-code', :text => /Demande cr\?\?e avec succ\?s/
  57. end
  58. end
  59. set_tmp_attachments_directory
  60. end
  61. def test_show_diff_latin_1
  62. with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
  63. ['inline', 'sbs'].each do |dt|
  64. # 060719210727_changeset_iso8859-1.diff
  65. get :show, :params => {
  66. :id => 5,
  67. :type => dt
  68. }
  69. assert_response :success
  70. assert_equal 'text/html', @response.content_type
  71. assert_select 'th.filename', :text => /issues_controller.rb\t\(révision 1484\)/
  72. assert_select 'td.line-code', :text => /Demande créée avec succès/
  73. end
  74. end
  75. set_tmp_attachments_directory
  76. end
  77. def test_show_should_save_diff_type_as_user_preference
  78. user1 = User.find(1)
  79. user1.pref[:diff_type] = nil
  80. user1.preference.save
  81. user = User.find(1)
  82. assert_nil user.pref[:diff_type]
  83. @request.session[:user_id] = 1 # admin
  84. get :show, :params => {
  85. :id => 5
  86. }
  87. assert_response :success
  88. user.reload
  89. assert_equal "inline", user.pref[:diff_type]
  90. get :show, :params => {
  91. :id => 5,
  92. :type => 'sbs'
  93. }
  94. assert_response :success
  95. user.reload
  96. assert_equal "sbs", user.pref[:diff_type]
  97. end
  98. def test_diff_show_filename_in_mercurial_export
  99. set_tmp_attachments_directory
  100. a = Attachment.new(:container => Issue.find(1),
  101. :file => uploaded_test_file("hg-export.diff", "text/plain"),
  102. :author => User.find(1))
  103. assert a.save
  104. assert_equal 'hg-export.diff', a.filename
  105. get :show, :params => {
  106. :id => a.id,
  107. :type => 'inline'
  108. }
  109. assert_response :success
  110. assert_equal 'text/html', @response.content_type
  111. assert_select 'th.filename', :text => 'test1.txt'
  112. end
  113. def test_show_text_file
  114. get :show, :params => {
  115. :id => 4
  116. }
  117. assert_response :success
  118. assert_equal 'text/html', @response.content_type
  119. set_tmp_attachments_directory
  120. end
  121. def test_show_text_file_utf_8
  122. set_tmp_attachments_directory
  123. a = Attachment.new(:container => Issue.find(1),
  124. :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
  125. :author => User.find(1))
  126. assert a.save
  127. assert_equal 'japanese-utf-8.txt', a.filename
  128. str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
  129. get :show, :params => {
  130. :id => a.id
  131. }
  132. assert_response :success
  133. assert_equal 'text/html', @response.content_type
  134. assert_select 'tr#L1' do
  135. assert_select 'th.line-num', :text => '1'
  136. assert_select 'td', :text => /#{str_japanese}/
  137. end
  138. end
  139. def test_show_text_file_replace_cannot_convert_content
  140. set_tmp_attachments_directory
  141. with_settings :repositories_encodings => 'UTF-8' do
  142. a = Attachment.new(:container => Issue.find(1),
  143. :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
  144. :author => User.find(1))
  145. assert a.save
  146. assert_equal 'iso8859-1.txt', a.filename
  147. get :show, :params => {
  148. :id => a.id
  149. }
  150. assert_response :success
  151. assert_equal 'text/html', @response.content_type
  152. assert_select 'tr#L7' do
  153. assert_select 'th.line-num', :text => '7'
  154. assert_select 'td', :text => /Demande cr\?\?e avec succ\?s/
  155. end
  156. end
  157. end
  158. def test_show_text_file_latin_1
  159. set_tmp_attachments_directory
  160. with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
  161. a = Attachment.new(:container => Issue.find(1),
  162. :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
  163. :author => User.find(1))
  164. assert a.save
  165. assert_equal 'iso8859-1.txt', a.filename
  166. get :show, :params => {
  167. :id => a.id
  168. }
  169. assert_response :success
  170. assert_equal 'text/html', @response.content_type
  171. assert_select 'tr#L7' do
  172. assert_select 'th.line-num', :text => '7'
  173. assert_select 'td', :text => /Demande créée avec succès/
  174. end
  175. end
  176. end
  177. def test_show_text_file_should_show_other_if_too_big
  178. @request.session[:user_id] = 2
  179. with_settings :file_max_size_displayed => 512 do
  180. Attachment.find(4).update_attribute :filesize, 754.kilobyte
  181. get :show, :params => {
  182. :id => 4
  183. }
  184. assert_response :success
  185. assert_equal 'text/html', @response.content_type
  186. assert_select '.nodata', :text => 'No preview available. Download the file instead.'
  187. end
  188. set_tmp_attachments_directory
  189. end
  190. def test_show_image
  191. @request.session[:user_id] = 2
  192. get :show, :params => {
  193. :id => 16
  194. }
  195. assert_response :success
  196. assert_equal 'text/html', @response.content_type
  197. assert_select 'img.filecontent', :src => attachments(:attachments_010).filename
  198. end
  199. def test_show_other_with_no_preview
  200. @request.session[:user_id] = 2
  201. get :show, :params => {
  202. :id => 6
  203. }
  204. assert_equal 'text/html', @response.content_type
  205. assert_select '.nodata', :text => 'No preview available. Download the file instead.'
  206. set_tmp_attachments_directory
  207. end
  208. def test_show_file_from_private_issue_without_permission
  209. get :show, :params => {
  210. :id => 15
  211. }
  212. assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
  213. set_tmp_attachments_directory
  214. end
  215. def test_show_file_from_private_issue_with_permission
  216. @request.session[:user_id] = 2
  217. get :show, :params => {
  218. :id => 15
  219. }
  220. assert_response :success
  221. assert_select 'h2', :text => /private.diff/
  222. set_tmp_attachments_directory
  223. end
  224. def test_show_file_without_container_should_be_allowed_to_author
  225. set_tmp_attachments_directory
  226. attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
  227. @request.session[:user_id] = 2
  228. get :show, :params => {
  229. :id => attachment.id
  230. }
  231. assert_response 200
  232. end
  233. def test_show_file_without_container_should_be_denied_to_other_users
  234. set_tmp_attachments_directory
  235. attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
  236. @request.session[:user_id] = 3
  237. get :show, :params => {
  238. :id => attachment.id
  239. }
  240. assert_response 403
  241. end
  242. def test_show_issue_attachment_should_highlight_issues_menu_item
  243. get :show, :params => {
  244. :id => 4
  245. }
  246. assert_response :success
  247. assert_select '#main-menu a.issues.selected'
  248. end
  249. def test_show_invalid_should_respond_with_404
  250. get :show, :params => {
  251. :id => 999
  252. }
  253. assert_response 404
  254. end
  255. def test_show_renders_pagination
  256. get :show, :params => { :id => 5, :type => 'inline' }
  257. assert_response :success
  258. assert_select 'ul.pages li.next', :text => /next/i
  259. assert_select 'ul.pages li.previous', :text => /previous/i
  260. set_tmp_attachments_directory
  261. end
  262. def test_download_text_file
  263. get :download, :params => {
  264. :id => 4
  265. }
  266. assert_response :success
  267. assert_equal 'application/x-ruby', @response.content_type
  268. etag = @response.etag
  269. assert_not_nil etag
  270. @request.env["HTTP_IF_NONE_MATCH"] = etag
  271. get :download, :params => {
  272. :id => 4
  273. }
  274. assert_response 304
  275. set_tmp_attachments_directory
  276. end
  277. def test_download_js_file
  278. set_tmp_attachments_directory
  279. attachment = Attachment.create!(
  280. :file => mock_file_with_options(:original_filename => "hello.js", :content_type => "text/javascript"),
  281. :author_id => 2,
  282. :container => Issue.find(1)
  283. )
  284. get :download, :params => {
  285. :id => attachment.id
  286. }
  287. assert_response :success
  288. assert_equal 'text/javascript', @response.content_type
  289. end
  290. def test_download_version_file_with_issue_tracking_disabled
  291. Project.find(1).disable_module! :issue_tracking
  292. get :download, :params => {
  293. :id => 9
  294. }
  295. assert_response :success
  296. end
  297. def test_download_should_assign_content_type_if_blank
  298. Attachment.find(4).update_attribute(:content_type, '')
  299. get :download, :params => {
  300. :id => 4
  301. }
  302. assert_response :success
  303. assert_equal 'text/x-ruby', @response.content_type
  304. set_tmp_attachments_directory
  305. end
  306. def test_download_should_assign_better_content_type_than_application_octet_stream
  307. Attachment.find(4).update! :content_type => "application/octet-stream"
  308. get :download, :params => {
  309. :id => 4
  310. }
  311. assert_response :success
  312. assert_equal 'text/x-ruby', @response.content_type
  313. set_tmp_attachments_directory
  314. end
  315. def test_download_missing_file
  316. get :download, :params => {
  317. :id => 2
  318. }
  319. assert_response 404
  320. set_tmp_attachments_directory
  321. end
  322. def test_download_should_be_denied_without_permission
  323. get :download, :params => {
  324. :id => 7
  325. }
  326. assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
  327. set_tmp_attachments_directory
  328. end
  329. if convert_installed?
  330. def test_thumbnail
  331. Attachment.clear_thumbnails
  332. @request.session[:user_id] = 2
  333. get :thumbnail, :params => {
  334. :id => 16
  335. }
  336. assert_response :success
  337. assert_equal 'image/png', response.content_type
  338. etag = @response.etag
  339. assert_not_nil etag
  340. @request.env["HTTP_IF_NONE_MATCH"] = etag
  341. get :thumbnail, :params => {
  342. :id => 16
  343. }
  344. assert_response 304
  345. end
  346. def test_thumbnail_should_not_exceed_maximum_size
  347. Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 800}
  348. @request.session[:user_id] = 2
  349. get :thumbnail, :params => {
  350. :id => 16,
  351. :size => 2000
  352. }
  353. end
  354. def test_thumbnail_should_round_size
  355. Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 250}
  356. @request.session[:user_id] = 2
  357. get :thumbnail, :params => {
  358. :id => 16,
  359. :size => 260
  360. }
  361. end
  362. def test_thumbnail_should_return_404_for_non_image_attachment
  363. @request.session[:user_id] = 2
  364. get :thumbnail, :params => {
  365. :id => 15
  366. }
  367. assert_response 404
  368. end
  369. def test_thumbnail_should_return_404_if_thumbnail_generation_failed
  370. Attachment.any_instance.stubs(:thumbnail).returns(nil)
  371. @request.session[:user_id] = 2
  372. get :thumbnail, :params => {
  373. :id => 16
  374. }
  375. assert_response 404
  376. end
  377. def test_thumbnail_should_be_denied_without_permission
  378. get :thumbnail, :params => {
  379. :id => 16
  380. }
  381. assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fthumbnail%2F16'
  382. end
  383. else
  384. puts '(ImageMagick convert not available)'
  385. end
  386. def test_edit_all
  387. @request.session[:user_id] = 2
  388. get :edit_all, :params => {
  389. :object_type => 'issues',
  390. :object_id => '2'
  391. }
  392. assert_response :success
  393. assert_select 'form[action=?]', '/attachments/issues/2' do
  394. Issue.find(2).attachments.each do |attachment|
  395. assert_select "tr#attachment-#{attachment.id}"
  396. end
  397. assert_select 'tr#attachment-4' do
  398. assert_select 'input[name=?][value=?]', 'attachments[4][filename]', 'source.rb'
  399. assert_select 'input[name=?][value=?]', 'attachments[4][description]', 'This is a Ruby source file'
  400. end
  401. end
  402. # Link to the container in heading
  403. assert_select 'h2 a', :text => "Feature request #2"
  404. end
  405. def test_edit_all_with_invalid_container_class_should_return_404
  406. get :edit_all, :params => {
  407. :object_type => 'nuggets',
  408. :object_id => '3'
  409. }
  410. assert_response 404
  411. end
  412. def test_edit_all_with_invalid_object_should_return_404
  413. get :edit_all, :params => {
  414. :object_type => 'issues',
  415. :object_id => '999'
  416. }
  417. assert_response 404
  418. end
  419. def test_edit_all_for_object_that_is_not_visible_should_return_403
  420. get :edit_all, :params => {
  421. :object_type => 'issues',
  422. :object_id => '4'
  423. }
  424. assert_response 403
  425. end
  426. def test_update_all
  427. @request.session[:user_id] = 2
  428. patch :update_all, :params => {
  429. :object_type => 'issues',
  430. :object_id => '2',
  431. :attachments => {
  432. '1' => {
  433. :filename => 'newname.text',
  434. :description => ''
  435. },
  436. '4' => {
  437. :filename => 'newname.rb',
  438. :description => 'Renamed'
  439. },
  440. }
  441. }
  442. assert_response 302
  443. attachment = Attachment.find(4)
  444. assert_equal 'newname.rb', attachment.filename
  445. assert_equal 'Renamed', attachment.description
  446. end
  447. def test_update_all_with_failure
  448. @request.session[:user_id] = 2
  449. patch :update_all, :params => {
  450. :object_type => 'issues',
  451. :object_id => '3',
  452. :attachments => {
  453. '1' => {
  454. :filename => '',
  455. :description => ''
  456. },
  457. '4' => {
  458. :filename => 'newname.rb',
  459. :description => 'Renamed'
  460. },
  461. }
  462. }
  463. assert_response :success
  464. assert_select_error /file cannot be blank/i
  465. # The other attachment should not be updated
  466. attachment = Attachment.find(4)
  467. assert_equal 'source.rb', attachment.filename
  468. assert_equal 'This is a Ruby source file', attachment.description
  469. end
  470. def test_destroy_issue_attachment
  471. set_tmp_attachments_directory
  472. issue = Issue.find(3)
  473. @request.session[:user_id] = 2
  474. assert_difference 'issue.attachments.count', -1 do
  475. assert_difference 'Journal.count' do
  476. delete :destroy, :params => {
  477. :id => 1
  478. }
  479. assert_redirected_to '/projects/ecookbook'
  480. end
  481. end
  482. assert_nil Attachment.find_by_id(1)
  483. j = Journal.order('id DESC').first
  484. assert_equal issue, j.journalized
  485. assert_equal 'attachment', j.details.first.property
  486. assert_equal '1', j.details.first.prop_key
  487. assert_equal 'error281.txt', j.details.first.old_value
  488. assert_equal User.find(2), j.user
  489. end
  490. def test_destroy_wiki_page_attachment
  491. set_tmp_attachments_directory
  492. @request.session[:user_id] = 2
  493. assert_difference 'Attachment.count', -1 do
  494. delete :destroy, :params => {
  495. :id => 3
  496. }
  497. assert_response 302
  498. end
  499. end
  500. def test_destroy_project_attachment
  501. set_tmp_attachments_directory
  502. @request.session[:user_id] = 2
  503. assert_difference 'Attachment.count', -1 do
  504. delete :destroy, :params => {
  505. :id => 8
  506. }
  507. assert_response 302
  508. end
  509. end
  510. def test_destroy_version_attachment
  511. set_tmp_attachments_directory
  512. @request.session[:user_id] = 2
  513. assert_difference 'Attachment.count', -1 do
  514. delete :destroy, :params => {
  515. :id => 9
  516. }
  517. assert_response 302
  518. end
  519. end
  520. def test_destroy_version_attachment_with_issue_tracking_disabled
  521. Project.find(1).disable_module! :issue_tracking
  522. set_tmp_attachments_directory
  523. @request.session[:user_id] = 2
  524. assert_difference 'Attachment.count', -1 do
  525. delete :destroy, :params => {
  526. :id => 9
  527. }
  528. assert_response 302
  529. end
  530. end
  531. def test_destroy_without_permission
  532. set_tmp_attachments_directory
  533. assert_no_difference 'Attachment.count' do
  534. delete :destroy, :params => {
  535. :id => 3
  536. }
  537. end
  538. assert_response 302
  539. assert Attachment.find_by_id(3)
  540. end
  541. end