##// END OF EJS Templates
Allow to download javascript attachments again (#23376)....
Jean-Philippe Lang -
r15474:76bf2404d511
parent child
Show More
@@ -1,202 +1,206
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class AttachmentsController < ApplicationController
18 class AttachmentsController < ApplicationController
19 before_action :find_attachment, :only => [:show, :download, :thumbnail, :destroy]
19 before_action :find_attachment, :only => [:show, :download, :thumbnail, :destroy]
20 before_action :find_editable_attachments, :only => [:edit, :update]
20 before_action :find_editable_attachments, :only => [:edit, :update]
21 before_action :file_readable, :read_authorize, :only => [:show, :download, :thumbnail]
21 before_action :file_readable, :read_authorize, :only => [:show, :download, :thumbnail]
22 before_action :delete_authorize, :only => :destroy
22 before_action :delete_authorize, :only => :destroy
23 before_action :authorize_global, :only => :upload
23 before_action :authorize_global, :only => :upload
24
24
25 # Disable check for same origin requests for JS files, i.e. attachments with
26 # MIME type text/javascript.
27 skip_after_filter :verify_same_origin_request, :only => :download
28
25 accept_api_auth :show, :download, :thumbnail, :upload, :destroy
29 accept_api_auth :show, :download, :thumbnail, :upload, :destroy
26
30
27 def show
31 def show
28 respond_to do |format|
32 respond_to do |format|
29 format.html {
33 format.html {
30 if @attachment.is_diff?
34 if @attachment.is_diff?
31 @diff = File.read(@attachment.diskfile, :mode => "rb")
35 @diff = File.read(@attachment.diskfile, :mode => "rb")
32 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
36 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
33 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
37 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
34 # Save diff type as user preference
38 # Save diff type as user preference
35 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
39 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
36 User.current.pref[:diff_type] = @diff_type
40 User.current.pref[:diff_type] = @diff_type
37 User.current.preference.save
41 User.current.preference.save
38 end
42 end
39 render :action => 'diff'
43 render :action => 'diff'
40 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
44 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
41 @content = File.read(@attachment.diskfile, :mode => "rb")
45 @content = File.read(@attachment.diskfile, :mode => "rb")
42 render :action => 'file'
46 render :action => 'file'
43 elsif @attachment.is_image?
47 elsif @attachment.is_image?
44 render :action => 'image'
48 render :action => 'image'
45 else
49 else
46 render :action => 'other'
50 render :action => 'other'
47 end
51 end
48 }
52 }
49 format.api
53 format.api
50 end
54 end
51 end
55 end
52
56
53 def download
57 def download
54 if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project)
58 if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project)
55 @attachment.increment_download
59 @attachment.increment_download
56 end
60 end
57
61
58 if stale?(:etag => @attachment.digest)
62 if stale?(:etag => @attachment.digest)
59 # images are sent inline
63 # images are sent inline
60 send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
64 send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
61 :type => detect_content_type(@attachment),
65 :type => detect_content_type(@attachment),
62 :disposition => disposition(@attachment)
66 :disposition => disposition(@attachment)
63 end
67 end
64 end
68 end
65
69
66 def thumbnail
70 def thumbnail
67 if @attachment.thumbnailable? && tbnail = @attachment.thumbnail(:size => params[:size])
71 if @attachment.thumbnailable? && tbnail = @attachment.thumbnail(:size => params[:size])
68 if stale?(:etag => tbnail)
72 if stale?(:etag => tbnail)
69 send_file tbnail,
73 send_file tbnail,
70 :filename => filename_for_content_disposition(@attachment.filename),
74 :filename => filename_for_content_disposition(@attachment.filename),
71 :type => detect_content_type(@attachment),
75 :type => detect_content_type(@attachment),
72 :disposition => 'inline'
76 :disposition => 'inline'
73 end
77 end
74 else
78 else
75 # No thumbnail for the attachment or thumbnail could not be created
79 # No thumbnail for the attachment or thumbnail could not be created
76 head 404
80 head 404
77 end
81 end
78 end
82 end
79
83
80 def upload
84 def upload
81 # Make sure that API users get used to set this content type
85 # Make sure that API users get used to set this content type
82 # as it won't trigger Rails' automatic parsing of the request body for parameters
86 # as it won't trigger Rails' automatic parsing of the request body for parameters
83 unless request.content_type == 'application/octet-stream'
87 unless request.content_type == 'application/octet-stream'
84 head 406
88 head 406
85 return
89 return
86 end
90 end
87
91
88 @attachment = Attachment.new(:file => request.raw_post)
92 @attachment = Attachment.new(:file => request.raw_post)
89 @attachment.author = User.current
93 @attachment.author = User.current
90 @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16)
94 @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16)
91 @attachment.content_type = params[:content_type].presence
95 @attachment.content_type = params[:content_type].presence
92 saved = @attachment.save
96 saved = @attachment.save
93
97
94 respond_to do |format|
98 respond_to do |format|
95 format.js
99 format.js
96 format.api {
100 format.api {
97 if saved
101 if saved
98 render :action => 'upload', :status => :created
102 render :action => 'upload', :status => :created
99 else
103 else
100 render_validation_errors(@attachment)
104 render_validation_errors(@attachment)
101 end
105 end
102 }
106 }
103 end
107 end
104 end
108 end
105
109
106 def edit
110 def edit
107 end
111 end
108
112
109 def update
113 def update
110 if params[:attachments].is_a?(Hash)
114 if params[:attachments].is_a?(Hash)
111 if Attachment.update_attachments(@attachments, params[:attachments])
115 if Attachment.update_attachments(@attachments, params[:attachments])
112 redirect_back_or_default home_path
116 redirect_back_or_default home_path
113 return
117 return
114 end
118 end
115 end
119 end
116 render :action => 'edit'
120 render :action => 'edit'
117 end
121 end
118
122
119 def destroy
123 def destroy
120 if @attachment.container.respond_to?(:init_journal)
124 if @attachment.container.respond_to?(:init_journal)
121 @attachment.container.init_journal(User.current)
125 @attachment.container.init_journal(User.current)
122 end
126 end
123 if @attachment.container
127 if @attachment.container
124 # Make sure association callbacks are called
128 # Make sure association callbacks are called
125 @attachment.container.attachments.delete(@attachment)
129 @attachment.container.attachments.delete(@attachment)
126 else
130 else
127 @attachment.destroy
131 @attachment.destroy
128 end
132 end
129
133
130 respond_to do |format|
134 respond_to do |format|
131 format.html { redirect_to_referer_or project_path(@project) }
135 format.html { redirect_to_referer_or project_path(@project) }
132 format.js
136 format.js
133 format.api { render_api_ok }
137 format.api { render_api_ok }
134 end
138 end
135 end
139 end
136
140
137 private
141 private
138
142
139 def find_attachment
143 def find_attachment
140 @attachment = Attachment.find(params[:id])
144 @attachment = Attachment.find(params[:id])
141 # Show 404 if the filename in the url is wrong
145 # Show 404 if the filename in the url is wrong
142 raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
146 raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
143 @project = @attachment.project
147 @project = @attachment.project
144 rescue ActiveRecord::RecordNotFound
148 rescue ActiveRecord::RecordNotFound
145 render_404
149 render_404
146 end
150 end
147
151
148 def find_editable_attachments
152 def find_editable_attachments
149 klass = params[:object_type].to_s.singularize.classify.constantize rescue nil
153 klass = params[:object_type].to_s.singularize.classify.constantize rescue nil
150 unless klass && klass.reflect_on_association(:attachments)
154 unless klass && klass.reflect_on_association(:attachments)
151 render_404
155 render_404
152 return
156 return
153 end
157 end
154
158
155 @container = klass.find(params[:object_id])
159 @container = klass.find(params[:object_id])
156 if @container.respond_to?(:visible?) && !@container.visible?
160 if @container.respond_to?(:visible?) && !@container.visible?
157 render_403
161 render_403
158 return
162 return
159 end
163 end
160 @attachments = @container.attachments.select(&:editable?)
164 @attachments = @container.attachments.select(&:editable?)
161 if @container.respond_to?(:project)
165 if @container.respond_to?(:project)
162 @project = @container.project
166 @project = @container.project
163 end
167 end
164 render_404 if @attachments.empty?
168 render_404 if @attachments.empty?
165 rescue ActiveRecord::RecordNotFound
169 rescue ActiveRecord::RecordNotFound
166 render_404
170 render_404
167 end
171 end
168
172
169 # Checks that the file exists and is readable
173 # Checks that the file exists and is readable
170 def file_readable
174 def file_readable
171 if @attachment.readable?
175 if @attachment.readable?
172 true
176 true
173 else
177 else
174 logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable."
178 logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable."
175 render_404
179 render_404
176 end
180 end
177 end
181 end
178
182
179 def read_authorize
183 def read_authorize
180 @attachment.visible? ? true : deny_access
184 @attachment.visible? ? true : deny_access
181 end
185 end
182
186
183 def delete_authorize
187 def delete_authorize
184 @attachment.deletable? ? true : deny_access
188 @attachment.deletable? ? true : deny_access
185 end
189 end
186
190
187 def detect_content_type(attachment)
191 def detect_content_type(attachment)
188 content_type = attachment.content_type
192 content_type = attachment.content_type
189 if content_type.blank? || content_type == "application/octet-stream"
193 if content_type.blank? || content_type == "application/octet-stream"
190 content_type = Redmine::MimeType.of(attachment.filename)
194 content_type = Redmine::MimeType.of(attachment.filename)
191 end
195 end
192 content_type.to_s
196 content_type.to_s
193 end
197 end
194
198
195 def disposition(attachment)
199 def disposition(attachment)
196 if attachment.is_image? || attachment.is_pdf?
200 if attachment.is_image? || attachment.is_pdf?
197 'inline'
201 'inline'
198 else
202 else
199 'attachment'
203 'attachment'
200 end
204 end
201 end
205 end
202 end
206 end
@@ -1,470 +1,483
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
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
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.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require File.expand_path('../../test_helper', __FILE__)
20 require File.expand_path('../../test_helper', __FILE__)
21
21
22 class AttachmentsControllerTest < Redmine::ControllerTest
22 class AttachmentsControllerTest < Redmine::ControllerTest
23 fixtures :users, :projects, :roles, :members, :member_roles,
23 fixtures :users, :projects, :roles, :members, :member_roles,
24 :enabled_modules, :issues, :trackers, :attachments,
24 :enabled_modules, :issues, :trackers, :attachments,
25 :versions, :wiki_pages, :wikis, :documents
25 :versions, :wiki_pages, :wikis, :documents
26
26
27 def setup
27 def setup
28 User.current = nil
28 User.current = nil
29 set_fixtures_attachments_directory
29 set_fixtures_attachments_directory
30 end
30 end
31
31
32 def teardown
32 def teardown
33 set_tmp_attachments_directory
33 set_tmp_attachments_directory
34 end
34 end
35
35
36 def test_show_diff
36 def test_show_diff
37 ['inline', 'sbs'].each do |dt|
37 ['inline', 'sbs'].each do |dt|
38 # 060719210727_changeset_utf8.diff
38 # 060719210727_changeset_utf8.diff
39 get :show, :id => 14, :type => dt
39 get :show, :id => 14, :type => dt
40 assert_response :success
40 assert_response :success
41
41
42 assert_equal 'text/html', @response.content_type
42 assert_equal 'text/html', @response.content_type
43 assert_select 'th.filename', :text => /issues_controller.rb\t\(rΓ©vision 1484\)/
43 assert_select 'th.filename', :text => /issues_controller.rb\t\(rΓ©vision 1484\)/
44 assert_select 'td.line-code', :text => /Demande créée avec succès/
44 assert_select 'td.line-code', :text => /Demande créée avec succès/
45 end
45 end
46 set_tmp_attachments_directory
46 set_tmp_attachments_directory
47 end
47 end
48
48
49 def test_show_diff_replace_cannot_convert_content
49 def test_show_diff_replace_cannot_convert_content
50 with_settings :repositories_encodings => 'UTF-8' do
50 with_settings :repositories_encodings => 'UTF-8' do
51 ['inline', 'sbs'].each do |dt|
51 ['inline', 'sbs'].each do |dt|
52 # 060719210727_changeset_iso8859-1.diff
52 # 060719210727_changeset_iso8859-1.diff
53 get :show, :id => 5, :type => dt
53 get :show, :id => 5, :type => dt
54 assert_response :success
54 assert_response :success
55
55
56 assert_equal 'text/html', @response.content_type
56 assert_equal 'text/html', @response.content_type
57 assert_select 'th.filename', :text => /issues_controller.rb\t\(r\?vision 1484\)/
57 assert_select 'th.filename', :text => /issues_controller.rb\t\(r\?vision 1484\)/
58 assert_select 'td.line-code', :text => /Demande cr\?\?e avec succ\?s/
58 assert_select 'td.line-code', :text => /Demande cr\?\?e avec succ\?s/
59 end
59 end
60 end
60 end
61 set_tmp_attachments_directory
61 set_tmp_attachments_directory
62 end
62 end
63
63
64 def test_show_diff_latin_1
64 def test_show_diff_latin_1
65 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
65 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
66 ['inline', 'sbs'].each do |dt|
66 ['inline', 'sbs'].each do |dt|
67 # 060719210727_changeset_iso8859-1.diff
67 # 060719210727_changeset_iso8859-1.diff
68 get :show, :id => 5, :type => dt
68 get :show, :id => 5, :type => dt
69 assert_response :success
69 assert_response :success
70
70
71 assert_equal 'text/html', @response.content_type
71 assert_equal 'text/html', @response.content_type
72 assert_select 'th.filename', :text => /issues_controller.rb\t\(rΓ©vision 1484\)/
72 assert_select 'th.filename', :text => /issues_controller.rb\t\(rΓ©vision 1484\)/
73 assert_select 'td.line-code', :text => /Demande créée avec succès/
73 assert_select 'td.line-code', :text => /Demande créée avec succès/
74 end
74 end
75 end
75 end
76 set_tmp_attachments_directory
76 set_tmp_attachments_directory
77 end
77 end
78
78
79 def test_save_diff_type
79 def test_save_diff_type
80 user1 = User.find(1)
80 user1 = User.find(1)
81 user1.pref[:diff_type] = nil
81 user1.pref[:diff_type] = nil
82 user1.preference.save
82 user1.preference.save
83 user = User.find(1)
83 user = User.find(1)
84 assert_nil user.pref[:diff_type]
84 assert_nil user.pref[:diff_type]
85 @request.session[:user_id] = 1 # admin
85 @request.session[:user_id] = 1 # admin
86
86
87 get :show, :id => 5
87 get :show, :id => 5
88 assert_response :success
88 assert_response :success
89 user.reload
89 user.reload
90 assert_equal "inline", user.pref[:diff_type]
90 assert_equal "inline", user.pref[:diff_type]
91
91
92 get :show, :id => 5, :type => 'sbs'
92 get :show, :id => 5, :type => 'sbs'
93 assert_response :success
93 assert_response :success
94 user.reload
94 user.reload
95 assert_equal "sbs", user.pref[:diff_type]
95 assert_equal "sbs", user.pref[:diff_type]
96 end
96 end
97
97
98 def test_diff_show_filename_in_mercurial_export
98 def test_diff_show_filename_in_mercurial_export
99 set_tmp_attachments_directory
99 set_tmp_attachments_directory
100 a = Attachment.new(:container => Issue.find(1),
100 a = Attachment.new(:container => Issue.find(1),
101 :file => uploaded_test_file("hg-export.diff", "text/plain"),
101 :file => uploaded_test_file("hg-export.diff", "text/plain"),
102 :author => User.find(1))
102 :author => User.find(1))
103 assert a.save
103 assert a.save
104 assert_equal 'hg-export.diff', a.filename
104 assert_equal 'hg-export.diff', a.filename
105
105
106 get :show, :id => a.id, :type => 'inline'
106 get :show, :id => a.id, :type => 'inline'
107 assert_response :success
107 assert_response :success
108 assert_equal 'text/html', @response.content_type
108 assert_equal 'text/html', @response.content_type
109 assert_select 'th.filename', :text => 'test1.txt'
109 assert_select 'th.filename', :text => 'test1.txt'
110 end
110 end
111
111
112 def test_show_text_file
112 def test_show_text_file
113 get :show, :id => 4
113 get :show, :id => 4
114 assert_response :success
114 assert_response :success
115 assert_equal 'text/html', @response.content_type
115 assert_equal 'text/html', @response.content_type
116 set_tmp_attachments_directory
116 set_tmp_attachments_directory
117 end
117 end
118
118
119 def test_show_text_file_utf_8
119 def test_show_text_file_utf_8
120 set_tmp_attachments_directory
120 set_tmp_attachments_directory
121 a = Attachment.new(:container => Issue.find(1),
121 a = Attachment.new(:container => Issue.find(1),
122 :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
122 :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
123 :author => User.find(1))
123 :author => User.find(1))
124 assert a.save
124 assert a.save
125 assert_equal 'japanese-utf-8.txt', a.filename
125 assert_equal 'japanese-utf-8.txt', a.filename
126
126
127 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
127 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
128
128
129 get :show, :id => a.id
129 get :show, :id => a.id
130 assert_response :success
130 assert_response :success
131 assert_equal 'text/html', @response.content_type
131 assert_equal 'text/html', @response.content_type
132 assert_select 'tr#L1' do
132 assert_select 'tr#L1' do
133 assert_select 'th.line-num', :text => '1'
133 assert_select 'th.line-num', :text => '1'
134 assert_select 'td', :text => /#{str_japanese}/
134 assert_select 'td', :text => /#{str_japanese}/
135 end
135 end
136 end
136 end
137
137
138 def test_show_text_file_replace_cannot_convert_content
138 def test_show_text_file_replace_cannot_convert_content
139 set_tmp_attachments_directory
139 set_tmp_attachments_directory
140 with_settings :repositories_encodings => 'UTF-8' do
140 with_settings :repositories_encodings => 'UTF-8' do
141 a = Attachment.new(:container => Issue.find(1),
141 a = Attachment.new(:container => Issue.find(1),
142 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
142 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
143 :author => User.find(1))
143 :author => User.find(1))
144 assert a.save
144 assert a.save
145 assert_equal 'iso8859-1.txt', a.filename
145 assert_equal 'iso8859-1.txt', a.filename
146
146
147 get :show, :id => a.id
147 get :show, :id => a.id
148 assert_response :success
148 assert_response :success
149 assert_equal 'text/html', @response.content_type
149 assert_equal 'text/html', @response.content_type
150 assert_select 'tr#L7' do
150 assert_select 'tr#L7' do
151 assert_select 'th.line-num', :text => '7'
151 assert_select 'th.line-num', :text => '7'
152 assert_select 'td', :text => /Demande cr\?\?e avec succ\?s/
152 assert_select 'td', :text => /Demande cr\?\?e avec succ\?s/
153 end
153 end
154 end
154 end
155 end
155 end
156
156
157 def test_show_text_file_latin_1
157 def test_show_text_file_latin_1
158 set_tmp_attachments_directory
158 set_tmp_attachments_directory
159 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
159 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
160 a = Attachment.new(:container => Issue.find(1),
160 a = Attachment.new(:container => Issue.find(1),
161 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
161 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
162 :author => User.find(1))
162 :author => User.find(1))
163 assert a.save
163 assert a.save
164 assert_equal 'iso8859-1.txt', a.filename
164 assert_equal 'iso8859-1.txt', a.filename
165
165
166 get :show, :id => a.id
166 get :show, :id => a.id
167 assert_response :success
167 assert_response :success
168 assert_equal 'text/html', @response.content_type
168 assert_equal 'text/html', @response.content_type
169 assert_select 'tr#L7' do
169 assert_select 'tr#L7' do
170 assert_select 'th.line-num', :text => '7'
170 assert_select 'th.line-num', :text => '7'
171 assert_select 'td', :text => /Demande créée avec succès/
171 assert_select 'td', :text => /Demande créée avec succès/
172 end
172 end
173 end
173 end
174 end
174 end
175
175
176 def test_show_text_file_should_show_other_if_too_big
176 def test_show_text_file_should_show_other_if_too_big
177 @request.session[:user_id] = 2
177 @request.session[:user_id] = 2
178 with_settings :file_max_size_displayed => 512 do
178 with_settings :file_max_size_displayed => 512 do
179 Attachment.find(4).update_attribute :filesize, 754.kilobyte
179 Attachment.find(4).update_attribute :filesize, 754.kilobyte
180 get :show, :id => 4
180 get :show, :id => 4
181 assert_response :success
181 assert_response :success
182 assert_equal 'text/html', @response.content_type
182 assert_equal 'text/html', @response.content_type
183 assert_select '.nodata', :text => 'No preview available'
183 assert_select '.nodata', :text => 'No preview available'
184 end
184 end
185 set_tmp_attachments_directory
185 set_tmp_attachments_directory
186 end
186 end
187
187
188 def test_show_image
188 def test_show_image
189 @request.session[:user_id] = 2
189 @request.session[:user_id] = 2
190 get :show, :id => 16
190 get :show, :id => 16
191 assert_response :success
191 assert_response :success
192 assert_equal 'text/html', @response.content_type
192 assert_equal 'text/html', @response.content_type
193 assert_select 'img.filecontent', :src => attachments(:attachments_010).filename
193 assert_select 'img.filecontent', :src => attachments(:attachments_010).filename
194 end
194 end
195
195
196 def test_show_other
196 def test_show_other
197 @request.session[:user_id] = 2
197 @request.session[:user_id] = 2
198 get :show, :id => 6
198 get :show, :id => 6
199 assert_equal 'text/html', @response.content_type
199 assert_equal 'text/html', @response.content_type
200 assert_select '.nodata', :text => 'No preview available'
200 assert_select '.nodata', :text => 'No preview available'
201 set_tmp_attachments_directory
201 set_tmp_attachments_directory
202 end
202 end
203
203
204 def test_show_file_from_private_issue_without_permission
204 def test_show_file_from_private_issue_without_permission
205 get :show, :id => 15
205 get :show, :id => 15
206 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
206 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
207 set_tmp_attachments_directory
207 set_tmp_attachments_directory
208 end
208 end
209
209
210 def test_show_file_from_private_issue_with_permission
210 def test_show_file_from_private_issue_with_permission
211 @request.session[:user_id] = 2
211 @request.session[:user_id] = 2
212 get :show, :id => 15
212 get :show, :id => 15
213 assert_response :success
213 assert_response :success
214 assert_select 'h2', :text => /private.diff/
214 assert_select 'h2', :text => /private.diff/
215 set_tmp_attachments_directory
215 set_tmp_attachments_directory
216 end
216 end
217
217
218 def test_show_file_without_container_should_be_allowed_to_author
218 def test_show_file_without_container_should_be_allowed_to_author
219 set_tmp_attachments_directory
219 set_tmp_attachments_directory
220 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
220 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
221
221
222 @request.session[:user_id] = 2
222 @request.session[:user_id] = 2
223 get :show, :id => attachment.id
223 get :show, :id => attachment.id
224 assert_response 200
224 assert_response 200
225 end
225 end
226
226
227 def test_show_file_without_container_should_be_denied_to_other_users
227 def test_show_file_without_container_should_be_denied_to_other_users
228 set_tmp_attachments_directory
228 set_tmp_attachments_directory
229 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
229 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
230
230
231 @request.session[:user_id] = 3
231 @request.session[:user_id] = 3
232 get :show, :id => attachment.id
232 get :show, :id => attachment.id
233 assert_response 403
233 assert_response 403
234 end
234 end
235
235
236 def test_show_invalid_should_respond_with_404
236 def test_show_invalid_should_respond_with_404
237 get :show, :id => 999
237 get :show, :id => 999
238 assert_response 404
238 assert_response 404
239 end
239 end
240
240
241 def test_download_text_file
241 def test_download_text_file
242 get :download, :id => 4
242 get :download, :id => 4
243 assert_response :success
243 assert_response :success
244 assert_equal 'application/x-ruby', @response.content_type
244 assert_equal 'application/x-ruby', @response.content_type
245 etag = @response.etag
245 etag = @response.etag
246 assert_not_nil etag
246 assert_not_nil etag
247
247
248 @request.env["HTTP_IF_NONE_MATCH"] = etag
248 @request.env["HTTP_IF_NONE_MATCH"] = etag
249 get :download, :id => 4
249 get :download, :id => 4
250 assert_response 304
250 assert_response 304
251
251
252 set_tmp_attachments_directory
252 set_tmp_attachments_directory
253 end
253 end
254
254
255 def test_download_js_file
256 set_tmp_attachments_directory
257 attachment = Attachment.create!(
258 :file => mock_file_with_options(:original_filename => "hello.js", :content_type => "text/javascript"),
259 :author_id => 2,
260 :container => Issue.find(1)
261 )
262
263 get :download, :id => attachment.id
264 assert_response :success
265 assert_equal 'text/javascript', @response.content_type
266 end
267
255 def test_download_version_file_with_issue_tracking_disabled
268 def test_download_version_file_with_issue_tracking_disabled
256 Project.find(1).disable_module! :issue_tracking
269 Project.find(1).disable_module! :issue_tracking
257 get :download, :id => 9
270 get :download, :id => 9
258 assert_response :success
271 assert_response :success
259 end
272 end
260
273
261 def test_download_should_assign_content_type_if_blank
274 def test_download_should_assign_content_type_if_blank
262 Attachment.find(4).update_attribute(:content_type, '')
275 Attachment.find(4).update_attribute(:content_type, '')
263
276
264 get :download, :id => 4
277 get :download, :id => 4
265 assert_response :success
278 assert_response :success
266 assert_equal 'text/x-ruby', @response.content_type
279 assert_equal 'text/x-ruby', @response.content_type
267 set_tmp_attachments_directory
280 set_tmp_attachments_directory
268 end
281 end
269
282
270 def test_download_should_assign_better_content_type_than_application_octet_stream
283 def test_download_should_assign_better_content_type_than_application_octet_stream
271 Attachment.find(4).update! :content_type => "application/octet-stream"
284 Attachment.find(4).update! :content_type => "application/octet-stream"
272
285
273 get :download, :id => 4
286 get :download, :id => 4
274 assert_response :success
287 assert_response :success
275 assert_equal 'text/x-ruby', @response.content_type
288 assert_equal 'text/x-ruby', @response.content_type
276 set_tmp_attachments_directory
289 set_tmp_attachments_directory
277 end
290 end
278
291
279 def test_download_missing_file
292 def test_download_missing_file
280 get :download, :id => 2
293 get :download, :id => 2
281 assert_response 404
294 assert_response 404
282 set_tmp_attachments_directory
295 set_tmp_attachments_directory
283 end
296 end
284
297
285 def test_download_should_be_denied_without_permission
298 def test_download_should_be_denied_without_permission
286 get :download, :id => 7
299 get :download, :id => 7
287 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
300 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
288 set_tmp_attachments_directory
301 set_tmp_attachments_directory
289 end
302 end
290
303
291 if convert_installed?
304 if convert_installed?
292 def test_thumbnail
305 def test_thumbnail
293 Attachment.clear_thumbnails
306 Attachment.clear_thumbnails
294 @request.session[:user_id] = 2
307 @request.session[:user_id] = 2
295 get :thumbnail, :id => 16
308 get :thumbnail, :id => 16
296 assert_response :success
309 assert_response :success
297 assert_equal 'image/png', response.content_type
310 assert_equal 'image/png', response.content_type
298
311
299 etag = @response.etag
312 etag = @response.etag
300 assert_not_nil etag
313 assert_not_nil etag
301
314
302 @request.env["HTTP_IF_NONE_MATCH"] = etag
315 @request.env["HTTP_IF_NONE_MATCH"] = etag
303 get :thumbnail, :id => 16
316 get :thumbnail, :id => 16
304 assert_response 304
317 assert_response 304
305 end
318 end
306
319
307 def test_thumbnail_should_not_exceed_maximum_size
320 def test_thumbnail_should_not_exceed_maximum_size
308 Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 800}
321 Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 800}
309
322
310 @request.session[:user_id] = 2
323 @request.session[:user_id] = 2
311 get :thumbnail, :id => 16, :size => 2000
324 get :thumbnail, :id => 16, :size => 2000
312 end
325 end
313
326
314 def test_thumbnail_should_round_size
327 def test_thumbnail_should_round_size
315 Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 250}
328 Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 250}
316
329
317 @request.session[:user_id] = 2
330 @request.session[:user_id] = 2
318 get :thumbnail, :id => 16, :size => 260
331 get :thumbnail, :id => 16, :size => 260
319 end
332 end
320
333
321 def test_thumbnail_should_return_404_for_non_image_attachment
334 def test_thumbnail_should_return_404_for_non_image_attachment
322 @request.session[:user_id] = 2
335 @request.session[:user_id] = 2
323
336
324 get :thumbnail, :id => 15
337 get :thumbnail, :id => 15
325 assert_response 404
338 assert_response 404
326 end
339 end
327
340
328 def test_thumbnail_should_return_404_if_thumbnail_generation_failed
341 def test_thumbnail_should_return_404_if_thumbnail_generation_failed
329 Attachment.any_instance.stubs(:thumbnail).returns(nil)
342 Attachment.any_instance.stubs(:thumbnail).returns(nil)
330 @request.session[:user_id] = 2
343 @request.session[:user_id] = 2
331
344
332 get :thumbnail, :id => 16
345 get :thumbnail, :id => 16
333 assert_response 404
346 assert_response 404
334 end
347 end
335
348
336 def test_thumbnail_should_be_denied_without_permission
349 def test_thumbnail_should_be_denied_without_permission
337 get :thumbnail, :id => 16
350 get :thumbnail, :id => 16
338 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fthumbnail%2F16'
351 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fthumbnail%2F16'
339 end
352 end
340 else
353 else
341 puts '(ImageMagick convert not available)'
354 puts '(ImageMagick convert not available)'
342 end
355 end
343
356
344 def test_edit
357 def test_edit
345 @request.session[:user_id] = 2
358 @request.session[:user_id] = 2
346 get :edit, :object_type => 'issues', :object_id => '2'
359 get :edit, :object_type => 'issues', :object_id => '2'
347 assert_response :success
360 assert_response :success
348
361
349 assert_select 'form[action=?]', '/attachments/issues/2' do
362 assert_select 'form[action=?]', '/attachments/issues/2' do
350 Issue.find(2).attachments.each do |attachment|
363 Issue.find(2).attachments.each do |attachment|
351 assert_select "tr#attachment-#{attachment.id}"
364 assert_select "tr#attachment-#{attachment.id}"
352 end
365 end
353
366
354 assert_select 'tr#attachment-4' do
367 assert_select 'tr#attachment-4' do
355 assert_select 'input[name=?][value=?]', 'attachments[4][filename]', 'source.rb'
368 assert_select 'input[name=?][value=?]', 'attachments[4][filename]', 'source.rb'
356 assert_select 'input[name=?][value=?]', 'attachments[4][description]', 'This is a Ruby source file'
369 assert_select 'input[name=?][value=?]', 'attachments[4][description]', 'This is a Ruby source file'
357 end
370 end
358 end
371 end
359 end
372 end
360
373
361 def test_edit_invalid_container_class_should_return_404
374 def test_edit_invalid_container_class_should_return_404
362 get :edit, :object_type => 'nuggets', :object_id => '3'
375 get :edit, :object_type => 'nuggets', :object_id => '3'
363 assert_response 404
376 assert_response 404
364 end
377 end
365
378
366 def test_edit_invalid_object_should_return_404
379 def test_edit_invalid_object_should_return_404
367 get :edit, :object_type => 'issues', :object_id => '999'
380 get :edit, :object_type => 'issues', :object_id => '999'
368 assert_response 404
381 assert_response 404
369 end
382 end
370
383
371 def test_edit_for_object_that_is_not_visible_should_return_403
384 def test_edit_for_object_that_is_not_visible_should_return_403
372 get :edit, :object_type => 'issues', :object_id => '4'
385 get :edit, :object_type => 'issues', :object_id => '4'
373 assert_response 403
386 assert_response 403
374 end
387 end
375
388
376 def test_update
389 def test_update
377 @request.session[:user_id] = 2
390 @request.session[:user_id] = 2
378 patch :update, :object_type => 'issues', :object_id => '2', :attachments => {
391 patch :update, :object_type => 'issues', :object_id => '2', :attachments => {
379 '1' => {:filename => 'newname.text', :description => ''},
392 '1' => {:filename => 'newname.text', :description => ''},
380 '4' => {:filename => 'newname.rb', :description => 'Renamed'},
393 '4' => {:filename => 'newname.rb', :description => 'Renamed'},
381 }
394 }
382
395
383 assert_response 302
396 assert_response 302
384 attachment = Attachment.find(4)
397 attachment = Attachment.find(4)
385 assert_equal 'newname.rb', attachment.filename
398 assert_equal 'newname.rb', attachment.filename
386 assert_equal 'Renamed', attachment.description
399 assert_equal 'Renamed', attachment.description
387 end
400 end
388
401
389 def test_update_with_failure
402 def test_update_with_failure
390 @request.session[:user_id] = 2
403 @request.session[:user_id] = 2
391 patch :update, :object_type => 'issues', :object_id => '3', :attachments => {
404 patch :update, :object_type => 'issues', :object_id => '3', :attachments => {
392 '1' => {:filename => '', :description => ''},
405 '1' => {:filename => '', :description => ''},
393 '4' => {:filename => 'newname.rb', :description => 'Renamed'},
406 '4' => {:filename => 'newname.rb', :description => 'Renamed'},
394 }
407 }
395
408
396 assert_response :success
409 assert_response :success
397 assert_select_error /file cannot be blank/i
410 assert_select_error /file cannot be blank/i
398
411
399 # The other attachment should not be updated
412 # The other attachment should not be updated
400 attachment = Attachment.find(4)
413 attachment = Attachment.find(4)
401 assert_equal 'source.rb', attachment.filename
414 assert_equal 'source.rb', attachment.filename
402 assert_equal 'This is a Ruby source file', attachment.description
415 assert_equal 'This is a Ruby source file', attachment.description
403 end
416 end
404
417
405 def test_destroy_issue_attachment
418 def test_destroy_issue_attachment
406 set_tmp_attachments_directory
419 set_tmp_attachments_directory
407 issue = Issue.find(3)
420 issue = Issue.find(3)
408 @request.session[:user_id] = 2
421 @request.session[:user_id] = 2
409
422
410 assert_difference 'issue.attachments.count', -1 do
423 assert_difference 'issue.attachments.count', -1 do
411 assert_difference 'Journal.count' do
424 assert_difference 'Journal.count' do
412 delete :destroy, :id => 1
425 delete :destroy, :id => 1
413 assert_redirected_to '/projects/ecookbook'
426 assert_redirected_to '/projects/ecookbook'
414 end
427 end
415 end
428 end
416 assert_nil Attachment.find_by_id(1)
429 assert_nil Attachment.find_by_id(1)
417 j = Journal.order('id DESC').first
430 j = Journal.order('id DESC').first
418 assert_equal issue, j.journalized
431 assert_equal issue, j.journalized
419 assert_equal 'attachment', j.details.first.property
432 assert_equal 'attachment', j.details.first.property
420 assert_equal '1', j.details.first.prop_key
433 assert_equal '1', j.details.first.prop_key
421 assert_equal 'error281.txt', j.details.first.old_value
434 assert_equal 'error281.txt', j.details.first.old_value
422 assert_equal User.find(2), j.user
435 assert_equal User.find(2), j.user
423 end
436 end
424
437
425 def test_destroy_wiki_page_attachment
438 def test_destroy_wiki_page_attachment
426 set_tmp_attachments_directory
439 set_tmp_attachments_directory
427 @request.session[:user_id] = 2
440 @request.session[:user_id] = 2
428 assert_difference 'Attachment.count', -1 do
441 assert_difference 'Attachment.count', -1 do
429 delete :destroy, :id => 3
442 delete :destroy, :id => 3
430 assert_response 302
443 assert_response 302
431 end
444 end
432 end
445 end
433
446
434 def test_destroy_project_attachment
447 def test_destroy_project_attachment
435 set_tmp_attachments_directory
448 set_tmp_attachments_directory
436 @request.session[:user_id] = 2
449 @request.session[:user_id] = 2
437 assert_difference 'Attachment.count', -1 do
450 assert_difference 'Attachment.count', -1 do
438 delete :destroy, :id => 8
451 delete :destroy, :id => 8
439 assert_response 302
452 assert_response 302
440 end
453 end
441 end
454 end
442
455
443 def test_destroy_version_attachment
456 def test_destroy_version_attachment
444 set_tmp_attachments_directory
457 set_tmp_attachments_directory
445 @request.session[:user_id] = 2
458 @request.session[:user_id] = 2
446 assert_difference 'Attachment.count', -1 do
459 assert_difference 'Attachment.count', -1 do
447 delete :destroy, :id => 9
460 delete :destroy, :id => 9
448 assert_response 302
461 assert_response 302
449 end
462 end
450 end
463 end
451
464
452 def test_destroy_version_attachment_with_issue_tracking_disabled
465 def test_destroy_version_attachment_with_issue_tracking_disabled
453 Project.find(1).disable_module! :issue_tracking
466 Project.find(1).disable_module! :issue_tracking
454 set_tmp_attachments_directory
467 set_tmp_attachments_directory
455 @request.session[:user_id] = 2
468 @request.session[:user_id] = 2
456 assert_difference 'Attachment.count', -1 do
469 assert_difference 'Attachment.count', -1 do
457 delete :destroy, :id => 9
470 delete :destroy, :id => 9
458 assert_response 302
471 assert_response 302
459 end
472 end
460 end
473 end
461
474
462 def test_destroy_without_permission
475 def test_destroy_without_permission
463 set_tmp_attachments_directory
476 set_tmp_attachments_directory
464 assert_no_difference 'Attachment.count' do
477 assert_no_difference 'Attachment.count' do
465 delete :destroy, :id => 3
478 delete :destroy, :id => 3
466 end
479 end
467 assert_response 302
480 assert_response 302
468 assert Attachment.find_by_id(3)
481 assert Attachment.find_by_id(3)
469 end
482 end
470 end
483 end
General Comments 0
You need to be logged in to leave comments. Login now