1# frozen_string_literal: true
2
3class ImportExportUpload < ApplicationRecord
4  include WithUploads
5  include ObjectStorage::BackgroundMove
6
7  belongs_to :project
8  belongs_to :group
9
10  # These hold the project Import/Export archives (.tar.gz files)
11  mount_uploader :import_file, ImportExportUploader
12  mount_uploader :export_file, ImportExportUploader
13
14  # This causes CarrierWave v1 and v3 (but not v2) to upload the file to
15  # object storage *after* the database entry has been committed to the
16  # database. This avoids idling in a transaction.
17  if Gitlab::Utils.to_boolean(ENV.fetch('ENABLE_STORE_EXPORT_FILE_AFTER_COMMIT', true))
18    skip_callback :save, :after, :store_export_file!
19    set_callback :commit, :after, :store_export_file!
20  end
21
22  scope :updated_before, ->(date) { where('updated_at < ?', date) }
23  scope :with_export_file, -> { where.not(export_file: nil) }
24
25  def retrieve_upload(_identifier, paths)
26    Upload.find_by(model: self, path: paths)
27  end
28
29  def export_file_exists?
30    !!carrierwave_export_file
31  end
32
33  # This checks if the export archive is actually stored on disk. It
34  # requires a HEAD request if object storage is used.
35  def export_archive_exists?
36    !!carrierwave_export_file&.exists?
37  # Handle any HTTP unexpected error
38  # https://github.com/excon/excon/blob/bbb5bd791d0bb2251593b80e3bce98dbec6e8f24/lib/excon/error.rb#L129-L169
39  rescue Excon::Error => e
40    # The HEAD request will fail with a 403 Forbidden if the file does not
41    # exist, and the user does not have permission to list the object
42    # storage bucket.
43    Gitlab::ErrorTracking.track_exception(e)
44    false
45  end
46
47  private
48
49  def carrierwave_export_file
50    export_file&.file
51  end
52end
53