diff options
Diffstat (limited to 'app/services/groups/transfer_service.rb')
-rw-r--r-- | app/services/groups/transfer_service.rb | 85 |
1 files changed, 73 insertions, 12 deletions
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb index 58e8cca04bb..6f6f33c2903 100644 --- a/app/services/groups/transfer_service.rb +++ b/app/services/groups/transfer_service.rb @@ -1,8 +1,15 @@ module Groups class TransferService < Groups::BaseService - include TransferErrorMessages + ERROR_MESSAGES = { + database_not_supported: 'Database is not supported.', + group_with_same_path: 'The parent group has a group with the same path.', + group_is_already_root: 'Group is already a root group.', + same_parent_as_current: 'Group is already associated to the parent group.', + invalid_policies: "You don't have enough permissions." + }.freeze TransferError = Class.new(StandardError) + attr_reader :error def initialize(group, user, params = {}) @@ -10,24 +17,78 @@ module Groups @error = nil end - private + def execute(new_parent_group) + @new_parent_group = new_parent_group + ensure_allowed_transfer + proceed_to_transfer - def with_transfer_error_handling - yield - rescue TransferError => e + rescue TransferError, ActiveRecord::RecordInvalid, Gitlab::UpdatePathError => e @error = "Transfer failed: " + e.message false - rescue Gitlab::UpdatePathError - @error = friendly_update_path_error - false end - def raise_transfer_error(message) - if message.is_a?(Symbol) - raise TransferError, error_messages[message] + private + + def proceed_to_transfer + Group.transaction do + update_children_and_projects_visibility if @new_parent_group.present? + update_group_attributes + end + end + + def ensure_allowed_transfer + raise_transfer_error(:group_is_already_root) if group_is_already_root + raise_transfer_error(:database_not_supported) unless Group.supports_nested_groups? + raise_transfer_error(:same_parent_as_current) if same_parent? + raise_transfer_error(:group_with_same_path) if group_with_same_path? + raise_transfer_error(:invalid_policies) unless valid_policies? + end + + def group_is_already_root + @new_parent_group.blank? && @group.parent.nil? + end + + def same_parent? + @new_parent_group.present? && @new_parent_group.id == @group.parent_id + end + + def valid_policies? + if @new_parent_group.present? + can?(current_user, :admin_group, @group) && + can?(current_user, :create_subgroup, @new_parent_group) else - raise TransferError, message + can?(current_user, :admin_group, @group) + end + end + + def group_with_same_path? + if @new_parent_group.present? + @new_parent_group.children.exists?(path: @group.path) + else + Group.exists?(path: @group.path, parent: nil) + end + end + + def update_group_attributes + @group.visibility_level = @new_parent_group.visibility_level if @new_parent_group.present? + @group.parent = @new_parent_group + @group.save! + end + + def update_children_and_projects_visibility + descendants = @group.descendants.where("visibility_level > ?", @new_parent_group.visibility_level) + descendants.each do |subgroup| + subgroup.update_column(:visibility_level, @new_parent_group.visibility_level) end + + @group + .projects + .where("visibility_level > ?", @new_parent_group.visibility_level) + .update_all(visibility_level: @new_parent_group.visibility_level) + end + + def raise_transfer_error(message) + raise TransferError, ERROR_MESSAGES[message] end end end |