From 65b7c08e336dac82e2db4ec811f064a9e419bbce Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 31 Jan 2022 12:14:06 -0600 Subject: [PATCH] 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. --- .../post_replacements_controller.rb | 8 +- app/logical/post_replacement_processor.rb | 72 +++++ app/logical/upload_service/replacer.rb | 83 ----- app/models/post.rb | 7 - app/models/post_replacement.rb | 7 +- test/factories/post_replacement.rb | 1 + .../post_replacements_controller_test.rb | 182 +++++++++-- test/unit/post_test.rb | 14 - test/unit/upload_service_test.rb | 297 ------------------ 9 files changed, 239 insertions(+), 432 deletions(-) create mode 100644 app/logical/post_replacement_processor.rb delete mode 100644 app/logical/upload_service/replacer.rb delete mode 100644 test/unit/upload_service_test.rb diff --git a/app/controllers/post_replacements_controller.rb b/app/controllers/post_replacements_controller.rb index 3a98fb31e..325773a19 100644 --- a/app/controllers/post_replacements_controller.rb +++ b/app/controllers/post_replacements_controller.rb @@ -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 diff --git a/app/logical/post_replacement_processor.rb b/app/logical/post_replacement_processor.rb new file mode 100644 index 000000000..44e4533e6 --- /dev/null +++ b/app/logical/post_replacement_processor.rb @@ -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 diff --git a/app/logical/upload_service/replacer.rb b/app/logical/upload_service/replacer.rb deleted file mode 100644 index f767d784d..000000000 --- a/app/logical/upload_service/replacer.rb +++ /dev/null @@ -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 diff --git a/app/models/post.rb b/app/models/post.rb index 78ba38c16..3ffec42a1 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -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 diff --git a/app/models/post_replacement.rb b/app/models/post_replacement.rb index 62ed62450..0b1ffc6b9 100644 --- a/app/models/post_replacement.rb +++ b/app/models/post_replacement.rb @@ -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| diff --git a/test/factories/post_replacement.rb b/test/factories/post_replacement.rb index 43108423a..20d2a8acb 100644 --- a/test/factories/post_replacement.rb +++ b/test/factories/post_replacement.rb @@ -3,5 +3,6 @@ FactoryBot.define do post factory: :post, source: FFaker::Internet.http_url original_url { FFaker::Internet.http_url } replacement_url { FFaker::Internet.http_url } + creator end end diff --git a/test/functional/post_replacements_controller_test.rb b/test/functional/post_replacements_controller_test.rb index 5b27a73ad..cebb18484 100644 --- a/test/functional/post_replacements_controller_test.rb +++ b/test/functional/post_replacements_controller_test.rb @@ -2,36 +2,161 @@ require 'test_helper' class PostReplacementsControllerTest < ActionDispatch::IntegrationTest 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 - should "render" do - params = { - format: :json, - post_id: @post.id, - post_replacement: { - replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg" - } - } + context "replacing a post from a source url" do + should "replace the post" do + assert_difference("PostReplacement.count") do + @post = create(:post) - assert_difference("PostReplacement.count") do - post_auth post_replacements_path, @mod, params: params - assert_response :success + post_auth post_replacements_path, create(:moderator_user), params: { + format: :json, + 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 - assert_equal("https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg", @post.reload.source) - assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @post.md5) - assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", Digest::MD5.file(@post.file(:original)).hexdigest) + context "replacing a post with the same file" do + should "only change the source to the final source" do + @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 should "not allow non-mods to replace posts" 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" }} assert_response 403 end @@ -40,16 +165,17 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest context "update action" 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, id: @post_replacement.id, post_replacement: { old_file_size: 23, - file_size: 42 + file_size: 42, } } - put_auth post_replacement_path(@post_replacement), @mod, params: params assert_response :success assert_equal(23, @post_replacement.reload.old_file_size) assert_equal(42, @post_replacement.file_size) @@ -58,7 +184,11 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest context "index action" 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 should "render" do diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index fcb6a917c..98a025215 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -1694,18 +1694,4 @@ class PostTest < ActiveSupport::TestCase assert_equal("https://www.example.com/data/original/77/d8/77d89bda37ea3af09158ed3282f8334f.gif", @post.file_url) 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 diff --git a/test/unit/upload_service_test.rb b/test/unit/upload_service_test.rb deleted file mode 100644 index b00c78785..000000000 --- a/test/unit/upload_service_test.rb +++ /dev/null @@ -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