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
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@post = authorize Post.find(params[:post_id]), policy_class: PostReplacementPolicy
|
@post_replacement = authorize PostReplacement.new(creator: CurrentUser.user, post_id: params[:post_id], **permitted_attributes(PostReplacement))
|
||||||
@post_replacement = @post.replace!(permitted_attributes(PostReplacement))
|
@post_replacement.save
|
||||||
|
@post_replacement.process!
|
||||||
|
|
||||||
flash[:notice] = "Post replaced"
|
respond_with(@post_replacement, location: @post_replacement.post, notice: "Post replaced")
|
||||||
respond_with(@post_replacement, location: @post)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace!(params)
|
|
||||||
replacement = replacements.create(params)
|
|
||||||
processor = UploadService::Replacer.new(post: self, replacement: replacement)
|
|
||||||
processor.process!
|
|
||||||
replacement
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module VersionMethods
|
module VersionMethods
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ class PostReplacement < ApplicationRecord
|
|||||||
before_validation :initialize_fields, on: :create
|
before_validation :initialize_fields, on: :create
|
||||||
attr_accessor :replacement_file, :final_source, :tags
|
attr_accessor :replacement_file, :final_source, :tags
|
||||||
|
|
||||||
|
attribute :replacement_url, default: ""
|
||||||
|
|
||||||
def initialize_fields
|
def initialize_fields
|
||||||
self.creator = CurrentUser.user
|
|
||||||
self.original_url = post.source
|
self.original_url = post.source
|
||||||
self.tags = "#{post.tag_string} #{tags}"
|
self.tags = "#{post.tag_string} #{tags}"
|
||||||
|
|
||||||
@@ -27,6 +28,10 @@ class PostReplacement < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process!
|
||||||
|
PostReplacementProcessor.new(post: post, replacement: self).process!
|
||||||
|
end
|
||||||
|
|
||||||
def suggested_tags_for_removal
|
def suggested_tags_for_removal
|
||||||
tags = post.tag_array.select do |tag|
|
tags = post.tag_array.select do |tag|
|
||||||
Danbooru.config.post_replacement_tag_removals.any? do |pattern|
|
Danbooru.config.post_replacement_tag_removals.any? do |pattern|
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ FactoryBot.define do
|
|||||||
post factory: :post, source: FFaker::Internet.http_url
|
post factory: :post, source: FFaker::Internet.http_url
|
||||||
original_url { FFaker::Internet.http_url }
|
original_url { FFaker::Internet.http_url }
|
||||||
replacement_url { FFaker::Internet.http_url }
|
replacement_url { FFaker::Internet.http_url }
|
||||||
|
creator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,36 +2,161 @@ require 'test_helper'
|
|||||||
|
|
||||||
class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
|
class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
|
||||||
context "The post replacements controller" do
|
context "The post replacements controller" do
|
||||||
setup do
|
|
||||||
@mod = create(:moderator_user, name: "yukari", can_approve_posts: true, created_at: 1.month.ago)
|
|
||||||
as(@mod) do
|
|
||||||
@post = create(:post, source: "https://google.com", tag_string: "touhou")
|
|
||||||
@post_replacement = create(:post_replacement, post: @post)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "create action" do
|
context "create action" do
|
||||||
should "render" do
|
context "replacing a post from a source url" do
|
||||||
params = {
|
should "replace the post" do
|
||||||
format: :json,
|
assert_difference("PostReplacement.count") do
|
||||||
post_id: @post.id,
|
@post = create(:post)
|
||||||
post_replacement: {
|
|
||||||
replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_difference("PostReplacement.count") do
|
post_auth post_replacements_path, create(:moderator_user), params: {
|
||||||
post_auth post_replacements_path, @mod, params: params
|
format: :json,
|
||||||
assert_response :success
|
post_id: @post.id,
|
||||||
|
post_replacement: {
|
||||||
|
replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
@replacement = PostReplacement.last
|
||||||
|
assert_equal(459, @replacement.image_width)
|
||||||
|
assert_equal(650, @replacement.image_height)
|
||||||
|
assert_equal(127_238, @replacement.file_size)
|
||||||
|
assert_equal("jpg", @replacement.file_ext)
|
||||||
|
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @replacement.md5)
|
||||||
|
|
||||||
|
assert_equal(@post.image_width, @replacement.old_image_width)
|
||||||
|
assert_equal(@post.image_height, @replacement.old_image_height)
|
||||||
|
assert_equal(@post.file_size, @replacement.old_file_size)
|
||||||
|
assert_equal(@post.file_ext, @replacement.old_file_ext)
|
||||||
|
assert_equal(@post.md5, @replacement.old_md5)
|
||||||
|
|
||||||
|
@post.reload
|
||||||
|
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @post.md5)
|
||||||
|
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @post.media_asset.variant(:original).open_file.md5)
|
||||||
|
assert_equal("https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg", @post.source)
|
||||||
|
assert_equal(459, @post.image_width)
|
||||||
|
assert_equal(650, @post.image_height)
|
||||||
|
assert_equal(127_238, @post.file_size)
|
||||||
|
assert_equal("jpg", @post.file_ext)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
assert_equal("https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg", @post.reload.source)
|
context "replacing a post with the same file" do
|
||||||
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @post.md5)
|
should "only change the source to the final source" do
|
||||||
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", Digest::MD5.file(@post.file(:original)).hexdigest)
|
@post = create(:post)
|
||||||
|
|
||||||
|
post_auth post_replacements_path, create(:moderator_user), params: {
|
||||||
|
format: :json,
|
||||||
|
post_id: @post.id,
|
||||||
|
post_replacement: {
|
||||||
|
replacement_file: Rack::Test::UploadedFile.new("test/files/test.png"),
|
||||||
|
final_source: "blah",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_equal("blah", @post.reload.source)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a post with the same MD5 already exists" do
|
||||||
|
should "return an error" do
|
||||||
|
@post1 = create(:post, md5: "ecef68c44edb8a0d6a3070b5f8e8ee76", file_size: 1234)
|
||||||
|
@post2 = create(:post, file_size: 789)
|
||||||
|
|
||||||
|
post_auth post_replacements_path, create(:moderator_user), params: {
|
||||||
|
format: :json,
|
||||||
|
post_id: @post2.id,
|
||||||
|
post_replacement: {
|
||||||
|
replacement_file: Rack::Test::UploadedFile.new("test/files/test.jpg"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response 422
|
||||||
|
assert_equal(789, @post2.reload.file_size)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "replacing a post with a Pixiv page URL" do
|
||||||
|
should "replace with the full size image" do
|
||||||
|
@post = create(:post)
|
||||||
|
|
||||||
|
post_auth post_replacements_path, create(:moderator_user), params: {
|
||||||
|
format: :json,
|
||||||
|
post_id: @post.id,
|
||||||
|
post_replacement: {
|
||||||
|
replacement_url: "https://www.pixiv.net/en/artworks/62247350",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_equal(80, @post.reload.image_width)
|
||||||
|
assert_equal(82, @post.image_height)
|
||||||
|
assert_equal(16_275, @post.file_size)
|
||||||
|
assert_equal("png", @post.file_ext)
|
||||||
|
assert_equal("4ceadc314938bc27f3574053a3e1459a", @post.md5)
|
||||||
|
assert_equal("4ceadc314938bc27f3574053a3e1459a", Digest::MD5.file(@post.file).hexdigest)
|
||||||
|
assert_equal("https://i.pximg.net/img-original/img/2017/04/04/08/54/15/62247350_p0.png", @post.replacements.last.replacement_url)
|
||||||
|
assert_equal("https://i.pximg.net/img-original/img/2017/04/04/08/54/15/62247350_p0.png", @post.source)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "replacing a post with a Pixiv ugoira" do
|
||||||
|
should "save the frame data" do
|
||||||
|
skip "Pixiv credentials not configured" unless Sources::Strategies::Pixiv.enabled?
|
||||||
|
|
||||||
|
@post = create(:post)
|
||||||
|
post_auth post_replacements_path, create(:moderator_user), params: {
|
||||||
|
format: :json,
|
||||||
|
post_id: @post.id,
|
||||||
|
post_replacement: {
|
||||||
|
replacement_url: "https://www.pixiv.net/en/artworks/62247364",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_equal(80, @post.reload.image_width)
|
||||||
|
assert_equal(82, @post.image_height)
|
||||||
|
assert_equal(2804, @post.file_size)
|
||||||
|
assert_equal("zip", @post.file_ext)
|
||||||
|
assert_equal("cad1da177ef309bf40a117c17b8eecf5", @post.md5)
|
||||||
|
assert_equal("cad1da177ef309bf40a117c17b8eecf5", @post.media_asset.variant(:original).open_file.md5)
|
||||||
|
|
||||||
|
assert_equal("https://i.pximg.net/img-zip-ugoira/img/2017/04/04/08/57/38/62247364_ugoira1920x1080.zip", @post.source)
|
||||||
|
assert_equal([{"delay" => 125, "file" => "000000.jpg"}, {"delay" => 125, "file" => "000001.jpg"}], @post.pixiv_ugoira_frame_data.data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "replacing a post with notes" do
|
||||||
|
should "rescale the notes" do
|
||||||
|
skip "Pixiv credentials not configured" unless Sources::Strategies::Pixiv.enabled?
|
||||||
|
|
||||||
|
as(create(:user)) do
|
||||||
|
@post = create(:post, image_width: 160, image_height: 164)
|
||||||
|
@note = @post.notes.create!(x: 80, y: 82, width: 80, height: 82, body: "test", created_at: 1.day.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
post_auth post_replacements_path, create(:moderator_user), params: {
|
||||||
|
format: :json,
|
||||||
|
post_id: @post.id,
|
||||||
|
post_replacement: {
|
||||||
|
replacement_url: "https://i.pximg.net/img-original/img/2017/04/04/08/54/15/62247350_p0.png",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
@note.reload
|
||||||
|
|
||||||
|
# replacement image is 80x82, so we're downscaling by 50% (160x164 -> 80x82).
|
||||||
|
assert_equal([40, 41, 40, 41], [@note.x, @note.y, @note.width, @note.height])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
should "not allow non-mods to replace posts" do
|
should "not allow non-mods to replace posts" do
|
||||||
assert_difference("PostReplacement.count", 0) do
|
assert_difference("PostReplacement.count", 0) do
|
||||||
|
@post = create(:post)
|
||||||
post_auth post_replacements_path(post_id: @post.id), create(:user), params: { post_replacement: { replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg" }}
|
post_auth post_replacements_path(post_id: @post.id), create(:user), params: { post_replacement: { replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg" }}
|
||||||
assert_response 403
|
assert_response 403
|
||||||
end
|
end
|
||||||
@@ -40,16 +165,17 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
context "update action" do
|
context "update action" do
|
||||||
should "update the replacement" do
|
should "update the replacement" do
|
||||||
params = {
|
@post_replacement = create(:post_replacement)
|
||||||
|
|
||||||
|
put_auth post_replacement_path(@post_replacement), create(:moderator_user), params: {
|
||||||
format: :json,
|
format: :json,
|
||||||
id: @post_replacement.id,
|
id: @post_replacement.id,
|
||||||
post_replacement: {
|
post_replacement: {
|
||||||
old_file_size: 23,
|
old_file_size: 23,
|
||||||
file_size: 42
|
file_size: 42,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
put_auth post_replacement_path(@post_replacement), @mod, params: params
|
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_equal(23, @post_replacement.reload.old_file_size)
|
assert_equal(23, @post_replacement.reload.old_file_size)
|
||||||
assert_equal(42, @post_replacement.file_size)
|
assert_equal(42, @post_replacement.file_size)
|
||||||
@@ -58,7 +184,11 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
context "index action" do
|
context "index action" do
|
||||||
setup do
|
setup do
|
||||||
as(create(:admin_user)) { @admin_replacement = create(:post_replacement, replacement_url: "https://danbooru.donmai.us") }
|
@admin = create(:admin_user)
|
||||||
|
@mod = create(:moderator_user, name: "yukari")
|
||||||
|
|
||||||
|
@post_replacement = create(:post_replacement, creator: @mod, post: create(:post, tag_string: "touhou"))
|
||||||
|
@admin_replacement = create(:post_replacement, creator: create(:admin_user), replacement_url: "https://danbooru.donmai.us")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "render" do
|
should "render" do
|
||||||
|
|||||||
@@ -1694,18 +1694,4 @@ class PostTest < ActiveSupport::TestCase
|
|||||||
assert_equal("https://www.example.com/data/original/77/d8/77d89bda37ea3af09158ed3282f8334f.gif", @post.file_url)
|
assert_equal("https://www.example.com/data/original/77/d8/77d89bda37ea3af09158ed3282f8334f.gif", @post.file_url)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "#replace!" do
|
|
||||||
subject { @post.replace!(tags: "something", replacement_url: "https://danbooru.donmai.us/images/download-preview.png") }
|
|
||||||
|
|
||||||
setup do
|
|
||||||
@post = FactoryBot.create(:post)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "update the post" do
|
|
||||||
assert_changes(-> { @post.md5 }) do
|
|
||||||
subject
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,297 +0,0 @@
|
|||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class UploadServiceTest < ActiveSupport::TestCase
|
|
||||||
context "::Replacer" do
|
|
||||||
context "for a file replacement" do
|
|
||||||
setup do
|
|
||||||
@new_file = upload_file("test/files/test.jpg")
|
|
||||||
@old_file = upload_file("test/files/test.png")
|
|
||||||
travel_to(1.month.ago) do
|
|
||||||
@user = FactoryBot.create(:user)
|
|
||||||
end
|
|
||||||
as(@user) do
|
|
||||||
@post = FactoryBot.create(:post, md5: Digest::MD5.hexdigest(@old_file.read))
|
|
||||||
@old_md5 = @post.md5
|
|
||||||
@replacement = FactoryBot.create(:post_replacement, post: @post, replacement_url: "", replacement_file: @new_file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "#process!" do
|
|
||||||
should "not create a new post" do
|
|
||||||
assert_difference(-> { Post.count }, 0) do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "update the post's MD5" do
|
|
||||||
assert_changes(-> { @post.reload.md5 }) do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "preserve the old values" do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
|
||||||
@replacement = @post.replacements.last
|
|
||||||
|
|
||||||
assert_equal(1500, @replacement.old_image_width)
|
|
||||||
assert_equal(1000, @replacement.old_image_height)
|
|
||||||
assert_equal(2000, @replacement.old_file_size)
|
|
||||||
assert_equal("jpg", @replacement.old_file_ext)
|
|
||||||
assert_equal(@old_md5, @replacement.old_md5)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "record the new values" do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
|
||||||
@replacement = @post.replacements.last
|
|
||||||
|
|
||||||
assert_equal(500, @replacement.reload.image_width)
|
|
||||||
assert_equal(335, @replacement.image_height)
|
|
||||||
assert_equal(28086, @replacement.file_size)
|
|
||||||
assert_equal("jpg", @replacement.file_ext)
|
|
||||||
assert_equal("ecef68c44edb8a0d6a3070b5f8e8ee76", @replacement.md5)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "correctly update the attributes" do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
|
||||||
@replacement = @post.replacements.last
|
|
||||||
|
|
||||||
assert_equal(500, @post.image_width)
|
|
||||||
assert_equal(335, @post.image_height)
|
|
||||||
assert_equal(28086, @post.file_size)
|
|
||||||
assert_equal("jpg", @post.file_ext)
|
|
||||||
assert_equal("ecef68c44edb8a0d6a3070b5f8e8ee76", @post.md5)
|
|
||||||
assert(File.exist?(@post.file.path))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a post with the same file" do
|
|
||||||
should "update the source" do
|
|
||||||
upload_file("test/files/test.png") do |file|
|
|
||||||
as(@user) { @post.reload.replace!(replacement_file: file, replacement_url: "", final_source: "blah") }
|
|
||||||
|
|
||||||
assert_equal("blah", @post.reload.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "for a twitter source replacement" do
|
|
||||||
setup do
|
|
||||||
skip "Twitter credentials not configured" unless Sources::Strategies::Twitter.enabled?
|
|
||||||
|
|
||||||
@new_url = "https://pbs.twimg.com/media/B4HSEP5CUAA4xyu.png:orig"
|
|
||||||
|
|
||||||
travel_to(1.month.ago) do
|
|
||||||
@user = FactoryBot.create(:user)
|
|
||||||
end
|
|
||||||
|
|
||||||
as(@user) do
|
|
||||||
@post = FactoryBot.create(:post, source: "http://blah", file_ext: "jpg", md5: "something", uploader_ip_addr: "127.0.0.2")
|
|
||||||
@replacement = FactoryBot.create(:post_replacement, post: @post, replacement_url: @new_url)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "replace the post" do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
|
||||||
|
|
||||||
assert_equal(@new_url, @post.reload.replacements.last.replacement_url)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "for a source replacement" do
|
|
||||||
setup do
|
|
||||||
@new_url = "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg"
|
|
||||||
@new_md5 = "d34e4cf0a437a5d65f8e82b7bcd02606"
|
|
||||||
travel_to(1.month.ago) do
|
|
||||||
@user = FactoryBot.create(:user)
|
|
||||||
end
|
|
||||||
as(@user) do
|
|
||||||
@post_md5 = "710fd9cba4ef37260f9152ffa9d154d8"
|
|
||||||
@post_source = "https://cdn.donmai.us/original/71/0f/#{@post_md5}.png"
|
|
||||||
@post = FactoryBot.create(:post, source: @post_source, file_ext: "png", md5: @post_md5, uploader_ip_addr: "127.0.0.2")
|
|
||||||
@replacement = FactoryBot.create(:post_replacement, post: @post, replacement_url: @new_url)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when replacing a post with the same file as itself" do
|
|
||||||
should "update the source" do
|
|
||||||
@post.update!(source: "blah")
|
|
||||||
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: @post_source) }
|
|
||||||
assert_equal(@post_source, @post.reload.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when an upload with the same MD5 already exists" do
|
|
||||||
setup do
|
|
||||||
@post.update(md5: @new_md5)
|
|
||||||
as(@user) do
|
|
||||||
@post2 = FactoryBot.create(:post)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "throw an error" do
|
|
||||||
assert_raises(UploadService::Replacer::Error) do
|
|
||||||
as(@user) { @post2.reload.replace!(replacement_url: @new_url) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a post when given a final_source" do
|
|
||||||
should "change the source to the final_source" do
|
|
||||||
replacement_url = "https://cdn.donmai.us/original/fd/b4/fdb47f79fb8da82e66eeb1d84a1cae8d.jpg"
|
|
||||||
final_source = "https://cdn.donmai.us/original/71/0f/710fd9cba4ef37260f9152ffa9d154d8.png"
|
|
||||||
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: replacement_url, final_source: final_source) }
|
|
||||||
|
|
||||||
assert_equal(final_source, @post.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a post when replaced with a HTML source" do
|
|
||||||
should "record the image URL as the replacement URL, not the HTML source" do
|
|
||||||
skip "Twitter key not set" unless Danbooru.config.twitter_api_key
|
|
||||||
replacement_url = "https://twitter.com/nounproject/status/540944400767922176"
|
|
||||||
image_url = "https://pbs.twimg.com/media/B4HSEP5CUAA4xyu.png:orig"
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: replacement_url) }
|
|
||||||
|
|
||||||
assert_equal(replacement_url, @post.replacements.last.replacement_url)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "#undo!" do
|
|
||||||
setup do
|
|
||||||
@user = travel_to(1.month.ago) { FactoryBot.create(:user) }
|
|
||||||
as(@user) do
|
|
||||||
@post = FactoryBot.create(:post, source: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg")
|
|
||||||
@new_url = "https://cdn.donmai.us/original/fd/b4/fdb47f79fb8da82e66eeb1d84a1cae8d.jpg"
|
|
||||||
@post.reload.replace!(replacement_url: @new_url, tags: "-tag1 tag2")
|
|
||||||
end
|
|
||||||
|
|
||||||
@replacement = @post.replacements.last
|
|
||||||
end
|
|
||||||
|
|
||||||
should "update the attributes" do
|
|
||||||
as(@user) do
|
|
||||||
replacer = UploadService::Replacer.new(post: @post.reload, replacement: @replacement)
|
|
||||||
replacer.undo!
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal("tag2", @post.tag_string)
|
|
||||||
assert_equal(459, @post.image_width)
|
|
||||||
assert_equal(650, @post.image_height)
|
|
||||||
assert_equal(127238, @post.file_size)
|
|
||||||
assert_equal("jpg", @post.file_ext)
|
|
||||||
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @post.md5)
|
|
||||||
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", Digest::MD5.file(@post.file).hexdigest)
|
|
||||||
assert_equal("https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg", @post.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "#process!" do
|
|
||||||
should "not create a new post" do
|
|
||||||
assert_difference(-> { Post.count }, 0) do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "update the post's MD5" do
|
|
||||||
assert_changes(-> { @post.reload.md5 }) do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "update the post's source" do
|
|
||||||
assert_changes(-> { @post.reload.source }, nil, from: @post.source, to: @new_url) do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
|
||||||
@post.reload
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "not change the post status or uploader" do
|
|
||||||
assert_no_changes(-> { {ip_addr: @post.uploader_ip_addr.to_s, uploader: @post.uploader_id, pending: @post.is_pending?} }) do
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
|
||||||
@post.reload
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a post with a pixiv html source" do
|
|
||||||
setup do
|
|
||||||
skip "Pixiv credentials not configured" unless Sources::Strategies::Pixiv.enabled?
|
|
||||||
end
|
|
||||||
|
|
||||||
should "replace with the full size image" do
|
|
||||||
as(@user) do
|
|
||||||
@post.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal(80, @post.image_width)
|
|
||||||
assert_equal(82, @post.image_height)
|
|
||||||
assert_equal(16275, @post.file_size)
|
|
||||||
assert_equal("png", @post.file_ext)
|
|
||||||
assert_equal("4ceadc314938bc27f3574053a3e1459a", @post.md5)
|
|
||||||
assert_equal("4ceadc314938bc27f3574053a3e1459a", Digest::MD5.file(@post.file).hexdigest)
|
|
||||||
assert_equal("https://i.pximg.net/img-original/img/2017/04/04/08/54/15/62247350_p0.png", @post.replacements.last.replacement_url)
|
|
||||||
assert_equal("https://i.pximg.net/img-original/img/2017/04/04/08/54/15/62247350_p0.png", @post.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a post that is replaced by a ugoira" do
|
|
||||||
should "save the frame data" do
|
|
||||||
skip unless MediaFile::Ugoira.videos_enabled?
|
|
||||||
skip "Pixiv credentials not configured" unless Sources::Strategies::Pixiv.enabled?
|
|
||||||
|
|
||||||
begin
|
|
||||||
as(@user) { @post.reload.replace!(replacement_url: "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364") }
|
|
||||||
@post.reload
|
|
||||||
|
|
||||||
assert_equal(80, @post.image_width)
|
|
||||||
assert_equal(82, @post.image_height)
|
|
||||||
assert_equal(2804, @post.file_size)
|
|
||||||
assert_equal("zip", @post.file_ext)
|
|
||||||
assert_equal("cad1da177ef309bf40a117c17b8eecf5", @post.md5)
|
|
||||||
assert_equal("cad1da177ef309bf40a117c17b8eecf5", Digest::MD5.file(@post.file).hexdigest)
|
|
||||||
|
|
||||||
assert_equal("https://i.pximg.net/img-zip-ugoira/img/2017/04/04/08/57/38/62247364_ugoira1920x1080.zip", @post.source)
|
|
||||||
assert_equal([{"delay" => 125, "file" => "000000.jpg"}, {"delay" => 125, "file" => "000001.jpg"}], @post.pixiv_ugoira_frame_data.data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a post with notes" do
|
|
||||||
setup do
|
|
||||||
skip "Pixiv credentials not configured" unless Sources::Strategies::Pixiv.enabled?
|
|
||||||
|
|
||||||
Note.any_instance.stubs(:merge_version?).returns(false)
|
|
||||||
|
|
||||||
as(@user) do
|
|
||||||
@post.update(image_width: 160, image_height: 164)
|
|
||||||
@note = @post.notes.create(x: 80, y: 82, width: 80, height: 82, body: "test")
|
|
||||||
@note.reload
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "rescale the notes" do
|
|
||||||
assert_equal([80, 82, 80, 82], [@note.x, @note.y, @note.width, @note.height])
|
|
||||||
|
|
||||||
begin
|
|
||||||
assert_difference(-> { @note.versions.count }) do
|
|
||||||
# replacement image is 80x82, so we're downscaling by 50% (160x164 -> 80x82).
|
|
||||||
as(@user) do
|
|
||||||
@post.reload.replace!(
|
|
||||||
replacement_url: "https://i.pximg.net/img-original/img/2017/04/04/08/54/15/62247350_p0.png",
|
|
||||||
final_source: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
@note.reload
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal([40, 41, 40, 41], [@note.x, @note.y, @note.width, @note.height])
|
|
||||||
assert_equal("https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350", @post.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user