forked from e621ng/e621ng
Move deleted posts to a protected folder
Set up support for moving deleted files to a protected location and support for emitting urls with authorization parameters to permit access to them. This closes #14
This commit is contained in:
parent
833f9208df
commit
895fa25c03
@ -21,7 +21,7 @@ module Moderator
|
||||
|
||||
def undelete
|
||||
@post = ::Post.find(params[:id])
|
||||
@post.approve!
|
||||
@post.undelete!
|
||||
end
|
||||
|
||||
def confirm_move_favorites
|
||||
|
@ -3,11 +3,15 @@ class StorageManager
|
||||
|
||||
DEFAULT_BASE_DIR = "#{Rails.root}/public/data"
|
||||
|
||||
attr_reader :base_url, :base_dir, :hierarchical, :tagged_filenames, :large_image_prefix
|
||||
attr_reader :base_url, :base_dir, :hierarchical, :tagged_filenames, :large_image_prefix, :base_url_protected, :base_dir_protected
|
||||
|
||||
def initialize(base_url: default_base_url, base_dir: DEFAULT_BASE_DIR, hierarchical: false, tagged_filenames: Danbooru.config.enable_seo_post_urls, large_image_prefix: Danbooru.config.large_image_prefix)
|
||||
def initialize(base_url: default_base_url, base_dir: DEFAULT_BASE_DIR, hierarchical: false,
|
||||
tagged_filenames: Danbooru.config.enable_seo_post_urls, large_image_prefix: Danbooru.config.large_image_prefix,
|
||||
protected_prefix: Danbooru.config.protected_path_prefix)
|
||||
@base_url = base_url.chomp("/")
|
||||
@base_url_protected = "#{@base_url}/#{protected_prefix}"
|
||||
@base_dir = base_dir
|
||||
@base_dir_protected = "#{@base_dir}/#{protected_prefix}"
|
||||
@hierarchical = hierarchical
|
||||
@tagged_filenames = tagged_filenames
|
||||
@large_image_prefix = large_image_prefix
|
||||
@ -48,21 +52,44 @@ class StorageManager
|
||||
open(file_path(post.md5, post.file_ext, type))
|
||||
end
|
||||
|
||||
def move_file_delete(post)
|
||||
raise NotImplementedError, "move_file_delete not implemented"
|
||||
end
|
||||
|
||||
def move_file_undelete(post)
|
||||
raise NotImplementedError, "move_file_undelete not implemented"
|
||||
end
|
||||
|
||||
def protected_params(url, post)
|
||||
user_id = CurrentUser.id
|
||||
ip = CurrentUser.ip_addr
|
||||
time = (Time.now + 15.minute).to_i
|
||||
secret = Danbooru.config.protected_file_secret
|
||||
hmac = Digest::MD5.base64digest("#{time} #{url} #{user_id} #{secret}").tr("+/","-_").gsub("==",'')
|
||||
"?auth=#{hmac}&expires=#{time}&uid=#{user_id}"
|
||||
end
|
||||
|
||||
def file_url(post, type, tagged_filenames: false)
|
||||
subdir = subdir_for(post.md5)
|
||||
file = file_name(post.md5, post.file_ext, type)
|
||||
seo_tags = seo_tags(post) if tagged_filenames
|
||||
base = post.protect_file? ? base_url_protected : base_url
|
||||
|
||||
if type == :preview && !post.has_preview?
|
||||
url = if type == :preview && !post.has_preview?
|
||||
"#{root_url}/images/download-preview.png"
|
||||
elsif type == :preview
|
||||
"#{base_url}/preview/#{subdir}#{file}"
|
||||
"#{base}/preview/#{subdir}#{file}"
|
||||
elsif type == :crop
|
||||
"#{base_url}/crop/#{subdir}#{file}"
|
||||
"#{base}/crop/#{subdir}#{file}"
|
||||
elsif type == :large && post.has_large?
|
||||
"#{base_url}/sample/#{subdir}#{seo_tags}#{file}"
|
||||
"#{base}/sample/#{subdir}#{seo_tags}#{file}"
|
||||
else
|
||||
"#{base_url}/#{subdir}#{seo_tags}#{post.md5}.#{post.file_ext}"
|
||||
"#{base}/#{subdir}#{seo_tags}#{post.md5}.#{post.file_ext}"
|
||||
end
|
||||
if post.protect_file?
|
||||
"#{url}#{protected_params(url, post)}" if post.protect_file?
|
||||
else
|
||||
url
|
||||
end
|
||||
end
|
||||
|
||||
@ -72,20 +99,21 @@ class StorageManager
|
||||
origin
|
||||
end
|
||||
|
||||
def file_path(post_or_md5, file_ext, type)
|
||||
def file_path(post_or_md5, file_ext, type, protected=false)
|
||||
md5 = post_or_md5.is_a?(String) ? post_or_md5 : post_or_md5.md5
|
||||
subdir = subdir_for(md5)
|
||||
file = file_name(md5, file_ext, type)
|
||||
base = protected ? base_dir_protected : base_dir
|
||||
|
||||
case type
|
||||
when :preview
|
||||
"#{base_dir}/preview/#{subdir}#{file}"
|
||||
"#{base}/preview/#{subdir}#{file}"
|
||||
when :crop
|
||||
"#{base_dir}/crop/#{subdir}#{file}"
|
||||
"#{base}/crop/#{subdir}#{file}"
|
||||
when :large
|
||||
"#{base_dir}/sample/#{subdir}#{file}"
|
||||
"#{base}/sample/#{subdir}#{file}"
|
||||
when :original
|
||||
"#{base_dir}/#{subdir}#{file}"
|
||||
"#{base}/#{subdir}#{file}"
|
||||
end
|
||||
end
|
||||
|
||||
@ -105,11 +133,7 @@ class StorageManager
|
||||
end
|
||||
|
||||
def subdir_for(md5)
|
||||
if hierarchical
|
||||
"#{md5[0..1]}/#{md5[2..3]}/"
|
||||
else
|
||||
""
|
||||
end
|
||||
hierarchical ? "#{md5[0..1]}/#{md5[2..3]}/" : ""
|
||||
end
|
||||
|
||||
def seo_tags(post)
|
||||
|
@ -1,5 +1,6 @@
|
||||
class StorageManager::Local < StorageManager
|
||||
DEFAULT_PERMISSIONS = 0644
|
||||
IMAGE_TYPES = %i[preview large crop original]
|
||||
|
||||
def store(io, dest_path)
|
||||
temp_path = dest_path + "-" + SecureRandom.uuid + ".tmp"
|
||||
@ -23,4 +24,30 @@ class StorageManager::Local < StorageManager
|
||||
def open(path)
|
||||
File.open(path, "r", binmode: true)
|
||||
end
|
||||
|
||||
def move_file_delete(post)
|
||||
IMAGE_TYPES.each do |type|
|
||||
path = file_path(post, post.file_ext, type, false)
|
||||
new_path = file_path(post, post.file_ext, type, true)
|
||||
move_file(path, new_path)
|
||||
end
|
||||
end
|
||||
|
||||
def move_file_undelete(post)
|
||||
IMAGE_TYPES.each do |type|
|
||||
path = file_path(post, post.file_ext, type, true)
|
||||
new_path = file_path(post, post.file_ext, type, false)
|
||||
move_file(path, new_path)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def move_file(old_path, new_path)
|
||||
if File.exists?(old_path)
|
||||
FileUtils.mkdir_p(File.dirname(new_path))
|
||||
FileUtils.mv(old_path, new_path)
|
||||
FileUtils.chmod(DEFAULT_PERMISSIONS, new_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -96,6 +96,14 @@ class Post < ApplicationRecord
|
||||
Post.delete_files(id, md5, file_ext, force: true)
|
||||
end
|
||||
|
||||
def move_files_on_delete
|
||||
Danbooru.config.storage_manager.move_file_delete(self)
|
||||
end
|
||||
|
||||
def move_files_on_undelete
|
||||
Danbooru.config.storage_manager.move_file_undelete(self)
|
||||
end
|
||||
|
||||
def distribute_files(file, sample_file, preview_file)
|
||||
storage_manager.store_file(file, self, :original)
|
||||
storage_manager.store_file(sample_file, self, :large) if sample_file.present?
|
||||
@ -1374,6 +1382,10 @@ class Post < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def protect_file?
|
||||
is_banned || is_deleted
|
||||
end
|
||||
|
||||
def ban!
|
||||
update_column(:is_banned, true)
|
||||
ModAction.log("banned post ##{id}",:post_ban)
|
||||
@ -1400,6 +1412,8 @@ class Post < ApplicationRecord
|
||||
is_banned: is_banned || options[:ban] || has_tag?("banned_artist")
|
||||
)
|
||||
|
||||
move_files_on_delete
|
||||
|
||||
# XXX This must happen *after* the `is_deleted` flag is set to true (issue #3419).
|
||||
give_favorites_to_parent(options) if options[:move_favorites]
|
||||
|
||||
@ -1427,6 +1441,8 @@ class Post < ApplicationRecord
|
||||
self.approver_id = CurrentUser.id
|
||||
flags.each {|x| x.resolve!}
|
||||
save
|
||||
move_files_on_undelete
|
||||
approvals.create(user: CurrentUser.user)
|
||||
ModAction.log("undeleted post ##{id}",:post_undelete)
|
||||
end
|
||||
|
||||
|
@ -124,6 +124,14 @@ module Danbooru
|
||||
"sample-"
|
||||
end
|
||||
|
||||
def protected_path_prefix
|
||||
"deleted"
|
||||
end
|
||||
|
||||
def protected_file_secret
|
||||
"abc123"
|
||||
end
|
||||
|
||||
# When calculating statistics based on the posts table, gather this many posts to sample from.
|
||||
def post_sample_size
|
||||
300
|
||||
|
Loading…
Reference in New Issue
Block a user