diff --git a/app/models/upload.rb b/app/models/upload.rb index 0453578e889..ef92afe6cc3 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -205,97 +205,105 @@ class Upload < ActiveRecord::Base def self.migrate_to_new_scheme(limit: nil) problems = [] - if SiteSetting.migrate_to_new_scheme - max_file_size_kb = [SiteSetting.max_image_size_kb, SiteSetting.max_attachment_size_kb].max.kilobytes - local_store = FileStore::LocalStore.new - db = RailsMultisite::ConnectionManagement.current_db + DistributedMutex.synchronize("migrate_upload_to_new_scheme") do + if SiteSetting.migrate_to_new_scheme + max_file_size_kb = [ + SiteSetting.max_image_size_kb, + SiteSetting.max_attachment_size_kb + ].max.kilobytes - scope = Upload.by_users.where("url NOT LIKE '%/original/_X/%' AND url LIKE '%/uploads/#{db}%'").order(id: :desc) + local_store = FileStore::LocalStore.new + db = RailsMultisite::ConnectionManagement.current_db - scope = scope.limit(limit) if limit + scope = Upload.by_users + .where("url NOT LIKE '%/original/_X/%' AND url LIKE '%/uploads/#{db}%'") + .order(id: :desc) - if scope.count == 0 - SiteSetting.migrate_to_new_scheme = false - return problems - end + scope = scope.limit(limit) if limit - remap_scope = nil + if scope.count == 0 + SiteSetting.migrate_to_new_scheme = false + return problems + end - scope.each do |upload| - begin - # keep track of the url - previous_url = upload.url.dup - # where is the file currently stored? - external = previous_url =~ /^\/\// - # download if external - if external - url = SiteSetting.scheme + ":" + previous_url + remap_scope = nil - begin - retries ||= 0 + scope.each do |upload| + begin + # keep track of the url + previous_url = upload.url.dup + # where is the file currently stored? + external = previous_url =~ /^\/\// + # download if external + if external + url = SiteSetting.scheme + ":" + previous_url - file = FileHelper.download( - url, - max_file_size: max_file_size_kb, - tmp_file_name: "discourse", - follow_redirect: true - ) - rescue OpenURI::HTTPError - retry if (retires += 1) < 1 - next + begin + retries ||= 0 + + file = FileHelper.download( + url, + max_file_size: max_file_size_kb, + tmp_file_name: "discourse", + follow_redirect: true + ) + rescue OpenURI::HTTPError + retry if (retires += 1) < 1 + next + end + + path = file.path + else + path = local_store.path_for(upload) + end + # compute SHA if missing + if upload.sha1.blank? + upload.sha1 = Upload.generate_digest(path) end - path = file.path - else - path = local_store.path_for(upload) - end - # compute SHA if missing - if upload.sha1.blank? - upload.sha1 = Upload.generate_digest(path) - end + # store to new location & update the filesize + File.open(path) do |f| + upload.url = Discourse.store.store_upload(f, upload) + upload.filesize = f.size + upload.save!(validate: false) + end + # remap the URLs + DbHelper.remap(UrlHelper.absolute(previous_url), upload.url) unless external - # store to new location & update the filesize - File.open(path) do |f| - upload.url = Discourse.store.store_upload(f, upload) - upload.filesize = f.size - upload.save!(validate: false) - end - # remap the URLs - DbHelper.remap(UrlHelper.absolute(previous_url), upload.url) unless external + DbHelper.remap( + previous_url, + upload.url, + excluded_tables: %w{ + posts + post_search_data + } + ) - DbHelper.remap( - previous_url, - upload.url, - excluded_tables: %w{ - posts - post_search_data - } - ) + remap_scope ||= begin + Post.with_deleted + .where("raw ~ '/uploads/#{db}/\\d+/' OR raw ~ '/uploads/#{db}/original/\\d{1}/'") + .select(:raw, :cooked) + .all + end - remap_scope ||= begin - Post.with_deleted - .where("raw ~ '/uploads/#{db}/\\d+/' OR raw ~ '/uploads/#{db}/original/\\d{1}/'") - .select(:raw, :cooked) - .all - end + remap_scope.each do |post| + post.raw.gsub!(previous_url, upload.url) + post.cooked.gsub!(previous_url, upload.url) + post.save! if post.changed? + end - remap_scope.each do |post| - post.raw.gsub!(previous_url, upload.url) - post.cooked.gsub!(previous_url, upload.url) - post.save! if post.changed? + upload.optimized_images.find_each(&:destroy!) + upload.rebake_posts_on_old_scheme + # remove the old file (when local) + unless external + FileUtils.rm(path, force: true) + end + rescue => e + problems << { upload: upload, ex: e } + ensure + file&.unlink + file&.close end - - upload.optimized_images.find_each(&:destroy!) - upload.rebake_posts_on_old_scheme - # remove the old file (when local) - unless external - FileUtils.rm(path, force: true) - end - rescue => e - problems << { upload: upload, ex: e } - ensure - file&.unlink - file&.close end end end