ensl.org/app/models/data_file.rb
2020-04-06 23:54:10 +03:00

183 lines
5.2 KiB
Ruby

# == Schema Information
#
# Table name: data_files
#
# id :integer not null, primary key
# description :string(255)
# md5 :string(255)
# name :string(255)
# path :string(255)
# size :integer not null
# created_at :datetime
# updated_at :datetime
# article_id :integer
# directory_id :integer
# related_id :integer
#
# Indexes
#
# index_data_files_on_article_id (article_id)
# index_data_files_on_directory_id (directory_id)
# index_data_files_on_related_id (related_id)
#
# DataFile uses CarrierWave to manage files. The attrribute 'name' is the most crucial attribute.
# Avoid using .path for anything, rather use .location which is alias.
require 'digest/md5'
class DataFile < ActiveRecord::Base
include Extra
MEGABYTE = 1_048_576
attr_accessor :related_id
scope :recent, -> { order("created_at DESC").limit(8) }
scope :demos, -> { order("created_at DESC").where("directory_id IN (SELECT id FROM directories WHERE parent_id = ?)", Directory::DEMOS) }
scope :ordered, -> { order("created_at DESC") }
scope :movies, -> { order("created_at DESC").where({:directory_id => Directory::MOVIES}) }
scope :not, -> (file) { where.not(id: file.id) }
scope :unrelated, -> { where("related_id is null") }
has_many :related_files, :class_name => "DataFile", :foreign_key => :related_id
has_many :comments, :as => :commentable
has_one :movie, :foreign_key => :file_id, :dependent => :destroy
has_one :preview, :class_name => "Movie", :foreign_key => :preview_id, :dependent => :nullify
has_one :match, :foreign_key => :demo_id
belongs_to :directory, :optional => true
belongs_to :related, :class_name => "DataFile", :optional => true
belongs_to :article, :optional => true
validates_length_of [:description, :path], :maximum => 255
before_save :process_file
after_create :create_movie, :if => Proc.new {|file| file.directory_id == Directory::MOVIES and !file.location.include?("_preview.mp4") }
after_save :update_relations, :if => Proc.new { |file| file.related_id_changed? and related_files.count > 0 }
# acts_as_rateable
mount_uploader :name, FileUploader
def to_s
description&.empty? ? File.basename(name.to_s) : description
end
def md5_s
md5.upcase
end
def extra_url
url.to_s.gsub(/^\/files/, "http://extra.ensl.org/static")
end
def size_s
(size.to_f/MEGABYTE).round(2).to_s + " MB"
end
# Just an alias, use this to find the file's current path
def location
name.current_path
end
def url
name.url
end
def manual_upload(manual_location)
File.open(manual_location) do |f|
self.name = f
end
end
def process_file
self.md5 = "e948c22100d29623a1df48e1760494df"
if article
self.directory_id = Directory::ARTICLES
end
if File.exists?(location) and (new_record? or size != File.size(location) or created_at != File.mtime(location))
self.md5 = Digest::MD5.hexdigest(File.read(location))
self.size = File.size(location)
self.created_at = File.mtime(location)
end
# Update the path on creation
# Move the file if it has moved
if !new_record? and directory_id_changed? and File.exists?(path)
FileUtils.mv(path, location)
end
if path.nil? or directory_id_changed?
self.path = File.join(directory.full_path, File.basename(name.to_s))
end
if description.nil? or description.empty?
self.description = File.basename(location).gsub(/[_\-]/, " ").gsub(/\.\w{1,5}$/, "")
self.description = description.split(/\s+/).each{ |word| word.capitalize! }.join(' ')
end
if match
self.description = match.contester1.to_s + " vs " + match.contester2.to_s
end
if location.include? "_preview.mp4" and !related
stripped = location.gsub(/_preview\.mp4/, "")
DataFile.where(["path LIKE ?", stripped + "%"]).each do |r|
if r.location.match(/#{stripped}\.\w{1,5}$/)
self.related = r
end
end
end
if movie and (new_record? or md5_changed?)
movie.get_length
end
end
def create_movie
movie = Movie.new
movie.file = self
movie.make_snapshot 5
movie.save
end
def update_relations
related_files.each do |rf|
rf.related = self.related
rf.save
end
end
def rateable? user
user and !rated_by?(user)
end
# TODO: instead of using path, use name + directory path
def self.find_existing(subitem_path, subitem_name)
hash = Digest::MD5.hexdigest(File.read(subitem_path))
DataFile.where(arel_table[:path].eq(subitem_path)\
.or(arel_table[:md5].eq(hash))).first
end
def can_create? cuser
return false unless cuser
return false if cuser.banned?(Ban::TYPE_MUTE)
(cuser.admin? or \
(article and article.can_create? cuser) or \
(directory_id == Directory::MOVIES and cuser.has_access? Group::MOVIES))
end
def can_update? cuser
cuser and cuser.admin? or (article and article.can_create? cuser)
end
def can_destroy? cuser
cuser and cuser.admin? or (article and article.can_create? cuser)
end
def self.params(params, cuser)
params.require(:data_file).permit(:description, :name, :article_id, :related_id, :directory_id)
end
end