1 require 'zip/zipfilesystem'
3 # Files in the database are represented by Myfile.
4 # It's called Myfile, because File is a reserved word.
5 # Files are in (belong to) a folder and are uploaded by (belong to) a User.
6 class Myfile < ActiveRecord::Base
7 acts_as_ferret :store_class_name => true, :fields => { :text => { :store => :yes }, :filename => { :store => :no } }
13 has_many :clipboards, :dependent => :destroy
15 validates_uniqueness_of :filename, :scope => 'folder_id'
17 # Validate if the user's data is valid.
19 if self.filename.blank?
20 errors.add(:filename, " can't blank.")
22 if Folder.find_by_name_and_parent_id(self.filename, self.folder_id)
23 errors.add_to_base("You cannot upload a file with the same name as a folder.")
27 # Accessor that receives the data from the form in the view.
28 # The file will be saved in a folder called 'uploads'.
29 # (See: AWDWR pp. 362.)
30 def myfile=(myfile_field)
31 if myfile_field and myfile_field.length > 0
33 filename = Myfile.base_part_of(myfile_field.original_filename)
35 self.date_modified = Time.now
37 # Save the file on the file system
38 File.open(self.temp_path, 'wb') do |f|
39 while buff = myfile_field.read(4096)
44 # Save it all to the database
45 self.filename = filename
46 filesize = (myfile_field.length / 1024).to_i
48 self.filesize = 1 # a file of 0 KB doesn't make sense
50 self.filesize = filesize
58 # Try to get the text from the uploaded file
59 # Variable to hold the plain text content of the uploaded file
61 filename = self.filename
63 # Try the helpers first
64 INDEX_HELPERS.each do |index_helper| # defined in environment.rb
65 if filename =~ index_helper[:ext] # a matching helper!
67 if index_helper[:file_output] # a file that writes to an output file
68 `#{ sprintf(index_helper[:helper], self.temp_path, self.temp_path + '_copy') }`
69 if File.exists?(self.temp_path + '_copy') # avoid error messages if external prog
71 text_in_file = File.open(self.temp_path + '_copy') { |f| f.read }
72 File.delete(self.temp_path + '_copy')
76 else # we get the contents from stido directly
77 text_in_file = `#{ sprintf(index_helper[:helper], self.temp_path) }`
80 # Check if we need to remove first part (e.g. unrtf)
81 unless index_helper[:remove_before].blank?
82 if index_helper[:remove_before].match(text_in_file)
83 text_in_file = Regexp::last_match.post_match
87 # Check if we need to remove last part
88 unless index_helper[:remove_after].blank?
89 if index_helper[:remove_after].match(text_in_file)
90 text_in_file = Regexp::last_match.pre_match
96 unless text_in_file # no hits yet - try the built in
99 text_in_file = File.open(self.temp_path) { |f| f.read }
101 when /.htm$|.html$/ # get the file, strip all <> tags
102 text_in_file = File.open(self.temp_path) { |f| f.read.gsub(/<head>.*?<\/head>/m,'').gsub(/<.*?>/, ' ') }
104 when /.sxw$|.odt$/ # read content.xml from zip file, strip <> tags
105 Zip::ZipFile.open(self.temp_path) do |zipfile|
106 text_in_file = zipfile.file.open('content.xml') { |f| f.read.gsub(/<.*?>/, ' ') }
111 if text_in_file && !text_in_file.strip.empty?
112 self.text = text_in_file.strip # assign text_in_file to self.text to get it indexed
119 attr_writer :text # Setter for text
122 # If text is blank get the text from the index.
124 @text = Myfile.ferret_index[self.document_number][:text] if @text.blank?
127 after_create :index, :rename_newfile
128 # The file in the uploads folder has the same name as the id of the file.
129 # This must be done after_create, because the id won't be available any earlier.
131 File.rename self.temp_path, self.path
132 log_usage("uploaded")
135 before_destroy :delete_file_on_disk
136 # When removing a myfile record from the database,
137 # the actual file on disk has to be removed too.
138 # However, instead of deleting, we move it to the trash directory. Safer.
139 def delete_file_on_disk
140 if File.exists? self.path
141 new_name = "#{TRASH_PATH}/#{basename}.#{Time.now.to_f.to_s}"
142 log_usage("deleted","moved from #{self.path} to #{new_name}")
143 File.mv(self.path, new_name)
148 old_filename = self.filename
149 if self.update_attributes(:filename => filename, :date_modified => Time.now) && File.rename( self.folder.path_on_disk + "/" + old_filename, self.path )
151 log_usage("renamed","from #{old_filename} to #{self.filename}")
157 # Strip of the path and replace all the non alphanumeric,
158 # underscores and periods in the filename with an underscore.
159 def self.base_part_of(file_name)
160 # NOTE: File.basename doesn't work right with Windows paths on Unix
161 # INCORRECT: just_filename = File.basename(file_name.gsub('\\\\', '/'))
162 # get only the filename, not the whole path
163 name = file_name.gsub(/^.*(\\|\/)/, '')
165 # finally, replace all non alphanumeric, underscore or periods with space, and
166 # reduce all spaces to maximum one, with no trailing or leading
167 name.gsub(/[^\w\.\-]/, ' ').gsub(/([^\s])(\s+?)([^\s])/,'\1 \3').gsub(/([^\s])(\s+?)([^\s])/,'\1 \3').strip
171 return Myfile.base_part_of(self.filename)
174 # Returns the location of the file before it's saved
176 "#{TEMP_PATH}/#{self.date_modified.to_f}.tmp"
179 # The path of the file
181 File.join(self.folder.path_on_disk, basename)
185 FILE_ICONS.each do |f_icon|
186 if self.filename =~ f_icon[:ext]
193 def short_fname(length = 50)
194 return self.filename.shorten(length)
197 def log_usage(action, comment = nil)
199 :download_date_time => Time.now,
200 :user => User.logged_in_user,
202 :filename => self.filename,
211 File.open(file) { |f| return f.read }