##// END OF EJS Templates
Resourcified attachments....
Jean-Philippe Lang -
r7828:885605b439de
parent child
Show More
@@ -1,95 +1,95
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class AttachmentsController < ApplicationController
19 19 before_filter :find_project
20 20 before_filter :file_readable, :read_authorize, :except => :destroy
21 21 before_filter :delete_authorize, :only => :destroy
22 22
23 23 accept_api_auth :show, :download
24 24
25 25 def show
26 26 respond_to do |format|
27 27 format.html {
28 28 if @attachment.is_diff?
29 29 @diff = File.new(@attachment.diskfile, "rb").read
30 30 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
31 31 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
32 32 render :action => 'diff'
33 33 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
34 34 @content = File.new(@attachment.diskfile, "rb").read
35 35 render :action => 'file'
36 36 else
37 37 download
38 38 end
39 39 }
40 40 format.api
41 41 end
42 42 end
43 43
44 44 def download
45 45 if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project)
46 46 @attachment.increment_download
47 47 end
48 48
49 49 # images are sent inline
50 50 send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
51 51 :type => detect_content_type(@attachment),
52 52 :disposition => (@attachment.image? ? 'inline' : 'attachment')
53 53
54 54 end
55 55
56 verify :method => :post, :only => :destroy
56 verify :method => :delete, :only => :destroy
57 57 def destroy
58 58 # Make sure association callbacks are called
59 59 @attachment.container.attachments.delete(@attachment)
60 60 redirect_to :back
61 61 rescue ::ActionController::RedirectBackError
62 62 redirect_to :controller => 'projects', :action => 'show', :id => @project
63 63 end
64 64
65 65 private
66 66 def find_project
67 67 @attachment = Attachment.find(params[:id])
68 68 # Show 404 if the filename in the url is wrong
69 69 raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
70 70 @project = @attachment.project
71 71 rescue ActiveRecord::RecordNotFound
72 72 render_404
73 73 end
74 74
75 75 # Checks that the file exists and is readable
76 76 def file_readable
77 77 @attachment.readable? ? true : render_404
78 78 end
79 79
80 80 def read_authorize
81 81 @attachment.visible? ? true : deny_access
82 82 end
83 83
84 84 def delete_authorize
85 85 @attachment.deletable? ? true : deny_access
86 86 end
87 87
88 88 def detect_content_type(attachment)
89 89 content_type = attachment.content_type
90 90 if content_type.blank?
91 91 content_type = Redmine::MimeType.of(attachment.filename)
92 92 end
93 93 content_type.to_s
94 94 end
95 95 end
@@ -1,18 +1,18
1 1 <div class="attachments">
2 2 <% for attachment in attachments %>
3 3 <p><%= link_to_attachment attachment, :class => 'icon icon-attachment' -%>
4 4 <%= h(" - #{attachment.description}") unless attachment.description.blank? %>
5 5 <span class="size">(<%= number_to_human_size attachment.filesize %>)</span>
6 6 <% if options[:deletable] %>
7 <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment},
7 <%= link_to image_tag('delete.png'), attachment_path(attachment),
8 8 :confirm => l(:text_are_you_sure),
9 :method => :post,
9 :method => :delete,
10 10 :class => 'delete',
11 11 :title => l(:button_delete) %>
12 12 <% end %>
13 13 <% if options[:author] %>
14 14 <span class="author"><%= h(attachment.author) %>, <%= format_time(attachment.created_on) %></span>
15 15 <% end %>
16 16 </p>
17 17 <% end %>
18 18 </div>
@@ -1,46 +1,46
1 1 <div class="contextual">
2 2 <%= link_to(l(:label_attachment_new), new_project_file_path(@project), :class => 'icon icon-add') if User.current.allowed_to?(:manage_files, @project) %>
3 3 </div>
4 4
5 5 <h2><%=l(:label_attachment_plural)%></h2>
6 6
7 7 <% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>
8 8
9 9 <table class="list files">
10 10 <thead><tr>
11 11 <%= sort_header_tag('filename', :caption => l(:field_filename)) %>
12 12 <%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
13 13 <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
14 14 <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
15 15 <th>MD5</th>
16 16 <th></th>
17 17 </tr></thead>
18 18 <tbody>
19 19 <% @containers.each do |container| %>
20 20 <% next if container.attachments.empty? -%>
21 21 <% if container.is_a?(Version) -%>
22 22 <tr>
23 23 <th colspan="6" align="left">
24 24 <%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
25 25 </th>
26 26 </tr>
27 27 <% end -%>
28 28 <% container.attachments.each do |file| %>
29 29 <tr class="file <%= cycle("odd", "even") %>">
30 30 <td class="filename"><%= link_to_attachment file, :download => true, :title => file.description %></td>
31 31 <td class="created_on"><%= format_time(file.created_on) %></td>
32 32 <td class="filesize"><%= number_to_human_size(file.filesize) %></td>
33 33 <td class="downloads"><%= file.downloads %></td>
34 34 <td class="digest"><%= file.digest %></td>
35 35 <td align="center">
36 <%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file},
37 :confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %>
36 <%= link_to(image_tag('delete.png'), attachment_path(file),
37 :confirm => l(:text_are_you_sure), :method => :delete) if delete_allowed %>
38 38 </td>
39 39 </tr>
40 40 <% end
41 41 reset_cycle %>
42 42 <% end %>
43 43 </tbody>
44 44 </table>
45 45
46 46 <% html_title(l(:label_attachment_plural)) -%>
@@ -1,258 +1,258
1 1 ActionController::Routing::Routes.draw do |map|
2 2 # Add your own custom routes here.
3 3 # The priority is based upon order of creation: first created -> highest priority.
4 4
5 5 # Here's a sample route:
6 6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 7 # Keep in mind you can assign values other than :controller and :action
8 8
9 9 map.home '', :controller => 'welcome'
10 10
11 11 map.signin 'login', :controller => 'account', :action => 'login'
12 12 map.signout 'logout', :controller => 'account', :action => 'logout'
13 13
14 14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
15 15 map.connect 'help/:ctrl/:page', :controller => 'help'
16 16
17 17 map.with_options :controller => 'time_entry_reports', :action => 'report',:conditions => {:method => :get} do |time_report|
18 18 time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report'
19 19 time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report.:format'
20 20 time_report.connect 'projects/:project_id/time_entries/report'
21 21 time_report.connect 'projects/:project_id/time_entries/report.:format'
22 22 time_report.connect 'time_entries/report'
23 23 time_report.connect 'time_entries/report.:format'
24 24 end
25 25
26 26 map.bulk_edit_time_entry 'time_entries/bulk_edit',
27 27 :controller => 'timelog', :action => 'bulk_edit', :conditions => { :method => :get }
28 28 map.bulk_update_time_entry 'time_entries/bulk_edit',
29 29 :controller => 'timelog', :action => 'bulk_update', :conditions => { :method => :post }
30 30 map.time_entries_context_menu '/time_entries/context_menu',
31 31 :controller => 'context_menus', :action => 'time_entries'
32 32 # TODO: wasteful since this is also nested under issues, projects, and projects/issues
33 33 map.resources :time_entries, :controller => 'timelog'
34 34
35 35 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
36 36 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
37 37 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
38 38
39 39 map.with_options :controller => 'messages' do |messages_routes|
40 40 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
41 41 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
42 42 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
43 43 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
44 44 end
45 45 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
46 46 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
47 47 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
48 48 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
49 49 end
50 50 end
51 51
52 52 map.with_options :controller => 'boards' do |board_routes|
53 53 board_routes.with_options :conditions => {:method => :get} do |board_views|
54 54 board_views.connect 'projects/:project_id/boards', :action => 'index'
55 55 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
56 56 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
57 57 board_views.connect 'projects/:project_id/boards/:id.:format', :action => 'show'
58 58 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
59 59 end
60 60 board_routes.with_options :conditions => {:method => :post} do |board_actions|
61 61 board_actions.connect 'projects/:project_id/boards', :action => 'new'
62 62 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
63 63 end
64 64 end
65 65
66 66 map.with_options :controller => 'documents' do |document_routes|
67 67 document_routes.with_options :conditions => {:method => :get} do |document_views|
68 68 document_views.connect 'projects/:project_id/documents', :action => 'index'
69 69 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
70 70 document_views.connect 'documents/:id', :action => 'show'
71 71 document_views.connect 'documents/:id/edit', :action => 'edit'
72 72 end
73 73 document_routes.with_options :conditions => {:method => :post} do |document_actions|
74 74 document_actions.connect 'projects/:project_id/documents', :action => 'new'
75 75 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
76 76 end
77 77 end
78 78
79 79 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
80 80 map.resources :queries, :except => [:show]
81 81
82 82 # Misc issue routes. TODO: move into resources
83 83 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues'
84 84 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
85 85 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
86 86 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
87 87 map.bulk_edit_issue 'issues/bulk_edit', :controller => 'issues', :action => 'bulk_edit', :conditions => { :method => :get }
88 88 map.bulk_update_issue 'issues/bulk_edit', :controller => 'issues', :action => 'bulk_update', :conditions => { :method => :post }
89 89 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
90 90 map.connect '/issues/:id/destroy', :controller => 'issues', :action => 'destroy', :conditions => { :method => :post } # legacy
91 91
92 92 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
93 93 gantts_routes.connect '/projects/:project_id/issues/gantt'
94 94 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
95 95 gantts_routes.connect '/issues/gantt.:format'
96 96 end
97 97
98 98 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
99 99 calendars_routes.connect '/projects/:project_id/issues/calendar'
100 100 calendars_routes.connect '/issues/calendar'
101 101 end
102 102
103 103 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
104 104 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
105 105 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
106 106 end
107 107
108 108 # Following two routes conflict with the resources because #index allows POST
109 109 map.connect '/issues', :controller => 'issues', :action => 'index', :conditions => { :method => :post }
110 110 map.connect '/issues/create', :controller => 'issues', :action => 'index', :conditions => { :method => :post }
111 111
112 112 map.resources :issues, :member => { :edit => :post }, :collection => {} do |issues|
113 113 issues.resources :time_entries, :controller => 'timelog'
114 114 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
115 115 end
116 116
117 117 map.resources :issues, :path_prefix => '/projects/:project_id', :collection => { :create => :post } do |issues|
118 118 issues.resources :time_entries, :controller => 'timelog'
119 119 end
120 120
121 121 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
122 122
123 123 map.with_options :controller => 'users' do |users|
124 124 users.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil, :conditions => {:method => :get}
125 125
126 126 users.with_options :conditions => {:method => :post} do |user_actions|
127 127 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
128 128 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
129 129 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
130 130 end
131 131 end
132 132
133 133 map.resources :users, :member => {
134 134 :edit_membership => :post,
135 135 :destroy_membership => :post
136 136 }
137 137
138 138 # For nice "roadmap" in the url for the index action
139 139 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
140 140
141 141 map.all_news 'news', :controller => 'news', :action => 'index'
142 142 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
143 143 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
144 144 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
145 145 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
146 146
147 147 map.resources :projects, :member => {
148 148 :copy => [:get, :post],
149 149 :settings => :get,
150 150 :modules => :post,
151 151 :archive => :post,
152 152 :unarchive => :post
153 153 } do |project|
154 154 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
155 155 project.resources :files, :only => [:index, :new, :create]
156 156 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
157 157 project.resources :news, :shallow => true
158 158 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id'
159 159 project.resources :queries, :only => [:new, :create]
160 160 project.resources :issue_categories, :shallow => true
161 161
162 162 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
163 163 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
164 164 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
165 165 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
166 166 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
167 167 project.resources :wiki, :except => [:new, :create], :member => {
168 168 :rename => [:get, :post],
169 169 :history => :get,
170 170 :preview => :any,
171 171 :protect => :post,
172 172 :add_attachment => :post
173 173 }, :collection => {
174 174 :export => :get,
175 175 :date_index => :get
176 176 }
177 177
178 178 end
179 179
180 180 # Destroy uses a get request to prompt the user before the actual DELETE request
181 181 map.project_destroy_confirm 'projects/:id/destroy', :controller => 'projects', :action => 'destroy', :conditions => {:method => :get}
182 182
183 183 # TODO: port to be part of the resources route(s)
184 184 map.with_options :controller => 'projects' do |project_mapper|
185 185 project_mapper.with_options :conditions => {:method => :get} do |project_views|
186 186 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
187 187 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
188 188 end
189 189 end
190 190
191 191 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
192 192 activity.connect 'projects/:id/activity'
193 193 activity.connect 'projects/:id/activity.:format'
194 194 activity.connect 'activity', :id => nil
195 195 activity.connect 'activity.:format', :id => nil
196 196 end
197 197
198 198 map.with_options :controller => 'repositories' do |repositories|
199 199 repositories.with_options :conditions => {:method => :get} do |repository_views|
200 200 repository_views.connect 'projects/:id/repository', :action => 'show'
201 201 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
202 202 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
203 203 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
204 204 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
205 205 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
206 206 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
207 207 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
208 208 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
209 209 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
210 210 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
211 211 # TODO: why the following route is required?
212 212 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
213 213 repository_views.connect 'projects/:id/repository/:action/*path'
214 214 end
215 215
216 216 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
217 217 end
218
219 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
220 map.connect 'attachments/:id.:format', :controller => 'attachments', :action => 'show', :id => /\d+/
218
219 map.resources :attachments, :only => [:show, :destroy]
220 # additional routes for having the file name at the end of url
221 221 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
222 222 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
223 223
224 224 map.resources :groups, :member => {:autocomplete_for_user => :get}
225 225 map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post}
226 226 map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete}
227 227
228 228 map.resources :trackers, :except => :show
229 229 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
230 230
231 231 #left old routes at the bottom for backwards compat
232 232 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
233 233 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
234 234 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
235 235 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
236 236 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
237 237 map.connect 'projects/:project_id/news/:action', :controller => 'news'
238 238 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
239 239 map.with_options :controller => 'repositories' do |omap|
240 240 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
241 241 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
242 242 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
243 243 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
244 244 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
245 245 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
246 246 end
247 247
248 248 map.with_options :controller => 'sys' do |sys|
249 249 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
250 250 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
251 251 end
252 252
253 253 # Install the default route as the lowest priority.
254 254 map.connect ':controller/:action/:id'
255 255 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
256 256 # Used for OpenID
257 257 map.root :controller => 'account', :action => 'login'
258 258 end
@@ -1,272 +1,274
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2011 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require File.expand_path('../../test_helper', __FILE__)
21 21 require 'attachments_controller'
22 22
23 23 # Re-raise errors caught by the controller.
24 24 class AttachmentsController; def rescue_action(e) raise e end; end
25 25
26 26 class AttachmentsControllerTest < ActionController::TestCase
27 27 fixtures :users, :projects, :roles, :members, :member_roles,
28 28 :enabled_modules, :issues, :trackers, :attachments,
29 29 :versions, :wiki_pages, :wikis, :documents
30 30
31 31 def setup
32 32 @controller = AttachmentsController.new
33 33 @request = ActionController::TestRequest.new
34 34 @response = ActionController::TestResponse.new
35 35 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
36 36 User.current = nil
37 37 end
38 38
39 39 def test_show_diff
40 40 ['inline', 'sbs'].each do |dt|
41 41 # 060719210727_changeset_utf8.diff
42 42 get :show, :id => 14, :type => dt
43 43 assert_response :success
44 44 assert_template 'diff'
45 45 assert_equal 'text/html', @response.content_type
46 46 assert_tag 'th',
47 47 :attributes => {:class => /filename/},
48 48 :content => /issues_controller.rb\t\(rΓ©vision 1484\)/
49 49 assert_tag 'td',
50 50 :attributes => {:class => /line-code/},
51 51 :content => /Demande créée avec succès/
52 52 end
53 53 set_tmp_attachments_directory
54 54 end
55 55
56 56 def test_show_diff_replcace_cannot_convert_content
57 57 with_settings :repositories_encodings => 'UTF-8' do
58 58 ['inline', 'sbs'].each do |dt|
59 59 # 060719210727_changeset_iso8859-1.diff
60 60 get :show, :id => 5, :type => dt
61 61 assert_response :success
62 62 assert_template 'diff'
63 63 assert_equal 'text/html', @response.content_type
64 64 assert_tag 'th',
65 65 :attributes => {:class => "filename"},
66 66 :content => /issues_controller.rb\t\(r\?vision 1484\)/
67 67 assert_tag 'td',
68 68 :attributes => {:class => /line-code/},
69 69 :content => /Demande cr\?\?e avec succ\?s/
70 70 end
71 71 end
72 72 set_tmp_attachments_directory
73 73 end
74 74
75 75 def test_show_diff_latin_1
76 76 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
77 77 ['inline', 'sbs'].each do |dt|
78 78 # 060719210727_changeset_iso8859-1.diff
79 79 get :show, :id => 5, :type => dt
80 80 assert_response :success
81 81 assert_template 'diff'
82 82 assert_equal 'text/html', @response.content_type
83 83 assert_tag 'th',
84 84 :attributes => {:class => "filename"},
85 85 :content => /issues_controller.rb\t\(rΓ©vision 1484\)/
86 86 assert_tag 'td',
87 87 :attributes => {:class => /line-code/},
88 88 :content => /Demande créée avec succès/
89 89 end
90 90 end
91 91 set_tmp_attachments_directory
92 92 end
93 93
94 94 def test_show_text_file
95 95 get :show, :id => 4
96 96 assert_response :success
97 97 assert_template 'file'
98 98 assert_equal 'text/html', @response.content_type
99 99 set_tmp_attachments_directory
100 100 end
101 101
102 102 def test_show_text_file_utf_8
103 103 set_tmp_attachments_directory
104 104 a = Attachment.new(:container => Issue.find(1),
105 105 :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"),
106 106 :author => User.find(1))
107 107 assert a.save
108 108 assert_equal 'japanese-utf-8.txt', a.filename
109 109
110 110 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
111 111 str_japanese.force_encoding('UTF-8') if str_japanese.respond_to?(:force_encoding)
112 112
113 113 get :show, :id => a.id
114 114 assert_response :success
115 115 assert_template 'file'
116 116 assert_equal 'text/html', @response.content_type
117 117 assert_tag :tag => 'th',
118 118 :content => '1',
119 119 :attributes => { :class => 'line-num' },
120 120 :sibling => { :tag => 'td', :content => /#{str_japanese}/ }
121 121 end
122 122
123 123 def test_show_text_file_replcace_cannot_convert_content
124 124 set_tmp_attachments_directory
125 125 with_settings :repositories_encodings => 'UTF-8' do
126 126 a = Attachment.new(:container => Issue.find(1),
127 127 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
128 128 :author => User.find(1))
129 129 assert a.save
130 130 assert_equal 'iso8859-1.txt', a.filename
131 131
132 132 get :show, :id => a.id
133 133 assert_response :success
134 134 assert_template 'file'
135 135 assert_equal 'text/html', @response.content_type
136 136 assert_tag :tag => 'th',
137 137 :content => '7',
138 138 :attributes => { :class => 'line-num' },
139 139 :sibling => { :tag => 'td', :content => /Demande cr\?\?e avec succ\?s/ }
140 140 end
141 141 end
142 142
143 143 def test_show_text_file_latin_1
144 144 set_tmp_attachments_directory
145 145 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
146 146 a = Attachment.new(:container => Issue.find(1),
147 147 :file => uploaded_test_file("iso8859-1.txt", "text/plain"),
148 148 :author => User.find(1))
149 149 assert a.save
150 150 assert_equal 'iso8859-1.txt', a.filename
151 151
152 152 get :show, :id => a.id
153 153 assert_response :success
154 154 assert_template 'file'
155 155 assert_equal 'text/html', @response.content_type
156 156 assert_tag :tag => 'th',
157 157 :content => '7',
158 158 :attributes => { :class => 'line-num' },
159 159 :sibling => { :tag => 'td', :content => /Demande créée avec succès/ }
160 160 end
161 161 end
162 162
163 163 def test_show_text_file_should_send_if_too_big
164 164 Setting.file_max_size_displayed = 512
165 165 Attachment.find(4).update_attribute :filesize, 754.kilobyte
166 166
167 167 get :show, :id => 4
168 168 assert_response :success
169 169 assert_equal 'application/x-ruby', @response.content_type
170 170 set_tmp_attachments_directory
171 171 end
172 172
173 173 def test_show_other
174 174 get :show, :id => 6
175 175 assert_response :success
176 176 assert_equal 'application/octet-stream', @response.content_type
177 177 set_tmp_attachments_directory
178 178 end
179 179
180 180 def test_show_file_from_private_issue_without_permission
181 181 get :show, :id => 15
182 182 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
183 183 set_tmp_attachments_directory
184 184 end
185 185
186 186 def test_show_file_from_private_issue_with_permission
187 187 @request.session[:user_id] = 2
188 188 get :show, :id => 15
189 189 assert_response :success
190 190 assert_tag 'h2', :content => /private.diff/
191 191 set_tmp_attachments_directory
192 192 end
193 193
194 194 def test_download_text_file
195 195 get :download, :id => 4
196 196 assert_response :success
197 197 assert_equal 'application/x-ruby', @response.content_type
198 198 set_tmp_attachments_directory
199 199 end
200 200
201 201 def test_download_should_assign_content_type_if_blank
202 202 Attachment.find(4).update_attribute(:content_type, '')
203 203
204 204 get :download, :id => 4
205 205 assert_response :success
206 206 assert_equal 'text/x-ruby', @response.content_type
207 207 set_tmp_attachments_directory
208 208 end
209 209
210 210 def test_download_missing_file
211 211 get :download, :id => 2
212 212 assert_response 404
213 213 set_tmp_attachments_directory
214 214 end
215 215
216 216 def test_anonymous_on_private_private
217 217 get :download, :id => 7
218 218 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7'
219 219 set_tmp_attachments_directory
220 220 end
221 221
222 222 def test_destroy_issue_attachment
223 223 issue = Issue.find(3)
224 224 @request.session[:user_id] = 2
225 225
226 226 assert_difference 'issue.attachments.count', -1 do
227 post :destroy, :id => 1
227 delete :destroy, :id => 1
228 228 end
229 229 # no referrer
230 230 assert_redirected_to '/projects/ecookbook'
231 231 assert_nil Attachment.find_by_id(1)
232 232 j = issue.journals.find(:first, :order => 'created_on DESC')
233 233 assert_equal 'attachment', j.details.first.property
234 234 assert_equal '1', j.details.first.prop_key
235 235 assert_equal 'error281.txt', j.details.first.old_value
236 236 set_tmp_attachments_directory
237 237 end
238 238
239 239 def test_destroy_wiki_page_attachment
240 240 @request.session[:user_id] = 2
241 241 assert_difference 'Attachment.count', -1 do
242 post :destroy, :id => 3
242 delete :destroy, :id => 3
243 243 assert_response 302
244 244 end
245 245 set_tmp_attachments_directory
246 246 end
247 247
248 248 def test_destroy_project_attachment
249 249 @request.session[:user_id] = 2
250 250 assert_difference 'Attachment.count', -1 do
251 post :destroy, :id => 8
251 delete :destroy, :id => 8
252 252 assert_response 302
253 253 end
254 254 set_tmp_attachments_directory
255 255 end
256 256
257 257 def test_destroy_version_attachment
258 258 @request.session[:user_id] = 2
259 259 assert_difference 'Attachment.count', -1 do
260 post :destroy, :id => 9
260 delete :destroy, :id => 9
261 261 assert_response 302
262 262 end
263 263 set_tmp_attachments_directory
264 264 end
265 265
266 266 def test_destroy_without_permission
267 post :destroy, :id => 3
268 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdestroy%2F3'
267 assert_no_difference 'Attachment.count' do
268 delete :destroy, :id => 3
269 end
270 assert_response 302
269 271 assert Attachment.find_by_id(3)
270 272 set_tmp_attachments_directory
271 273 end
272 274 end
General Comments 0
You need to be logged in to leave comments. Login now