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