diff --git a/app/jobs/regular/pull_hotlinked_images.rb b/app/jobs/regular/pull_hotlinked_images.rb index e76c4b6c302..d3e3d07e43e 100644 --- a/app/jobs/regular/pull_hotlinked_images.rb +++ b/app/jobs/regular/pull_hotlinked_images.rb @@ -56,8 +56,8 @@ module Jobs has_new_broken_image = false has_downloaded_image = false - extract_images_from(post.cooked).each do |image| - src = original_src = image['src'] + extract_images_from(post.cooked).each do |node| + src = original_src = node['src'] || node['href'] src = "#{SiteSetting.force_https ? "https" : "http"}:#{src}" if src.start_with?("//") if should_download_image?(src) @@ -91,9 +91,20 @@ module Jobs if downloaded_urls[src].present? url = downloaded_urls[src] escaped_src = Regexp.escape(original_src) + # there are 6 ways to insert an image in a post # HTML tag - raw.gsub!(/src=["']#{escaped_src}["']/i, "src='#{url}'") + + if (original_path = Upload.extract_url(original_src)&.to_s) && + (path = Upload.extract_url(url)&.to_s) + + raw.gsub!( + /src=["']\S*#{Regexp.escape(original_path)}["']/i, + "src='#{url}'" + ) + end + # BBCode tag - [img]http://...[/img] raw.gsub!(/\[img\]#{escaped_src}\[\/img\]/i, "[img]#{url}[/img]") # Markdown linked image - [![alt](http://...)](http://...) @@ -136,7 +147,7 @@ module Jobs def extract_images_from(html) doc = Nokogiri::HTML::fragment(html) - doc.css("img[src]") - doc.css("img.avatar") - doc.css(".lightbox img[src]") + doc.css("img[src], a.lightbox[href]") - doc.css("img.avatar") - doc.css(".lightbox img[src]") end def should_download_image?(src) diff --git a/spec/fabricators/optimized_image_fabricator.rb b/spec/fabricators/optimized_image_fabricator.rb index f5311b9cfc6..01523d68d83 100644 --- a/spec/fabricators/optimized_image_fabricator.rb +++ b/spec/fabricators/optimized_image_fabricator.rb @@ -6,6 +6,9 @@ Fabricator(:optimized_image) do extension ".png" width 100 height 200 - url "138569_100x200.png" version OptimizedImage::VERSION + + after_build do |optimized_image, _| + optimized_image.url = Discourse.store.get_path_for_optimized_image(optimized_image) + end end diff --git a/spec/jobs/pull_hotlinked_images_spec.rb b/spec/jobs/pull_hotlinked_images_spec.rb index ba92da9530a..f87bc9ba93b 100644 --- a/spec/jobs/pull_hotlinked_images_spec.rb +++ b/spec/jobs/pull_hotlinked_images_spec.rb @@ -68,6 +68,25 @@ describe Jobs::PullHotlinkedImages do expect(post.raw).to match(/^") + + expect { Jobs::PullHotlinkedImages.new.execute(post_id: post.id) } + .to change { Upload.count }.by(1) + + upload = Upload.last + post.reload + + expect(post.raw).to eq("") + expect(post.uploads).to contain_exactly(upload) + end + describe 'onebox' do let(:media) { "File:Brisbane_May_2013201.jpg" } let(:url) { "https://commons.wikimedia.org/wiki/#{media}" } @@ -172,18 +191,52 @@ describe Jobs::PullHotlinkedImages do describe "with a lightboxed image" do fab!(:upload) { Fabricate(:upload) } + fab!(:user) { Fabricate(:user) } before do - FastImage.expects(:size).returns([1750, 2000]) + FastImage.expects(:size).returns([1750, 2000]).at_least_once OptimizedImage.stubs(:resize).returns(true) + Jobs.run_immediately! + end + + it 'replaces missing local uploads in lightbox link' do + post = PostCreator.create!( + user, + raw: "", + title: "Some title that is long enough" + ) + + expect(post.reload.cooked).to have_tag(:a, with: { class: "lightbox" }) + + stub_request(:get, "#{Discourse.base_url}#{upload.url}") + .to_return(status: 200, body: file_from_fixtures("smallest.png")) + + upload.delete + + expect { Jobs::PullHotlinkedImages.new.execute(post_id: post.id) } + .to change { Upload.count }.by(1) + + post.reload + + expect(post.raw).to eq("") + expect(post.uploads.count).to eq(1) end it "doesn't remove optimized images from lightboxes" do - post = Fabricate(:post, raw: "![alt](#{upload.short_url})") - Jobs::ProcessPost.new.execute(post_id: post.id) + post = PostCreator.create!( + user, + raw: "![alt](#{upload.short_url})", + title: "Some title that is long enough" + ) - expect { Jobs::PullHotlinkedImages.new.execute(post_id: post.id) }.not_to change { Upload.count } - expect(post.reload.cooked).to include "/uploads/default/optimized/" # Ensure the lightbox was actually rendered + expect(post.reload.cooked).to have_tag(:a, with: { class: "lightbox" }) + + expect { Jobs::PullHotlinkedImages.new.execute(post_id: post.id) } + .not_to change { Upload.count } + + post.reload + + expect(post.raw).to eq("![alt](#{upload.short_url})") end end