##// END OF EJS Templates
Update the issue subject when choosing an issue from the drop down menu....
Update the issue subject when choosing an issue from the drop down menu. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@11083 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r10761:c99b638d61cc
r10853:6be315c1ff8e
Show More
attachment.rb
326 lines | 10.5 KiB | text/x-ruby | RubyLexer
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673 # Redmine - project management software
Toshi MARUYAMA
remove trailing white-spaces from app/models/attachment.rb...
r8892 # Copyright (C) 2006-2012 Jean-Philippe Lang
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 #
# 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.
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673 #
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # 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.
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673 #
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # 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.
require "digest/md5"
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 require "fileutils"
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
class Attachment < ActiveRecord::Base
belongs_to :container, :polymorphic => true
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 validates_presence_of :filename, :author
Jean-Philippe Lang
Added several validates_length_of...
r590 validates_length_of :filename, :maximum => 255
validates_length_of :disk_filename, :maximum => 255
Jean-Philippe Lang
Validate attachment description length (#11365)....
r9801 validates_length_of :description, :maximum => 255
Toshi MARUYAMA
Rails3: replace deprecate 'validate' instance method to declared validation method at Attachment model....
r6594 validate :validate_max_file_size
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663
acts_as_event :title => :filename,
Jean-Philippe Lang
Appends the filename to the attachment url so that clients that ignore content-disposition http header get the real filename (#1649)....
r1669 :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663
Jean-Philippe Lang
Activity refactoring....
r1692 acts_as_activity_provider :type => 'files',
:permission => :view_files,
Jean-Philippe Lang
Display latest user's activity on account/show view....
r2064 :author_key => :author_id,
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673 :find_options => {:select => "#{Attachment.table_name}.*",
Jean-Philippe Lang
Activity refactoring....
r1692 :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
Jean-Philippe Lang
Fixed: Files without Version aren't visible in the Activity page (#2930)....
r2501 "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"}
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Activity refactoring....
r1692 acts_as_activity_provider :type => 'documents',
:permission => :view_documents,
Jean-Philippe Lang
Display latest user's activity on account/show view....
r2064 :author_key => :author_id,
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673 :find_options => {:select => "#{Attachment.table_name}.*",
Jean-Philippe Lang
Activity refactoring....
r1692 :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 cattr_accessor :storage_path
Jean-Philippe Lang
Code cleanup....
r9381 @@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files")
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Displays thumbnails of attached images of the issue view (#1006)....
r9750 cattr_accessor :thumbnails_storage_path
@@thumbnails_storage_path = File.join(Rails.root, "tmp", "thumbnails")
Toshi MARUYAMA
Rails3: replace deprecated 'before_save' method at Attachment model....
r6636 before_save :files_to_final_location
Toshi MARUYAMA
Rails3: replace deprecated 'after_destroy' method at Attachment model....
r6643 after_destroy :delete_from_disk
Toshi MARUYAMA
Rails3: replace deprecated 'before_save' method at Attachment model....
r6636
Jean-Philippe Lang
Copy attachments on issue and project copy (#3055)....
r8556 # Returns an unsaved copy of the attachment
def copy(attributes=nil)
copy = self.class.new
copy.attributes = self.attributes.dup.except("id", "downloads")
copy.attributes = attributes if attributes
copy
end
Toshi MARUYAMA
Rails3: replace deprecate 'validate' instance method to declared validation method at Attachment model....
r6594 def validate_max_file_size
Jean-Philippe Lang
Copy attachments on issue and project copy (#3055)....
r8556 if @temp_file && self.filesize > Setting.attachment_max_size.to_i.kilobytes
Jean-Philippe Lang
Better message for file size validation error....
r8817 errors.add(:base, l(:error_attachment_too_big, :max_size => Setting.attachment_max_size.to_i.kilobytes))
Jean-Philippe Lang
Fixes that custom values length and attachment size validation error raises an error....
r2575 end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 def file=(incoming_file)
unless incoming_file.nil?
@temp_file = incoming_file
if @temp_file.size > 0
Jean-Philippe Lang
Adds support for adding attachments to issues through the REST API (#8171)....
r8808 if @temp_file.respond_to?(:original_filename)
self.filename = @temp_file.original_filename
Jean-Philippe Lang
Uploading of attachments which filename contains non-ASCII chars fails with Ruby 1.9 on issue update (#10575)....
r9200 self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding)
Jean-Philippe Lang
Adds support for adding attachments to issues through the REST API (#8171)....
r8808 end
if @temp_file.respond_to?(:content_type)
self.content_type = @temp_file.content_type.to_s.chomp
end
if content_type.blank? && filename.present?
Jean-Philippe Lang
Auto-detect attachment content type when blank (#3782)....
r3144 self.content_type = Redmine::MimeType.of(filename)
end
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 self.filesize = @temp_file.size
end
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/attachment.rb...
r8892
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 def file
nil
end
Jean-Philippe Lang
Adds support for adding attachments to issues through the REST API (#8171)....
r8808 def filename=(arg)
write_attribute :filename, sanitize_filename(arg.to_s)
filename
end
Jean-Philippe Lang
Fixes memory consumption on file upload (#3116)....
r2578 # Copies the temporary file to its final location
# and computes its MD5 hash
Toshi MARUYAMA
Rails3: replace deprecated 'before_save' method at Attachment model....
r6636 def files_to_final_location
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 if @temp_file && (@temp_file.size > 0)
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 self.disk_directory = target_directory
self.disk_filename = Attachment.disk_filename(filename, disk_directory)
Jean-Philippe Lang
Fixed: file uploads broken by r6312 (#8912)....
r6200 logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)")
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 path = File.dirname(diskfile)
unless File.directory?(path)
FileUtils.mkdir_p(path)
end
Jean-Philippe Lang
Fixes memory consumption on file upload (#3116)....
r2578 md5 = Digest::MD5.new
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673 File.open(diskfile, "wb") do |f|
Jean-Philippe Lang
Use Mail instead of TMail in MailHandler....
r9447 if @temp_file.respond_to?(:read)
buffer = ""
while (buffer = @temp_file.read(8192))
f.write(buffer)
md5.update(buffer)
end
else
f.write(@temp_file)
md5.update(@temp_file)
Jean-Philippe Lang
Fixes memory consumption on file upload (#3116)....
r2578 end
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 end
Jean-Philippe Lang
Fixes memory consumption on file upload (#3116)....
r2578 self.digest = md5.hexdigest
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 end
Jean-Philippe Lang
Fixed: file uploads broken by r6312 (#8912)....
r6200 @temp_file = nil
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 # Don't save the content type if it's longer than the authorized length
if self.content_type && self.content_type.length > 255
self.content_type = nil
end
end
Jean-Philippe Lang
Copy attachments on issue and project copy (#3055)....
r8556 # Deletes the file from the file system if it's not referenced by other attachments
Toshi MARUYAMA
Rails3: replace deprecated 'after_destroy' method at Attachment model....
r6643 def delete_from_disk
Jean-Philippe Lang
Code cleanup....
r9534 if Attachment.where("disk_filename = ? AND id <> ?", disk_filename, id).empty?
Jean-Philippe Lang
Copy attachments on issue and project copy (#3055)....
r8556 delete_from_disk!
end
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 end
# Returns file's location on disk
def diskfile
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s)
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Adds Attachment#title....
r9829 def title
title = filename.to_s
if description.present?
title << " (#{description})"
end
title
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 def increment_download
increment!(:downloads)
end
Jean-Philippe Lang
Attachments can now be added to wiki pages (original patch by Pavol Murin). Only authorized users can add/delete attachments....
r538
def project
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 container.try(:project)
Jean-Philippe Lang
Attachments can now be added to wiki pages (original patch by Pavol Murin). Only authorized users can add/delete attachments....
r538 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 def visible?(user=User.current)
Jean-Philippe Lang
Merged ajax_upload branch (#3957)....
r10748 if container_id
container && container.attachments_visible?(user)
else
author == user
end
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 def deletable?(user=User.current)
Jean-Philippe Lang
Merged ajax_upload branch (#3957)....
r10748 if container_id
container && container.attachments_deletable?(user)
else
author == user
end
Jean-Philippe Lang
AttachmentsController now handles attachments deletion....
r2114 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Image attachments are now sent inline to be viewed directly in the browser....
r636 def image?
Jean-Philippe Lang
Displays thumbnails of attached images of the issue view (#1006)....
r9750 !!(self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i)
end
def thumbnailable?
image?
end
# Returns the full path the attachment thumbnail, or nil
# if the thumbnail cannot be generated.
Jean-Philippe Lang
Adds a macro for inserting thumbnails in formatted text (#3510)....
r9830 def thumbnail(options={})
Jean-Philippe Lang
Displays thumbnails of attached images of the issue view (#1006)....
r9750 if thumbnailable? && readable?
Jean-Philippe Lang
Adds a macro for inserting thumbnails in formatted text (#3510)....
r9830 size = options[:size].to_i
if size > 0
# Limit the number of thumbnails per image
size = (size / 50) * 50
# Maximum thumbnail size
size = 800 if size > 800
else
size = Setting.thumbnails_size.to_i
end
Jean-Philippe Lang
Displays thumbnails of attached images of the issue view (#1006)....
r9750 size = 100 unless size > 0
target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb")
begin
Redmine::Thumbnail.generate(self.diskfile, target, size)
rescue => e
logger.error "An error occured while generating thumbnail for #{disk_filename} to #{target}\nException was: #{e.message}" if logger
return nil
end
end
end
# Deletes all thumbnails
def self.clear_thumbnails
Dir.glob(File.join(thumbnails_storage_path, "*.thumb")).each do |file|
File.delete file
end
Jean-Philippe Lang
Image attachments are now sent inline to be viewed directly in the browser....
r636 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
File viewer for attached text files....
r1506 def is_text?
Redmine::MimeType.is_type?('text', filename)
end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Unified diff viewer for attached files with .patch or .diff extension (#1403)....
r1502 def is_diff?
self.filename =~ /\.(patch|diff)$/i
end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Returns a 404 error when trying to view/download an attachment that can't be read from disk....
r2600 # Returns true if the file is readable
def readable?
File.readable?(diskfile)
end
Eric Davis
Refactor: Moved ApplicationController#attach_files to the Attachment model...
r3409
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 # Returns the attachment token
def token
"#{id}.#{digest}"
end
# Finds an attachment that matches the given token and that has no container
def self.find_by_token(token)
if token.to_s =~ /^(\d+)\.([0-9a-f]+)$/
attachment_id, attachment_digest = $1, $2
Jean-Philippe Lang
Code cleanup....
r9533 attachment = Attachment.where(:id => attachment_id, :digest => attachment_digest).first
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 if attachment && attachment.container.nil?
attachment
end
end
end
Eric Davis
Refactor: Moved ApplicationController#attach_files to the Attachment model...
r3409 # Bulk attaches a set of files to an object
#
# Returns a Hash of the results:
# :files => array of the attached files
# :unsaved => array of the files that could not be attached
def self.attach_files(obj, attachments)
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 result = obj.save_attachments(attachments, User.current)
obj.attach_saved_attachments
result
Eric Davis
Refactor: Moved ApplicationController#attach_files to the Attachment model...
r3409 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Toshi MARUYAMA
move logic to use latest image file attachment to class method for common use (#3261)...
r7788 def self.latest_attach(attachments, filename)
Toshi MARUYAMA
remove trailing white-spaces from app/models/attachment.rb...
r8892 attachments.sort_by(&:created_on).reverse.detect {
Toshi MARUYAMA
move logic to use latest image file attachment to class method for common use (#3261)...
r7788 |att| att.filename.downcase == filename.downcase
}
end
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 def self.prune(age=1.day)
Jean-Philippe Lang
Code cleanup....
r9533 Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all
Jean-Philippe Lang
Better handling of attachments when issue validation fails (#10253)....
r8771 end
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 # Moves an existing attachment to its target directory
def move_to_target_directory!
if !new_record? & readable?
src = diskfile
self.disk_directory = target_directory
dest = diskfile
if src != dest && FileUtils.mkdir_p(File.dirname(dest)) && FileUtils.mv(src, dest)
update_column :disk_directory, disk_directory
end
end
end
# Moves existing attachments that are stored at the root of the files
# directory (ie. created before Redmine 2.3) to their target subdirectories
def self.move_from_root_to_target_directory
Attachment.where("disk_directory IS NULL OR disk_directory = ''").find_each do |attachment|
attachment.move_to_target_directory!
end
end
Jean-Philippe Lang
Copy attachments on issue and project copy (#3055)....
r8556 private
# Physically deletes the file from the file system
def delete_from_disk!
if disk_filename.present? && File.exist?(diskfile)
File.delete(diskfile)
end
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 def sanitize_filename(value)
Jean-Philippe Lang
Attachment model clean up: fixed some inconsistent indentation and an inaccurate comment (closes patch #903 by Rocco Stanzione)....
r1306 # get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '')
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Jean-Philippe Lang
Limit the characters stripped by Attachment#sanitize_filename (#4324)....
r7797 # Finally, replace invalid characters with underscore
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_')
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Toshi MARUYAMA
remove trailing white-spaces from Attachment model source....
r5673
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 # Returns the subdirectory in which the attachment will be saved
def target_directory
time = created_on || DateTime.now
time.strftime("%Y/%m")
end
# Returns an ASCII or hashed filename that do not
# exists yet in the given subdirectory
def self.disk_filename(filename, directory=nil)
Jean-Philippe Lang
Fixed: attachments with the same name at the same time overwrite (#3691)....
r3397 timestamp = DateTime.now.strftime("%y%m%d%H%M%S")
ascii = ''
Jean-Philippe Lang
Fixed: possible error when attachment's filename is non-ASCII (#747, #1243, #1089)....
r1418 if filename =~ %r{^[a-zA-Z0-9_\.\-]*$}
Jean-Philippe Lang
Fixed: attachments with the same name at the same time overwrite (#3691)....
r3397 ascii = filename
Jean-Philippe Lang
Fixed: possible error when attachment's filename is non-ASCII (#747, #1243, #1089)....
r1418 else
Jean-Philippe Lang
Fixed: attachments with the same name at the same time overwrite (#3691)....
r3397 ascii = Digest::MD5.hexdigest(filename)
Jean-Philippe Lang
Fixed: possible error when attachment's filename is non-ASCII (#747, #1243, #1089)....
r1418 # keep the extension if any
Jean-Philippe Lang
Fixed: attachments with the same name at the same time overwrite (#3691)....
r3397 ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$}
Jean-Philippe Lang
Fixed: possible error when attachment's filename is non-ASCII (#747, #1243, #1089)....
r1418 end
Jean-Philippe Lang
Store attachments in subdirectories (#5298)....
r10761 while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}"))
Jean-Philippe Lang
Fixed: attachments with the same name at the same time overwrite (#3691)....
r3397 timestamp.succ!
end
"#{timestamp}_#{ascii}"
Jean-Philippe Lang
Fixed: possible error when attachment's filename is non-ASCII (#747, #1243, #1089)....
r1418 end
Jean-Philippe Lang
Initial commit...
r2 end