discourse/app/jobs/onceoff/migrate_badge_image_to_uplo...

99 lines
2.8 KiB
Ruby

# frozen_string_literal: true
require "uri"
module Jobs
class MigrateBadgeImageToUploads < ::Jobs::Onceoff
def execute_onceoff(args)
column_exists = DB.exec(<<~SQL) == 1
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
table_schema = 'public' AND
table_name = 'badges' AND
column_name = 'image_upload_id'
SQL
return unless column_exists
Badge
.where.not(image: nil)
.select(:id, :image_upload_id, :image)
.each do |badge|
if badge.image_upload.present?
DB.exec("UPDATE badges SET image = NULL WHERE id = ?", badge.id)
next
end
image_url = badge[:image]
next if image_url.blank? || image_url !~ URI.regexp
count = 0
file = nil
sleep_interval = 5
loop do
url = UrlHelper.absolute_without_cdn(image_url)
begin
file =
FileHelper.download(
url,
max_file_size: [SiteSetting.max_image_size_kb.kilobytes, 20.megabytes].max,
tmp_file_name: "tmp_badge_image_upload",
skip_rate_limit: true,
follow_redirect: true,
)
rescue OpenURI::HTTPError,
OpenSSL::SSL::SSLError,
Net::OpenTimeout,
Net::ReadTimeout,
Errno::ECONNREFUSED,
EOFError,
SocketError,
Discourse::InvalidParameters => e
logger.error(
"Error encountered when trying to download from URL '#{image_url}' " +
"for badge '#{badge[:id]}'.\n#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}",
)
end
count += 1
break if file
logger.warn(
"Failed to download image from #{url} for badge '#{badge[:id]}'. Retrying (#{count}/3)...",
)
break if count >= 3
sleep(count * sleep_interval)
end
next if file.blank?
upload =
UploadCreator.new(
file,
"image_for_badge_#{badge[:id]}",
origin: UrlHelper.absolute(image_url),
).create_for(Discourse.system_user.id)
if upload.errors.count > 0 || upload&.id.blank?
logger.error(
"Failed to create an upload for the image of badge '#{badge[:id]}'. Error: #{upload.errors.full_messages}",
)
else
DB.exec(
"UPDATE badges SET image = NULL, image_upload_id = ? WHERE id = ?",
upload.id,
badge[:id],
)
end
end
end
private
def logger
Rails.logger
end
end
end