post replacements: refactor and fix tests.
* Move replacement tests from test/unit/upload_service_test.rb to test/functional/post_replacement_controller_test.rb * Move UploadService::Replacer to PostReplacementProcessor. * Fix a minor bug where if you used the API to replace a post with a file, the replacement would fail unless you passed an empty string for the replacement_url.
This commit is contained in:
@@ -9,11 +9,11 @@ class PostReplacementsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
@post = authorize Post.find(params[:post_id]), policy_class: PostReplacementPolicy
|
||||
@post_replacement = @post.replace!(permitted_attributes(PostReplacement))
|
||||
@post_replacement = authorize PostReplacement.new(creator: CurrentUser.user, post_id: params[:post_id], **permitted_attributes(PostReplacement))
|
||||
@post_replacement.save
|
||||
@post_replacement.process!
|
||||
|
||||
flash[:notice] = "Post replaced"
|
||||
respond_with(@post_replacement, location: @post)
|
||||
respond_with(@post_replacement, location: @post_replacement.post, notice: "Post replaced")
|
||||
end
|
||||
|
||||
def update
|
||||
|
||||
72
app/logical/post_replacement_processor.rb
Normal file
72
app/logical/post_replacement_processor.rb
Normal file
@@ -0,0 +1,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class PostReplacementProcessor
|
||||
attr_reader :post, :replacement
|
||||
|
||||
def initialize(post:, replacement:)
|
||||
@post = post
|
||||
@replacement = replacement
|
||||
end
|
||||
|
||||
def process!
|
||||
media_file = get_file_for_upload(replacement.replacement_url, nil, replacement.replacement_file&.tempfile)
|
||||
|
||||
if Post.where.not(id: post.id).exists?(md5: media_file.md5)
|
||||
replacement.errors.add(:base, "Duplicate: post with md5 #{media_file.md5} already exists")
|
||||
return
|
||||
end
|
||||
|
||||
if media_file.md5 == post.md5
|
||||
media_asset = post.media_asset
|
||||
else
|
||||
media_asset = MediaAsset.upload!(media_file)
|
||||
end
|
||||
|
||||
if replacement.replacement_file.present?
|
||||
canonical_url = "file://#{replacement.replacement_file.original_filename}"
|
||||
else
|
||||
canonical_url = Sources::Strategies.find(replacement.replacement_url).canonical_url
|
||||
end
|
||||
|
||||
replacement.replacement_url = canonical_url
|
||||
replacement.file_ext = media_asset.file_ext
|
||||
replacement.file_size = media_asset.file_size
|
||||
replacement.image_height = media_asset.image_height
|
||||
replacement.image_width = media_asset.image_width
|
||||
replacement.md5 = media_asset.md5
|
||||
|
||||
post.md5 = media_asset.md5
|
||||
post.file_ext = media_asset.file_ext
|
||||
post.image_width = media_asset.image_width
|
||||
post.image_height = media_asset.image_height
|
||||
post.file_size = media_asset.file_size
|
||||
post.source = replacement.final_source.presence || replacement.replacement_url
|
||||
post.tag_string = replacement.tags
|
||||
|
||||
rescale_notes(post)
|
||||
|
||||
replacement.save!
|
||||
post.save!
|
||||
|
||||
post.update_iqdb
|
||||
end
|
||||
|
||||
def rescale_notes(post)
|
||||
x_scale = post.image_width.to_f / post.image_width_was.to_f
|
||||
y_scale = post.image_height.to_f / post.image_height_was.to_f
|
||||
|
||||
post.notes.each do |note|
|
||||
note.rescale!(x_scale, y_scale)
|
||||
end
|
||||
end
|
||||
|
||||
def get_file_for_upload(source_url, referer_url, file)
|
||||
return MediaFile.open(file) if file.present?
|
||||
raise "No file or source URL provided" if source_url.blank?
|
||||
|
||||
strategy = Sources::Strategies.find(source_url, referer_url)
|
||||
raise NotImplementedError, "No login credentials configured for #{strategy.site_name}." unless strategy.class.enabled?
|
||||
|
||||
strategy.download_file!
|
||||
end
|
||||
end
|
||||
@@ -1,83 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module UploadService
|
||||
class Replacer
|
||||
class Error < StandardError; end
|
||||
|
||||
attr_reader :post, :replacement
|
||||
|
||||
def initialize(post:, replacement:)
|
||||
@post = post
|
||||
@replacement = replacement
|
||||
end
|
||||
|
||||
def undo!
|
||||
undo_replacement = post.replacements.create(replacement_url: replacement.original_url)
|
||||
undoer = Replacer.new(post: post, replacement: undo_replacement)
|
||||
undoer.process!
|
||||
end
|
||||
|
||||
def replacement_url
|
||||
if replacement.replacement_file.present?
|
||||
"file://#{replacement.replacement_file.original_filename}"
|
||||
else
|
||||
Sources::Strategies.find(replacement.replacement_url).canonical_url
|
||||
end
|
||||
end
|
||||
|
||||
def process!
|
||||
media_file = get_file_for_upload(replacement.replacement_url, nil, replacement.replacement_file&.tempfile)
|
||||
|
||||
if Post.where.not(id: post.id).exists?(md5: media_file.md5)
|
||||
raise Error, "Duplicate: post with md5 #{media_file.md5} already exists"
|
||||
end
|
||||
|
||||
if media_file.md5 == post.md5
|
||||
media_asset = post.media_asset
|
||||
else
|
||||
media_asset = MediaAsset.upload!(media_file)
|
||||
end
|
||||
|
||||
replacement.replacement_url = replacement_url
|
||||
replacement.file_ext = media_asset.file_ext
|
||||
replacement.file_size = media_asset.file_size
|
||||
replacement.image_height = media_asset.image_height
|
||||
replacement.image_width = media_asset.image_width
|
||||
replacement.md5 = media_asset.md5
|
||||
|
||||
post.md5 = media_asset.md5
|
||||
post.file_ext = media_asset.file_ext
|
||||
post.image_width = media_asset.image_width
|
||||
post.image_height = media_asset.image_height
|
||||
post.file_size = media_asset.file_size
|
||||
post.source = replacement.final_source.presence || replacement.replacement_url
|
||||
post.tag_string = replacement.tags
|
||||
|
||||
rescale_notes(post)
|
||||
|
||||
replacement.save!
|
||||
post.save!
|
||||
|
||||
post.update_iqdb
|
||||
end
|
||||
|
||||
def rescale_notes(post)
|
||||
x_scale = post.image_width.to_f / post.image_width_was.to_f
|
||||
y_scale = post.image_height.to_f / post.image_height_was.to_f
|
||||
|
||||
post.notes.each do |note|
|
||||
note.rescale!(x_scale, y_scale)
|
||||
end
|
||||
end
|
||||
|
||||
def get_file_for_upload(source_url, referer_url, file)
|
||||
return MediaFile.open(file) if file.present?
|
||||
raise "No file or source URL provided" if source_url.blank?
|
||||
|
||||
strategy = Sources::Strategies.find(source_url, referer_url)
|
||||
raise NotImplementedError, "No login credentials configured for #{strategy.site_name}." unless strategy.class.enabled?
|
||||
|
||||
strategy.download_file!
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -842,13 +842,6 @@ class Post < ApplicationRecord
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def replace!(params)
|
||||
replacement = replacements.create(params)
|
||||
processor = UploadService::Replacer.new(post: self, replacement: replacement)
|
||||
processor.process!
|
||||
replacement
|
||||
end
|
||||
end
|
||||
|
||||
module VersionMethods
|
||||
|
||||
@@ -6,8 +6,9 @@ class PostReplacement < ApplicationRecord
|
||||
before_validation :initialize_fields, on: :create
|
||||
attr_accessor :replacement_file, :final_source, :tags
|
||||
|
||||
attribute :replacement_url, default: ""
|
||||
|
||||
def initialize_fields
|
||||
self.creator = CurrentUser.user
|
||||
self.original_url = post.source
|
||||
self.tags = "#{post.tag_string} #{tags}"
|
||||
|
||||
@@ -27,6 +28,10 @@ class PostReplacement < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def process!
|
||||
PostReplacementProcessor.new(post: post, replacement: self).process!
|
||||
end
|
||||
|
||||
def suggested_tags_for_removal
|
||||
tags = post.tag_array.select do |tag|
|
||||
Danbooru.config.post_replacement_tag_removals.any? do |pattern|
|
||||
|
||||
Reference in New Issue
Block a user