applied my changes - initial import
[boxroom-stian.git] / app / models / myfile.rb
blobd20b3de17775468c254f6aa4fd8124163bc1c013
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 } }
9   belongs_to :folder
10   belongs_to :user
12   has_many :usages
13   has_many :clipboards, :dependent => :destroy
15   validates_uniqueness_of :filename, :scope => 'folder_id'
17   # Validate if the user's data is valid.
18   def validate
19     if self.filename.blank?
20       errors.add(:filename, " can't blank.")
21     end
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.")
24     end
25   end
26   
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
32       # Get the filename
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)
40           f.write(buff)
41         end
42       end
44       # Save it all to the database
45       self.filename = filename
46       filesize = (myfile_field.length / 1024).to_i
47       if filesize == 0
48         self.filesize = 1 # a file of 0 KB doesn't make sense
49       else
50         self.filesize = filesize
51       end
53     end
54   end
57   def index
58     # Try to get the text from the uploaded file
59     # Variable to hold the plain text content of the uploaded file
60     text_in_file = nil
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           
70                                                       # borks
71             text_in_file = File.open(self.temp_path + '_copy') { |f| f.read }
72             File.delete(self.temp_path + '_copy')
73           else
74             text_in_file = ""
75           end
76         else # we get the contents from stido directly
77           text_in_file = `#{ sprintf(index_helper[:helper], self.temp_path) }`
78         end
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 
84           end
85         end
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
91           end
92         end
93       end
94     end
96     unless text_in_file # no hits yet - try the built in 
97       case filename
98         when /.txt$/
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(/<.*?>/, ' ') }
107           end
108       end
109     end
110     
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
113       self.indexed = true
114       self.save
115     end
116   end
119   attr_writer :text # Setter for text
121   # Getter for text.
122   # If text is blank get the text from the index.
123   def text
124     @text = Myfile.ferret_index[self.document_number][:text] if @text.blank?
125   end
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.
130   def rename_newfile
131     File.rename self.temp_path, self.path
132     log_usage("uploaded")
133   end
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)
144     end    
145   end
146   
147   def rename(filename)
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 )
150     
151       log_usage("renamed","from #{old_filename} to #{self.filename}")
152     else
153       return false
154     end
155   end
156     
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
168   end
170   def basename
171     return Myfile.base_part_of(self.filename)
172   end
174   # Returns the location of the file before it's saved
175   def temp_path
176     "#{TEMP_PATH}/#{self.date_modified.to_f}.tmp" 
177   end
179   # The path of the file
180   def path
181     File.join(self.folder.path_on_disk, basename)
182   end
183   
184   def icon_file
185     FILE_ICONS.each do |f_icon|
186       if self.filename =~ f_icon[:ext]
187         return f_icon[:icon]
188       end
189     end
190     return 'file.png'
191   end
192   
193   def short_fname(length = 50)
194     return self.filename.shorten(length)
195   end
196      
197   def log_usage(action, comment = nil)
198     usage = Usage.new(
199       :download_date_time => Time.now,
200       :user => User.logged_in_user,
201       :myfile => self,
202       :filename => self.filename,
203       :action => action,
204       :comment => comment 
205       ).save
206   end
207      
208      
209   private
210   def read_file(file)
211     File.open(file) { |f| return f.read }
212   end  
213