summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMichael Kozono <mkozono@gmail.com>2017-11-07 19:08:02 -0800
committerMichael Kozono <mkozono@gmail.com>2017-12-01 15:26:40 -0800
commit3a0ad99d59506592e8d5c6abf0de0fc2104f0bf2 (patch)
tree2e4c5a297c1a576ccac281fbfc0c99ac9a5fcfd0 /lib
parent8315c66a569bbc1b4806762e4da49c22813fc523 (diff)
downloadgitlab-ce-3a0ad99d59506592e8d5c6abf0de0fc2104f0bf2.tar.gz
Add untracked files to uploads
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/background_migration/populate_untracked_uploads.rb144
1 files changed, 133 insertions, 11 deletions
diff --git a/lib/gitlab/background_migration/populate_untracked_uploads.rb b/lib/gitlab/background_migration/populate_untracked_uploads.rb
index 6dbef41cff8..acd424f4558 100644
--- a/lib/gitlab/background_migration/populate_untracked_uploads.rb
+++ b/lib/gitlab/background_migration/populate_untracked_uploads.rb
@@ -4,27 +4,149 @@ module Gitlab
class UnhashedUploadFile < ActiveRecord::Base
self.table_name = 'unhashed_upload_files'
+ # Ends with /:random_hex/:filename
+ FILE_UPLOADER_PATH_PATTERN = /\/\h+\/[^\/]+\z/
+
+ # These regex patterns are tested against a relative path, relative to
+ # the upload directory.
+ # For convenience, if there exists a capture group in the pattern, then
+ # it indicates the model_id.
+ PATH_PATTERNS = [
+ {
+ pattern: /\A-\/system\/appearance\/logo\/(\d+)/,
+ uploader: 'AttachmentUploader',
+ model_type: 'Appearance',
+ },
+ {
+ pattern: /\A-\/system\/appearance\/header_logo\/(\d+)/,
+ uploader: 'AttachmentUploader',
+ model_type: 'Appearance',
+ },
+ {
+ pattern: /\A-\/system\/note\/attachment\/(\d+)/,
+ uploader: 'AttachmentUploader',
+ model_type: 'Note',
+ },
+ {
+ pattern: /\A-\/system\/user\/avatar\/(\d+)/,
+ uploader: 'AvatarUploader',
+ model_type: 'User',
+ },
+ {
+ pattern: /\A-\/system\/group\/avatar\/(\d+)/,
+ uploader: 'AvatarUploader',
+ model_type: 'Group',
+ },
+ {
+ pattern: /\A-\/system\/project\/avatar\/(\d+)/,
+ uploader: 'AvatarUploader',
+ model_type: 'Project',
+ },
+ {
+ pattern: FILE_UPLOADER_PATH_PATTERN,
+ uploader: 'FileUploader',
+ model_type: 'Project'
+ },
+ ]
+
scope :untracked, -> { where(tracked: false) }
def ensure_tracked!
- # TODO
- # unless unhashed_upload_file.in_uploads?
- # unhashed_upload_file.add_to_uploads
- # end
- #
- # unhashed_upload_file.mark_as_tracked
+ return if persisted? && tracked?
+
+ unless in_uploads?
+ add_to_uploads
+ end
+
+ mark_as_tracked
end
- def model_id
- # TODO
+ def in_uploads?
+ # Even though we are checking relative paths, path is enough to
+ # uniquely identify uploads. There is no ambiguity between
+ # FileUploader paths and other Uploader paths because we use the /-/
+ # separator kind of like an escape character. Project full_path will
+ # never conflict with an upload path starting with "uploads/-/".
+ Upload.exists?(path: upload_path)
end
- def model_type
- # TODO
+ def add_to_uploads
+ Upload.create!(
+ path: upload_path,
+ uploader: uploader,
+ model_type: model_type,
+ model_id: model_id,
+ size: file_size
+ )
+ end
+
+ def mark_as_tracked
+ self.tracked = true
+ self.save!
+ end
+
+ def upload_path
+ # UnhashedUploadFile#path is absolute, but Upload#path depends on uploader
+ if uploader == 'FileUploader'
+ # Path relative to project directory in uploads
+ matchd = path_relative_to_upload_dir.match(FILE_UPLOADER_PATH_PATTERN)
+ matchd[0].sub(/\A\//, '') # remove leading slash
+ else
+ path_relative_to_carrierwave_root
+ end
end
def uploader
- # TODO
+ PATH_PATTERNS.each do |path_pattern_map|
+ if path_relative_to_upload_dir.match(path_pattern_map[:pattern])
+ return path_pattern_map[:uploader]
+ end
+ end
+ end
+
+ def model_type
+ PATH_PATTERNS.each do |path_pattern_map|
+ if path_relative_to_upload_dir.match(path_pattern_map[:pattern])
+ return path_pattern_map[:model_type]
+ end
+ end
+ end
+
+ def model_id
+ PATH_PATTERNS.each do |path_pattern_map|
+ matchd = path_relative_to_upload_dir.match(path_pattern_map[:pattern])
+
+ # If something is captured (matchd[1] is not nil), it is a model_id
+ return matchd[1] if matchd && matchd[1]
+ end
+
+ # Only the FileUploader pattern will not match an ID
+ file_uploader_model_id
+ end
+
+ def file_size
+ File.size(path)
+ end
+
+ # Not including a leading slash
+ def path_relative_to_upload_dir
+ @path_relative_to_upload_dir ||= path.sub(/\A#{Gitlab::BackgroundMigration::PrepareUnhashedUploads::UPLOAD_DIR}\//, '')
+ end
+
+ # Not including a leading slash
+ def path_relative_to_carrierwave_root
+ "uploads/#{path_relative_to_upload_dir}"
+ end
+
+ private
+
+ def file_uploader_model_id
+ pattern_to_capture_full_path = /\A(.+)#{FILE_UPLOADER_PATH_PATTERN}/
+ matchd = path_relative_to_upload_dir.match(pattern_to_capture_full_path)
+ raise "Could not capture project full_path from a FileUploader path: \"#{path_relative_to_upload_dir}\"" unless matchd
+ full_path = matchd[1]
+ project = Project.find_by_full_path(full_path)
+ project.id.to_s
end
end