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