Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/groups/transfer_service.rb')
-rw-r--r--app/services/groups/transfer_service.rb96
1 files changed, 96 insertions, 0 deletions
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
new file mode 100644
index 00000000000..e591c820cff
--- /dev/null
+++ b/app/services/groups/transfer_service.rb
@@ -0,0 +1,96 @@
+module Groups
+ class TransferService < Groups::BaseService
+ ERROR_MESSAGES = {
+ database_not_supported: 'Database is not supported.',
+ namespace_with_same_path: 'The parent group already has a subgroup 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 = {})
+ super
+ @error = nil
+ end
+
+ def execute(new_parent_group)
+ @new_parent_group = new_parent_group
+ ensure_allowed_transfer
+ proceed_to_transfer
+
+ rescue TransferError, ActiveRecord::RecordInvalid, Gitlab::UpdatePathError => e
+ @group.errors.clear
+ @error = "Transfer failed: " + e.message
+ false
+ end
+
+ private
+
+ def proceed_to_transfer
+ Group.transaction do
+ 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(:invalid_policies) unless valid_policies?
+ raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path?
+ end
+
+ def group_is_already_root?
+ !@new_parent_group && !@group.has_parent?
+ end
+
+ def same_parent?
+ @new_parent_group && @new_parent_group.id == @group.parent_id
+ end
+
+ def valid_policies?
+ return false unless can?(current_user, :admin_group, @group)
+
+ if @new_parent_group
+ can?(current_user, :create_subgroup, @new_parent_group)
+ else
+ can?(current_user, :create_group)
+ end
+ end
+
+ def namespace_with_same_path?
+ Namespace.exists?(path: @group.path, parent: @new_parent_group)
+ end
+
+ def update_group_attributes
+ if @new_parent_group && @new_parent_group.visibility_level < @group.visibility_level
+ update_children_and_projects_visibility
+ @group.visibility_level = @new_parent_group.visibility_level
+ end
+
+ @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)
+
+ Group
+ .where(id: descendants.select(:id))
+ .update_all(visibility_level: @new_parent_group.visibility_level)
+
+ @group
+ .all_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