media assets: prevent duplicate media assets.
Add a md5 uniqueness constraint on media assets to prevent duplicate assets from being created. This way we can guarantee that there is one active media asset per uploaded file. Also make it so that if two people are uploading the same file at the same time, the file is processed only once.
This commit is contained in:
@@ -13,5 +13,20 @@ FactoryBot.define do
|
||||
rating {"q"}
|
||||
source { FFaker::Internet.http_url }
|
||||
media_asset { build(:media_asset) }
|
||||
|
||||
factory(:post_with_file) do
|
||||
transient do
|
||||
filename { "test.jpg" }
|
||||
media_file { MediaFile.open("test/files/#{filename}") }
|
||||
end
|
||||
|
||||
md5 { media_file.md5 }
|
||||
image_width { media_file.width }
|
||||
image_height { media_file.height }
|
||||
file_ext { media_file.file_ext }
|
||||
file_size { media_file.file_size }
|
||||
|
||||
before(:create) { |post, evaluator| MediaAsset.upload!(evaluator.media_file) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,8 +31,7 @@ class PostTest < ActiveSupport::TestCase
|
||||
context "Deletion:" do
|
||||
context "Expunging a post" do
|
||||
setup do
|
||||
@upload = UploadService.new(FactoryBot.attributes_for(:jpg_upload)).start!
|
||||
@post = @upload.post
|
||||
@post = create(:post_with_file, uploader: @user, filename: "test.jpg")
|
||||
Favorite.create!(post: @post, user: @user)
|
||||
create(:favorite_group, post_ids: [@post.id])
|
||||
perform_enqueued_jobs # perform IqdbAddPostJob
|
||||
|
||||
@@ -224,31 +224,29 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
subject { UploadService::Replacer.new(post: @post, replacement: @replacement) }
|
||||
|
||||
context "#process!" do
|
||||
should "create a comment" do
|
||||
assert_difference(-> { @post.comments.count }) do
|
||||
as(@user) { subject.process! }
|
||||
@post.reload
|
||||
assert_difference(-> { @post.reload.comments.count }) do
|
||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
||||
end
|
||||
end
|
||||
|
||||
should "not create a new post" do
|
||||
assert_difference(-> { Post.count }, 0) do
|
||||
as(@user) { subject.process! }
|
||||
as(@user) { @post.reload.replace!(replacement_url: "", replacement_file: @new_file) }
|
||||
end
|
||||
end
|
||||
|
||||
should "update the post's MD5" do
|
||||
assert_changes(-> { @post.md5 }) do
|
||||
as(@user) { subject.process! }
|
||||
@post.reload
|
||||
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) { subject.process! }
|
||||
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)
|
||||
@@ -257,8 +255,10 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "record the new values" do
|
||||
as(@user) { subject.process! }
|
||||
assert_equal(500, @replacement.image_width)
|
||||
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)
|
||||
@@ -266,7 +266,9 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "correctly update the attributes" do
|
||||
as(@user) { subject.process! }
|
||||
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)
|
||||
@@ -280,7 +282,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
should "raise an error" do
|
||||
upload_file("test/files/test.png") do |file|
|
||||
assert_raises(UploadService::Replacer::Error) do
|
||||
as(@user) { @post.replace!(replacement_file: file, replacement_url: "") }
|
||||
as(@user) { @post.reload.replace!(replacement_file: file, replacement_url: "") }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -304,14 +306,10 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
subject { UploadService::Replacer.new(post: @post, replacement: @replacement) }
|
||||
|
||||
should "replace the post" do
|
||||
as(@user) { subject.process! }
|
||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
||||
|
||||
@post.reload
|
||||
|
||||
assert_equal(@new_url, @post.replacements.last.replacement_url)
|
||||
assert_equal(@new_url, @post.reload.replacements.last.replacement_url)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -330,12 +328,10 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
subject { UploadService::Replacer.new(post: @post, replacement: @replacement) }
|
||||
|
||||
context "when replacing with its own source" do
|
||||
should "raise an error" do
|
||||
assert_raises(UploadService::Replacer::Error) do
|
||||
as(@user) { @post.replace!(replacement_url: @post.source) }
|
||||
as(@user) { @post.reload.replace!(replacement_url: @post.source) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -351,7 +347,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
|
||||
should "throw an error" do
|
||||
assert_raises(UploadService::Replacer::Error) do
|
||||
as(@user) { @post2.replace!(replacement_url: @new_url) }
|
||||
as(@user) { @post2.reload.replace!(replacement_url: @new_url) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -361,7 +357,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
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.replace!(replacement_url: replacement_url, final_source: final_source) }
|
||||
as(@user) { @post.reload.replace!(replacement_url: replacement_url, final_source: final_source) }
|
||||
|
||||
assert_equal(final_source, @post.source)
|
||||
end
|
||||
@@ -372,7 +368,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
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.replace!(replacement_url: replacement_url) }
|
||||
as(@user) { @post.reload.replace!(replacement_url: replacement_url) }
|
||||
|
||||
assert_equal(replacement_url, @post.replacements.last.replacement_url)
|
||||
end
|
||||
@@ -384,7 +380,8 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
as(@user) do
|
||||
@post = FactoryBot.create(:post, source: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg")
|
||||
@post.stubs(:queue_delete_files)
|
||||
@post.replace!(replacement_url: "https://cdn.donmai.us/original/fd/b4/fdb47f79fb8da82e66eeb1d84a1cae8d.jpg", tags: "-tag1 tag2")
|
||||
@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
|
||||
@@ -392,7 +389,8 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
|
||||
should "update the attributes" do
|
||||
as(@user) do
|
||||
subject.undo!
|
||||
replacer = UploadService::Replacer.new(post: @post.reload, replacement: @replacement)
|
||||
replacer.undo!
|
||||
end
|
||||
|
||||
assert_equal("tag2", @post.tag_string)
|
||||
@@ -408,41 +406,39 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
|
||||
context "#process!" do
|
||||
should "create a comment" do
|
||||
assert_difference(-> { @post.comments.count }) do
|
||||
as(@user) { subject.process! }
|
||||
@post.reload
|
||||
assert_difference(-> { @post.reload.comments.count }) do
|
||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
||||
end
|
||||
end
|
||||
|
||||
should "not create a new post" do
|
||||
assert_difference(-> { Post.count }, 0) do
|
||||
as(@user) { subject.process! }
|
||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
||||
end
|
||||
end
|
||||
|
||||
should "update the post's MD5" do
|
||||
assert_changes(-> { @post.md5 }) do
|
||||
as(@user) { subject.process! }
|
||||
@post.reload
|
||||
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.source }, nil, from: @post.source, to: @new_url) do
|
||||
as(@user) { subject.process! }
|
||||
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) { subject.process! }
|
||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
||||
@post.reload
|
||||
end
|
||||
end
|
||||
|
||||
should "leave a system comment" do
|
||||
as(@user) { subject.process! }
|
||||
as(@user) { @post.reload.replace!(replacement_url: @new_url) }
|
||||
comment = @post.comments.last
|
||||
assert_not_nil(comment)
|
||||
assert_equal(User.system.id, comment.creator_id)
|
||||
@@ -457,7 +453,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
|
||||
should "replace with the full size image" do
|
||||
as(@user) do
|
||||
@post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
end
|
||||
|
||||
assert_equal(80, @post.image_width)
|
||||
@@ -474,7 +470,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
@post.unstub(:queue_delete_files)
|
||||
FileUtils.expects(:rm_f).times(3)
|
||||
|
||||
as(@user) { @post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350") }
|
||||
as(@user) { @post.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350") }
|
||||
|
||||
travel_to((PostReplacement::DELETION_GRACE_PERIOD + 1).days.from_now) do
|
||||
perform_enqueued_jobs
|
||||
@@ -488,7 +484,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
skip "Pixiv credentials not configured" unless Sources::Strategies::Pixiv.enabled?
|
||||
|
||||
begin
|
||||
as(@user) { @post.replace!(replacement_url: "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364") }
|
||||
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)
|
||||
@@ -515,12 +511,10 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
#FileUtils.expects(:rm_f).times(3)
|
||||
|
||||
as(@user) do
|
||||
@post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post.reload
|
||||
@post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")
|
||||
@post.reload
|
||||
@post.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")
|
||||
Upload.destroy_all
|
||||
@post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
end
|
||||
|
||||
assert_nothing_raised { @post.file(:original) }
|
||||
@@ -550,20 +544,17 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
as(@user) do
|
||||
skip unless MediaFile::Ugoira.videos_enabled?
|
||||
|
||||
@post1.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post2.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")
|
||||
@post1.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post2.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")
|
||||
assert_equal("4ceadc314938bc27f3574053a3e1459a", @post1.md5)
|
||||
assert_equal("cad1da177ef309bf40a117c17b8eecf5", @post2.md5)
|
||||
|
||||
@post2.reload
|
||||
@post2.replace!(replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg")
|
||||
@post2.reload.replace!(replacement_url: "https://cdn.donmai.us/original/d3/4e/d34e4cf0a437a5d65f8e82b7bcd02606.jpg")
|
||||
assert_equal("d34e4cf0a437a5d65f8e82b7bcd02606", @post2.md5)
|
||||
Upload.destroy_all
|
||||
@post1.reload
|
||||
@post2.reload
|
||||
|
||||
@post1.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")
|
||||
@post2.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
@post1.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")
|
||||
@post2.reload.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||
assert_equal("cad1da177ef309bf40a117c17b8eecf5", @post1.md5)
|
||||
assert_equal("4ceadc314938bc27f3574053a3e1459a", @post2.md5)
|
||||
end
|
||||
@@ -599,7 +590,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
assert_difference(-> { @note.versions.count }) do
|
||||
# replacement image is 80x82, so we're downscaling by 50% (160x164 -> 80x82).
|
||||
as(@user) do
|
||||
@post.replace!(
|
||||
@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"
|
||||
)
|
||||
@@ -690,7 +681,8 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
|
||||
context "when the file has already been uploaded" do
|
||||
setup do
|
||||
@post = create(:post, md5: "d34e4cf0a437a5d65f8e82b7bcd02606")
|
||||
@asset = MediaAsset.find_by_md5("d34e4cf0a437a5d65f8e82b7bcd02606")
|
||||
@post = create(:post, md5: "d34e4cf0a437a5d65f8e82b7bcd02606", media_asset: @asset)
|
||||
@service = subject.new(source: @source)
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user