summaryrefslogtreecommitdiff
path: root/app/services/groups/transfer_service.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/groups/transfer_service.rb')
-rw-r--r--app/services/groups/transfer_service.rb85
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