Mercurial > hg > soundsoftware-site
diff app/models/attachment.rb @ 1464:261b3d9a4903 redmine-2.4
Update to Redmine 2.4 branch rev 12663
author | Chris Cannam |
---|---|
date | Tue, 14 Jan 2014 14:37:42 +0000 |
parents | 433d4f72a19b |
children | e248c7af89ec |
line wrap: on
line diff
--- a/app/models/attachment.rb Fri Jun 14 09:05:06 2013 +0100 +++ b/app/models/attachment.rb Tue Jan 14 14:37:42 2014 +0000 @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2012 Jean-Philippe Lang +# Copyright (C) 2006-2013 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require "digest/md5" +require "fileutils" class Attachment < ActiveRecord::Base belongs_to :container, :polymorphic => true @@ -92,9 +93,6 @@ def filename=(arg) write_attribute :filename, sanitize_filename(arg.to_s) - if new_record? && disk_filename.blank? - self.disk_filename = Attachment.disk_filename(filename) - end filename end @@ -102,7 +100,13 @@ # and computes its MD5 hash def files_to_final_location if @temp_file && (@temp_file.size > 0) - logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") + self.disk_directory = target_directory + self.disk_filename = Attachment.disk_filename(filename, disk_directory) + logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") if logger + path = File.dirname(diskfile) + unless File.directory?(path) + FileUtils.mkdir_p(path) + end md5 = Digest::MD5.new File.open(diskfile, "wb") do |f| if @temp_file.respond_to?(:read) @@ -134,7 +138,7 @@ # Returns file's location on disk def diskfile - File.join(self.class.storage_path, disk_filename.to_s) + File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s) end def title @@ -154,11 +158,19 @@ end def visible?(user=User.current) - container && container.attachments_visible?(user) + if container_id + container && container.attachments_visible?(user) + else + author == user + end end def deletable?(user=User.current) - container && container.attachments_deletable?(user) + if container_id + container && container.attachments_deletable?(user) + else + author == user + end end def image? @@ -251,6 +263,37 @@ Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all end + # Moves an existing attachment to its target directory + def move_to_target_directory! + return unless !new_record? & readable? + + src = diskfile + self.disk_directory = target_directory + dest = diskfile + + return if src == dest + + if !FileUtils.mkdir_p(File.dirname(dest)) + logger.error "Could not create directory #{File.dirname(dest)}" if logger + return + end + + if !FileUtils.mv(src, dest) + logger.error "Could not move attachment from #{src} to #{dest}" if logger + return + end + + update_column :disk_directory, disk_directory + 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 + private # Physically deletes the file from the file system @@ -262,14 +305,21 @@ def sanitize_filename(value) # get only the filename, not the whole path - just_filename = value.gsub(/^.*(\\|\/)/, '') + just_filename = value.gsub(/\A.*(\\|\/)/m, '') # Finally, replace invalid characters with underscore - @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') + @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>\n\r]+/, '_') end - # Returns an ASCII or hashed filename - def self.disk_filename(filename) + # 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) timestamp = DateTime.now.strftime("%y%m%d%H%M%S") ascii = '' if filename =~ %r{^[a-zA-Z0-9_\.\-]*$} @@ -279,7 +329,7 @@ # keep the extension if any ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$} end - while File.exist?(File.join(@@storage_path, "#{timestamp}_#{ascii}")) + while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}")) timestamp.succ! end "#{timestamp}_#{ascii}"