Commit a9fdf62b authored by James Lopez's avatar James Lopez

refactoring relation factory, changed from module to class

parent 102074c8
...@@ -32,6 +32,11 @@ module Gitlab ...@@ -32,6 +32,11 @@ module Gitlab
project: project) project: project)
end end
# Loops through the tree of models defined in import_export.yml and
# finds them in the imported JSON so they can be instantiated and saved
# in the DB. The structure and relationships between models are guessed from
# the configuration yaml file too.
# Finally, it updates each attribute in the newly imported project.
def create_relations def create_relations
saved = [] saved = []
default_relation_list.each do |relation| default_relation_list.each do |relation|
......
module Gitlab module Gitlab
module ImportExport module ImportExport
module RelationFactory class RelationFactory
extend self
OVERRIDES = { snippets: :project_snippets, OVERRIDES = { snippets: :project_snippets,
ci_commits: 'Ci::Commit', ci_commits: 'Ci::Commit',
...@@ -13,47 +12,54 @@ module Gitlab ...@@ -13,47 +12,54 @@ module Gitlab
USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id].freeze USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id].freeze
# Guesses a model and saves it to the DB given its name `relation_sym` def self.create(*args)
def create(relation_sym:, relation_hash:, members_mapper:, user_admin:) new(*args).create
relation_sym = parse_relation_sym(relation_sym) end
klass = relation_class(relation_sym) def initialize(relation_sym:, relation_hash:, members_mapper:, user_admin:)
relation_hash.delete('id') @relation_name = OVERRIDES[relation_sym] || relation_sym
@relation_hash = relation_hash.except('id')
@members_mapper = members_mapper
@user_admin = user_admin
end
update_missing_author(relation_hash, members_mapper, user_admin) if relation_sym == :notes # Creates an object from an actual model with name "relation_sym" with params from
update_user_references(relation_hash, members_mapper.map) # the relation_hash, updating references with new object IDs, mapping users using
update_project_references(relation_hash, klass) # the "members_mapper" object, also updating notes if required.
reset_tokens(relation_hash) if relation_sym == 'Ci::Trigger' def create
set_note_author if @relation_name == :notes
update_user_references
update_project_references
reset_tokens if @relation_name == 'Ci::Trigger'
generate_imported_object(klass, relation_hash, relation_sym) generate_imported_object
end end
private private
def update_user_references(relation_hash, members_map) def update_user_references
USER_REFERENCES.each do |reference| USER_REFERENCES.each do |reference|
if relation_hash[reference] if @relation_hash[reference]
relation_hash[reference] = members_map[relation_hash[reference]] @relation_hash[reference] = @members_mapper.map[@relation_hash[reference]]
end end
end end
end end
def update_missing_author(relation_hash, members_map, user_admin) # Sets the author for a note. If the user importing the project
old_author_id = relation_hash['author_id'] # has admin access, an actual mapping with new project members
# will be used. Otherwise, a note stating the original author name
# is left.
def set_note_author
old_author_id = @relation_hash['author_id']
# Users with admin access can map users # Users with admin access can map users
if user_admin @relation_hash['author_id'] = admin_user? ? @members_mapper.map[old_author_id] : @members_mapper.default_user_id
relation_hash['author_id'] = members_map.map[old_author_id]
else
relation_hash['author_id'] = members_map.default_user_id
end
author = relation_hash.delete('author')
return unless user_admin && members_map.note_member_list.include?(old_author_id) author = @relation_hash.delete('author')
relation_hash['note'] = '*Blank note*' if relation_hash['note'].blank? if admin_user? && @members_mapper.note_member_list.include?(old_author_id)
relation_hash['note'] += missing_author_note(relation_hash['updated_at'], author['name']) update_note_for_missing_author(author['name'])
end
end end
def missing_author_note(updated_at, author_name) def missing_author_note(updated_at, author_name)
...@@ -61,57 +67,60 @@ module Gitlab ...@@ -61,57 +67,60 @@ module Gitlab
"\n\n *By #{author_name} on #{timestamp} (imported from GitLab project)*" "\n\n *By #{author_name} on #{timestamp} (imported from GitLab project)*"
end end
def generate_imported_object(klass, relation_hash, relation_sym) def generate_imported_object
if relation_sym == 'commit_status' # call #trace= method after assigning the other attributes if @relation_sym == 'commit_status' # call #trace= method after assigning the other attributes
trace = relation_hash.delete('trace') trace = @relation_hash.delete('trace')
imported_object(klass, relation_hash) do |imported_object| imported_object do |object|
imported_object.trace = trace object.trace = trace
imported_object.commit_id = nil object.commit_id = nil
end end
else else
imported_object(klass, relation_hash) imported_object
end end
end end
def update_project_references(relation_hash, klass) def update_project_references
project_id = relation_hash.delete('project_id') project_id = @relation_hash.delete('project_id')
# project_id may not be part of the export, but we always need to populate it if required.
@relation_hash['project_id'] = project_id if relation_class.column_names.include?('project_id')
@relation_hash['gl_project_id'] = project_id if @relation_hash['gl_project_id']
@relation_hash['target_project_id'] = project_id if @relation_hash['target_project_id']
@relation_hash['source_project_id'] = -1 if @relation_hash['source_project_id']
if relation_hash['source_project_id'] && relation_hash['target_project_id']
# If source and target are the same, populate them with the new project ID. # If source and target are the same, populate them with the new project ID.
if relation_hash['target_project_id'] == relation_hash['source_project_id'] if @relation_hash['source_project_id'] && @relation_hash['target_project_id'] &&
relation_hash['source_project_id'] = project_id @relation_hash['target_project_id'] == @relation_hash['source_project_id']
else @relation_hash['source_project_id'] = project_id
relation_hash['source_project_id'] = -1
end end
end end
relation_hash['target_project_id'] = project_id if relation_hash['target_project_id']
# project_id may not be part of the export, but we always need to populate it if required. def reset_tokens
relation_hash['project_id'] = project_id if klass.column_names.include?('project_id')
relation_hash['gl_project_id'] = project_id if relation_hash ['gl_project_id']
end
def reset_tokens(relation_hash)
return unless Gitlab::ImportExport.reset_tokens? return unless Gitlab::ImportExport.reset_tokens?
# If we import/export a project to the same instance, tokens will have to be reseated. # If we import/export a project to the same instance, tokens will have to be reseated.
relation_hash['token'] = nil @relation_hash['token'] = nil
end
def relation_class(relation_sym)
relation_sym.to_s.classify.constantize
end end
def parse_relation_sym(relation_sym) def relation_class
OVERRIDES[relation_sym] || relation_sym @relation_class ||= @relation_name.to_s.classify.constantize
end end
def imported_object(klass, relation_hash) def imported_object
imported_object = klass.new(relation_hash) imported_object = relation_class.new(@relation_hash)
yield(imported_object) if block_given? yield(imported_object) if block_given?
imported_object.importing = true if imported_object.respond_to?(:importing) imported_object.importing = true if imported_object.respond_to?(:importing)
imported_object imported_object
end end
def update_note_for_missing_author(author_name)
@relation_hash['note'] = '*Blank note*' if @relation_hash['note'].blank?
@relation_hash['note'] += missing_author_note(@relation_hash['updated_at'], author_name)
end
def admin_user?
@user_admin
end
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment