| 
									
										
										
										
											2008-12-09 16:54:46 +00:00
										 |  |  | # Redmine - project management software | 
					
						
							| 
									
										
										
										
											2016-03-13 10:30:10 +00:00
										 |  |  | # Copyright (C) 2006-2016  Jean-Philippe Lang | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | # modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | # as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | # of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  | # This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | # GNU General Public License for more details. | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AttachmentsController < ApplicationController | 
					
						
							| 
									
										
										
										
											2014-11-29 13:41:53 +00:00
										 |  |  |   before_filter :find_attachment, :only => [:show, :download, :thumbnail, :destroy] | 
					
						
							|  |  |  |   before_filter :find_editable_attachments, :only => [:edit, :update] | 
					
						
							| 
									
										
										
										
											2012-07-07 13:48:07 +00:00
										 |  |  |   before_filter :file_readable, :read_authorize, :only => [:show, :download, :thumbnail] | 
					
						
							| 
									
										
										
										
											2008-12-09 16:54:46 +00:00
										 |  |  |   before_filter :delete_authorize, :only => :destroy | 
					
						
							| 
									
										
										
										
											2012-02-23 10:01:16 +00:00
										 |  |  |   before_filter :authorize_global, :only => :upload | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-12 19:18:34 +00:00
										 |  |  |   accept_api_auth :show, :download, :thumbnail, :upload, :destroy | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-08 18:26:39 +00:00
										 |  |  |   def show | 
					
						
							| 
									
										
										
										
											2011-07-18 20:53:10 +00:00
										 |  |  |     respond_to do |format| | 
					
						
							|  |  |  |       format.html { | 
					
						
							|  |  |  |         if @attachment.is_diff? | 
					
						
							| 
									
										
										
										
											2016-04-03 11:41:41 +00:00
										 |  |  |           @diff = File.read(@attachment.diskfile, :mode => "rb") | 
					
						
							| 
									
										
										
										
											2011-11-20 06:13:26 +00:00
										 |  |  |           @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' | 
					
						
							|  |  |  |           @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) | 
					
						
							| 
									
										
										
										
											2012-02-04 06:23:38 +00:00
										 |  |  |           # Save diff type as user preference | 
					
						
							|  |  |  |           if User.current.logged? && @diff_type != User.current.pref[:diff_type] | 
					
						
							|  |  |  |             User.current.pref[:diff_type] = @diff_type | 
					
						
							|  |  |  |             User.current.preference.save | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-07-18 20:53:10 +00:00
										 |  |  |           render :action => 'diff' | 
					
						
							|  |  |  |         elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte | 
					
						
							| 
									
										
										
										
											2016-04-03 11:41:41 +00:00
										 |  |  |           @content = File.read(@attachment.diskfile, :mode => "rb") | 
					
						
							| 
									
										
										
										
											2011-07-18 20:53:10 +00:00
										 |  |  |           render :action => 'file' | 
					
						
							| 
									
										
										
										
											2016-04-11 19:17:48 +00:00
										 |  |  |         elsif @attachment.is_image? | 
					
						
							|  |  |  |           render :action => 'image' | 
					
						
							| 
									
										
										
										
											2011-07-18 20:53:10 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2016-05-08 08:04:51 +00:00
										 |  |  |           render :action => 'other' | 
					
						
							| 
									
										
										
										
											2011-07-18 20:53:10 +00:00
										 |  |  |         end | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       format.api | 
					
						
							| 
									
										
										
										
											2008-06-08 18:26:39 +00:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  |   def download | 
					
						
							| 
									
										
										
										
											2008-12-30 13:32:51 +00:00
										 |  |  |     if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) | 
					
						
							|  |  |  |       @attachment.increment_download | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-08 15:26:40 +00:00
										 |  |  |     if stale?(:etag => @attachment.digest) | 
					
						
							|  |  |  |       # images are sent inline | 
					
						
							|  |  |  |       send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), | 
					
						
							|  |  |  |                                       :type => detect_content_type(@attachment), | 
					
						
							|  |  |  |                                       :disposition => (@attachment.image? ? 'inline' : 'attachment') | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-07 13:48:07 +00:00
										 |  |  |   def thumbnail | 
					
						
							| 
									
										
										
										
											2014-06-08 04:23:59 +00:00
										 |  |  |     if @attachment.thumbnailable? && tbnail = @attachment.thumbnail(:size => params[:size]) | 
					
						
							|  |  |  |       if stale?(:etag => tbnail) | 
					
						
							|  |  |  |         send_file tbnail, | 
					
						
							| 
									
										
										
										
											2012-07-08 15:26:40 +00:00
										 |  |  |           :filename => filename_for_content_disposition(@attachment.filename), | 
					
						
							|  |  |  |           :type => detect_content_type(@attachment), | 
					
						
							|  |  |  |           :disposition => 'inline' | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-07-07 13:48:07 +00:00
										 |  |  |     else | 
					
						
							|  |  |  |       # No thumbnail for the attachment or thumbnail could not be created | 
					
						
							|  |  |  |       render :nothing => true, :status => 404
 | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-23 10:01:16 +00:00
										 |  |  |   def upload | 
					
						
							|  |  |  |     # Make sure that API users get used to set this content type | 
					
						
							|  |  |  |     # as it won't trigger Rails' automatic parsing of the request body for parameters | 
					
						
							|  |  |  |     unless request.content_type == 'application/octet-stream' | 
					
						
							|  |  |  |       render :nothing => true, :status => 406
 | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-08 10:11:09 +00:00
										 |  |  |     @attachment = Attachment.new(:file => request.raw_post) | 
					
						
							| 
									
										
										
										
											2012-02-23 10:01:16 +00:00
										 |  |  |     @attachment.author = User.current | 
					
						
							| 
									
										
										
										
											2012-10-18 21:06:35 +00:00
										 |  |  |     @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16) | 
					
						
							| 
									
										
										
										
											2014-12-21 21:07:13 +00:00
										 |  |  |     @attachment.content_type = params[:content_type].presence | 
					
						
							| 
									
										
										
										
											2012-12-10 20:09:41 +00:00
										 |  |  |     saved = @attachment.save | 
					
						
							| 
									
										
										
										
											2012-02-23 10:01:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-10 20:09:41 +00:00
										 |  |  |     respond_to do |format| | 
					
						
							|  |  |  |       format.js | 
					
						
							|  |  |  |       format.api { | 
					
						
							|  |  |  |         if saved | 
					
						
							|  |  |  |           render :action => 'upload', :status => :created | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           render_validation_errors(@attachment) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2012-02-23 10:01:16 +00:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 13:41:53 +00:00
										 |  |  |   def edit | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def update | 
					
						
							|  |  |  |     if params[:attachments].is_a?(Hash) | 
					
						
							|  |  |  |       if Attachment.update_attachments(@attachments, params[:attachments]) | 
					
						
							|  |  |  |         redirect_back_or_default home_path | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     render :action => 'edit' | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-09 16:54:46 +00:00
										 |  |  |   def destroy | 
					
						
							| 
									
										
										
										
											2012-03-04 11:41:10 +00:00
										 |  |  |     if @attachment.container.respond_to?(:init_journal) | 
					
						
							|  |  |  |       @attachment.container.init_journal(User.current) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-12-10 20:09:41 +00:00
										 |  |  |     if @attachment.container | 
					
						
							|  |  |  |       # Make sure association callbacks are called | 
					
						
							|  |  |  |       @attachment.container.attachments.delete(@attachment) | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       @attachment.destroy | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     respond_to do |format| | 
					
						
							|  |  |  |       format.html { redirect_to_referer_or project_path(@project) } | 
					
						
							|  |  |  |       format.js | 
					
						
							| 
									
										
										
										
											2016-04-12 19:18:34 +00:00
										 |  |  |       format.api { render_api_ok } | 
					
						
							| 
									
										
										
										
											2012-12-10 20:09:41 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2008-12-09 16:54:46 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 13:41:53 +00:00
										 |  |  |   private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def find_attachment | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  |     @attachment = Attachment.find(params[:id]) | 
					
						
							| 
									
										
										
										
											2008-07-22 17:55:19 +00:00
										 |  |  |     # Show 404 if the filename in the url is wrong | 
					
						
							|  |  |  |     raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  |     @project = @attachment.project | 
					
						
							| 
									
										
										
										
											2008-07-22 17:20:02 +00:00
										 |  |  |   rescue ActiveRecord::RecordNotFound | 
					
						
							|  |  |  |     render_404 | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 13:41:53 +00:00
										 |  |  |   def find_editable_attachments | 
					
						
							|  |  |  |     klass = params[:object_type].to_s.singularize.classify.constantize rescue nil | 
					
						
							|  |  |  |     unless klass && klass.reflect_on_association(:attachments) | 
					
						
							|  |  |  |       render_404 | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @container = klass.find(params[:object_id]) | 
					
						
							|  |  |  |     if @container.respond_to?(:visible?) && !@container.visible? | 
					
						
							|  |  |  |       render_403 | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     @attachments = @container.attachments.select(&:editable?) | 
					
						
							|  |  |  |     if @container.respond_to?(:project) | 
					
						
							|  |  |  |       @project = @container.project | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     render_404 if @attachments.empty? | 
					
						
							|  |  |  |   rescue ActiveRecord::RecordNotFound | 
					
						
							|  |  |  |     render_404 | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-25 09:31:36 +00:00
										 |  |  |   # Checks that the file exists and is readable | 
					
						
							|  |  |  |   def file_readable | 
					
						
							| 
									
										
										
										
											2012-12-26 14:00:10 +00:00
										 |  |  |     if @attachment.readable? | 
					
						
							|  |  |  |       true | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable." | 
					
						
							|  |  |  |       render_404 | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2009-04-25 09:31:36 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-09 16:54:46 +00:00
										 |  |  |   def read_authorize | 
					
						
							|  |  |  |     @attachment.visible? ? true : deny_access | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-09 16:54:46 +00:00
										 |  |  |   def delete_authorize | 
					
						
							|  |  |  |     @attachment.deletable? ? true : deny_access | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-05-18 07:12:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-29 13:28:30 +00:00
										 |  |  |   def detect_content_type(attachment) | 
					
						
							|  |  |  |     content_type = attachment.content_type | 
					
						
							| 
									
										
										
										
											2015-02-19 17:46:24 +00:00
										 |  |  |     if content_type.blank? || content_type == "application/octet-stream" | 
					
						
							| 
									
										
										
										
											2009-12-29 13:28:30 +00:00
										 |  |  |       content_type = Redmine::MimeType.of(attachment.filename) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-01-05 18:16:03 +00:00
										 |  |  |     content_type.to_s | 
					
						
							| 
									
										
										
										
											2009-12-29 13:28:30 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2007-05-26 15:42:37 +00:00
										 |  |  | end |