2007-03-12 20:59:02 +03:00
# redMine - project management software
# Copyright (C) 2006-2007 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
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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.
#
# 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 "
class Attachment < ActiveRecord :: Base
belongs_to :container , :polymorphic = > true
belongs_to :author , :class_name = > " User " , :foreign_key = > " author_id "
2007-11-20 18:40:16 +03:00
validates_presence_of :container , :filename , :author
2007-07-16 21:16:49 +04:00
validates_length_of :filename , :maximum = > 255
validates_length_of :disk_filename , :maximum = > 255
2007-08-29 20:52:35 +04:00
acts_as_event :title = > :filename ,
2008-07-22 21:55:19 +04:00
:url = > Proc . new { | o | { :controller = > 'attachments' , :action = > 'download' , :id = > o . id , :filename = > o . filename } }
2007-08-29 20:52:35 +04:00
2008-07-27 21:54:09 +04:00
acts_as_activity_provider :type = > 'files' ,
:permission = > :view_files ,
:find_options = > { :select = > " #{ Attachment . table_name } .* " ,
:joins = > " LEFT JOIN #{ Version . table_name } ON #{ Attachment . table_name } .container_type='Version' AND #{ Version . table_name } .id = #{ Attachment . table_name } .container_id " +
" LEFT JOIN #{ Project . table_name } ON #{ Version . table_name } .project_id = #{ Project . table_name } .id " }
acts_as_activity_provider :type = > 'documents' ,
:permission = > :view_documents ,
:find_options = > { :select = > " #{ Attachment . table_name } .* " ,
: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 " }
2007-03-12 20:59:02 +03:00
cattr_accessor :storage_path
@@storage_path = " #{ RAILS_ROOT } /files "
def validate
errors . add_to_base :too_long if self . filesize > Setting . attachment_max_size . to_i . kilobytes
end
2008-04-03 01:30:32 +04:00
def file = ( incoming_file )
unless incoming_file . nil?
@temp_file = incoming_file
if @temp_file . size > 0
self . filename = sanitize_filename ( @temp_file . original_filename )
2008-05-17 15:03:43 +04:00
self . disk_filename = Attachment . disk_filename ( filename )
2008-04-03 01:30:32 +04:00
self . content_type = @temp_file . content_type . to_s . chomp
self . filesize = @temp_file . size
end
end
end
2007-03-12 20:59:02 +03:00
2008-04-03 01:30:32 +04:00
def file
nil
end
# Copy temp file to its final location
def before_save
if @temp_file && ( @temp_file . size > 0 )
logger . debug ( " saving ' #{ self . diskfile } ' " )
File . open ( diskfile , " wb " ) do | f |
f . write ( @temp_file . read )
end
self . digest = Digest :: MD5 . hexdigest ( File . read ( diskfile ) )
end
# 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
# Deletes file on the disk
def after_destroy
2008-05-22 22:26:43 +04:00
File . delete ( diskfile ) if ! filename . blank? && File . exist? ( diskfile )
2008-04-03 01:30:32 +04:00
end
# Returns file's location on disk
def diskfile
" #{ @@storage_path } / #{ self . disk_filename } "
end
2007-03-12 20:59:02 +03:00
def increment_download
increment! ( :downloads )
end
2007-05-26 19:42:37 +04:00
def project
2007-11-27 20:20:57 +03:00
container . project
2007-05-26 19:42:37 +04:00
end
2007-08-15 19:36:15 +04:00
def image?
2008-04-03 01:30:32 +04:00
self . filename =~ / \ .(jpe?g|gif|png)$ /i
2007-08-15 19:36:15 +04:00
end
2008-06-09 22:40:59 +04:00
def is_text?
Redmine :: MimeType . is_type? ( 'text' , filename )
end
2008-06-08 22:26:39 +04:00
def is_diff?
self . filename =~ / \ .(patch|diff)$ /i
end
2007-03-12 20:59:02 +03:00
private
def sanitize_filename ( value )
2008-04-03 01:30:32 +04:00
# get only the filename, not the whole path
just_filename = value . gsub ( / ^.*( \\ | \/ ) / , '' )
# NOTE: File.basename doesn't work right with Windows paths on Unix
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
2007-03-12 20:59:02 +03:00
2008-04-03 01:30:32 +04:00
# Finally, replace all non alphanumeric, hyphens or periods with underscore
@filename = just_filename . gsub ( / [^ \ w \ . \ -] / , '_' )
2007-03-12 20:59:02 +03:00
end
2008-05-17 15:03:43 +04:00
# Returns an ASCII or hashed filename
def self . disk_filename ( filename )
df = DateTime . now . strftime ( " %y%m%d%H%M%S " ) + " _ "
if filename =~ %r{ ^[a-zA-Z0-9_ \ . \ -]*$ }
df << filename
else
df << Digest :: MD5 . hexdigest ( filename )
# keep the extension if any
df << $1 if filename =~ %r{ ( \ .[a-zA-Z0-9]+)$ }
end
df
end
2006-06-28 22:11:03 +04:00
end