Add semi-working recreate for dirs

This commit is contained in:
Ari Timonen 2020-03-31 20:26:55 +03:00
parent b79220466b
commit 2aea81d063
3 changed files with 50 additions and 43 deletions

View file

@ -20,6 +20,11 @@ class DirectoriesController < ApplicationController
raise AccessError unless @directory.can_update? cuser raise AccessError unless @directory.can_update? cuser
end end
def recreate
@directory.recreate_transaction
render text: t(:directories_update)
end
def refresh def refresh
@directory.process_dir @directory.process_dir
render text: t(:directories_update) render text: t(:directories_update)

View file

@ -97,7 +97,7 @@ class DataFile < ActiveRecord::Base
end end
# Update the path on creation # Update the path on creation
if path.nil? or directory_id_changed? if path.nil?
self.path = File.join(directory.path, File.basename(name.to_s)) self.path = File.join(directory.path, File.basename(name.to_s))
end end
@ -147,6 +147,11 @@ class DataFile < ActiveRecord::Base
user and !rated_by?(user) user and !rated_by?(user)
end end
def self.find_existing(subdir_name, subitem_path)
DataFile.where(arel_tabe(:path).eq(subitem_path)\
.or(arel_table(:md5).eq(Digest::MD5.hexdigest(File.read(subitem_path))))).first
end
def can_create? cuser def can_create? cuser
return false unless cuser return false unless cuser
return false if cuser.banned?(Ban::TYPE_MUTE) return false if cuser.banned?(Ban::TYPE_MUTE)

View file

@ -108,10 +108,10 @@ class Directory < ActiveRecord::Base
logger.info 'Starting recreate on %d, root: %s' % [id, root] logger.info 'Starting recreate on %d, root: %s' % [id, root]
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
# We use destroy lists so technically there can be seperate roots # We use destroy lists so technically there can be seperate roots
destroy_list = Hash.new destroy_dirs = Hash.new
update_attribute :path, root update_attribute :path, root
destroy_list = recreate(destroy_list) destroy_dirs = recreate(destroy_dirs)
destroy_list.each do |key, dir| destroy_dirs.each do |key, dir|
logger.info 'Removed dir: %s' % dir.full_path logger.info 'Removed dir: %s' % dir.full_path
# dir.destroy! # dir.destroy!
end end
@ -122,26 +122,26 @@ class Directory < ActiveRecord::Base
end end
# QUESTION Symlinks? # QUESTION Symlinks?
def recreate(destroy_list, path = self.full_path) def recreate(destroy_dirs, path = self.full_path)
# Convert all subdirs into a hash and mark them to be deleted # Convert all subdirs into a hash and mark them to be deleted
# FIXME: better oneliner # FIXME: better oneliner
destroy_list.merge!(subdirs.all.map{ |s| [s.id,s] }.to_h) destroy_dirs.merge!(subdirs.all.map{ |s| [s.id,s] }.to_h)
# Go through all subdirectories (no recursion) # Go through all subdirectories (no recursion)
Dir.glob("%s/*" % path).each do |subdir_path| Dir.glob("%s/*" % path).each do |subitem_path|
if File.directory? subdir_path if File.directory? subitem_path
subdir_name = File.basename(subdir_path) subdir_name = File.basename(subitem_path)
# We find by name only, ignore path # We find by name only, ignore path
# Find existing subdirs from current path. Keep those we find # Find existing subdirs from current path. Keep those we find
if (subdir = find_existing(subdir_name)) if (subdir = find_existing(subdir_name, subitem_path))
if subdir.parent_id != self.id if subdir.parent_id != self.id
old_path = subdir.full_path old_path = subdir.full_path
subdir.parent = self subdir.parent = self
subdir.save! subdir.save!
logger.info 'Renamed dir: %s -> %s' % [old_path, subdir.full_path] logger.info 'Renamed dir: %s -> %s' % [old_path, subdir.full_path]
end end
destroy_list.delete subdir.id destroy_dirs.delete subdir.id
# In case its a new directory # In case its a new directory
else else
# Attempt to find it in existing directories # Attempt to find it in existing directories
@ -152,13 +152,24 @@ class Directory < ActiveRecord::Base
end end
# Recreate the directory # Recreate the directory
destroy_list = subdir.recreate(destroy_list) destroy_dirs = subdir.recreate(destroy_dirs)
elsif File.file? subitem_path
if dbfile = DataFile.find_existing(subitem_path, subitem_name)
dbfile.directory = self
dbfile.save!
elsif (File.mtime(file) + 100).past?
dbfile = DataFile.new
dbfile.path = file
dbfile.directory = self
dbfile.save!
end
# TODO: handle files that are only in database
end end
end end
return destroy_list return destroy_dirs
end end
def find_existing(subdir_name) def find_existing(subdir_name, subitem_path)
# Find by name # Find by name
if (dir = subdirs.where(name: subdir_name)).exists? if (dir = subdirs.where(name: subdir_name)).exists?
return dir.first return dir.first
@ -169,41 +180,27 @@ class Directory < ActiveRecord::Base
return dir return dir
end end
end end
# TODO: use filter_map here
# NOTE: we don't use the logic from dat_file
file_count = Dir["%s/*" % subitem_path].count{|f| File.file?(f) }
Directory.joins(:files).group('data_files.directory_id')\
.having('count(data_files.id) = ? and count(data_files.id) > 0', file_count).each do |dir|
Dir.glob(File.join(dir.full_path, '*')).each do |filename|
return false if File.size(file) != dir.files.where(name: filename).first&.size
end
return dir
end
# TODO: Find by number of files + hash of files # TODO: Find by number of files + hash of files
end end
return false return false
end end
# TODO check that you can download files # TODO
def recreate_check
true
end
def process_dir # TODO check that you can download files
ActiveRecord::Base.transaction do
Dir.glob("#{full_path}/*").each do |file|
if File.directory?(file)
if dir = Directory.find_by_path(file)
dir.save!
else
dir = Directory.new
dir.name = File.basename(file)
dir.path = file
dir.parent = self
dir.save!
end
dir.process_dir
else
if dbfile = DataFile.find_by_path(file)
dbfile.directory = self
dbfile.save!
elsif (File.mtime(file) + 100).past?
dbfile = DataFile.new
dbfile.path = file
dbfile.directory = self
dbfile.save!
end
end
end
end
end
def can_create? cuser def can_create? cuser
cuser and cuser.admin? cuser and cuser.admin?