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:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-28 03:09:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-28 03:09:08 +0300
commitf54a50aa826d0eedcf2e56f51462613bc132f826 (patch)
tree7194aca23f9af822ea55966a6f477b3d8d68ee47 /app/services
parentc77fda905a8619b756163c10a75171dc9cfe7084 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/services')
-rw-r--r--app/services/projects/destroy_service.rb19
-rw-r--r--app/services/repositories/base_service.rb8
-rw-r--r--app/services/repositories/destroy_service.rb4
-rw-r--r--app/services/snippets/bulk_destroy_service.rb74
-rw-r--r--app/services/snippets/destroy_service.rb30
-rw-r--r--app/services/users/destroy_service.rb5
6 files changed, 122 insertions, 18 deletions
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 066d1f1ca72..fd1366d2c4a 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -47,7 +47,7 @@ module Projects
private
- def trash_repositories!
+ def trash_project_repositories!
unless remove_repository(project.repository)
raise_error(s_('DeleteProject|Failed to remove project repository. Please try again or contact administrator.'))
end
@@ -57,6 +57,18 @@ module Projects
end
end
+ def trash_relation_repositories!
+ unless remove_snippets
+ raise_error(s_('DeleteProject|Failed to remove project snippets. Please try again or contact administrator.'))
+ end
+ end
+
+ def remove_snippets
+ response = Snippets::BulkDestroyService.new(current_user, project.snippets).execute
+
+ response.success?
+ end
+
def remove_repository(repository)
return true unless repository
@@ -95,7 +107,8 @@ module Projects
Project.transaction do
log_destroy_event
- trash_repositories!
+ trash_relation_repositories!
+ trash_project_repositories!
# Rails attempts to load all related records into memory before
# destroying: https://github.com/rails/rails/issues/22510
@@ -103,7 +116,7 @@ module Projects
#
# Exclude container repositories because its before_destroy would be
# called multiple times, and it doesn't destroy any database records.
- project.destroy_dependent_associations_in_batches(exclude: [:container_repositories])
+ project.destroy_dependent_associations_in_batches(exclude: [:container_repositories, :snippets])
project.destroy!
end
end
diff --git a/app/services/repositories/base_service.rb b/app/services/repositories/base_service.rb
index 6a39399c791..a99a65b7edb 100644
--- a/app/services/repositories/base_service.rb
+++ b/app/services/repositories/base_service.rb
@@ -7,8 +7,8 @@ class Repositories::BaseService < BaseService
attr_reader :repository
- delegate :project, :disk_path, :full_path, to: :repository
- delegate :repository_storage, to: :project
+ delegate :container, :disk_path, :full_path, to: :repository
+ delegate :repository_storage, to: :container
def initialize(repository)
@repository = repository
@@ -31,7 +31,7 @@ class Repositories::BaseService < BaseService
# gitlab/cookies.git -> gitlab/cookies+119+deleted.git
#
def removal_path
- "#{disk_path}+#{project.id}#{DELETED_FLAG}"
+ "#{disk_path}+#{container.id}#{DELETED_FLAG}"
end
# If we get a Gitaly error, the repository may be corrupted. We can
@@ -40,7 +40,7 @@ class Repositories::BaseService < BaseService
def ignore_git_errors(&block)
yield
rescue Gitlab::Git::CommandError => e
- Gitlab::GitLogger.warn(class: self.class.name, project_id: project.id, disk_path: disk_path, message: e.to_s)
+ Gitlab::GitLogger.warn(class: self.class.name, container_id: container.id, disk_path: disk_path, message: e.to_s)
end
def move_error(path)
diff --git a/app/services/repositories/destroy_service.rb b/app/services/repositories/destroy_service.rb
index 374968f610e..b12d0744387 100644
--- a/app/services/repositories/destroy_service.rb
+++ b/app/services/repositories/destroy_service.rb
@@ -14,11 +14,11 @@ class Repositories::DestroyService < Repositories::BaseService
log_info(%Q{Repository "#{disk_path}" moved to "#{removal_path}" for repository "#{full_path}"})
current_repository = repository
- project.run_after_commit do
+ container.run_after_commit do
Repositories::ShellDestroyService.new(current_repository).execute
end
- log_info("Project \"#{project.full_path}\" was removed")
+ log_info("Repository \"#{full_path}\" was removed")
success
else
diff --git a/app/services/snippets/bulk_destroy_service.rb b/app/services/snippets/bulk_destroy_service.rb
new file mode 100644
index 00000000000..d9cc383a5a6
--- /dev/null
+++ b/app/services/snippets/bulk_destroy_service.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+module Snippets
+ class BulkDestroyService
+ include Gitlab::Allowable
+
+ attr_reader :current_user, :snippets
+
+ DeleteRepositoryError = Class.new(StandardError)
+ SnippetAccessError = Class.new(StandardError)
+
+ def initialize(user, snippets)
+ @current_user = user
+ @snippets = snippets
+ end
+
+ def execute
+ return ServiceResponse.success(message: 'No snippets found.') if snippets.empty?
+
+ user_can_delete_snippets!
+ attempt_delete_repositories!
+ snippets.destroy_all # rubocop: disable DestroyAll
+
+ ServiceResponse.success(message: 'Snippets were deleted.')
+ rescue SnippetAccessError
+ service_response_error("You don't have access to delete these snippets.", 403)
+ rescue DeleteRepositoryError
+ attempt_rollback_repositories
+ service_response_error('Failed to delete snippet repositories.', 400)
+ rescue
+ # In case the delete operation fails
+ attempt_rollback_repositories
+ service_response_error('Failed to remove snippets.', 400)
+ end
+
+ private
+
+ def user_can_delete_snippets!
+ allowed = DeclarativePolicy.user_scope do
+ snippets.find_each.all? { |snippet| user_can_delete_snippet?(snippet) }
+ end
+
+ raise SnippetAccessError unless allowed
+ end
+
+ def user_can_delete_snippet?(snippet)
+ can?(current_user, :admin_snippet, snippet)
+ end
+
+ def attempt_delete_repositories!
+ snippets.each do |snippet|
+ result = Repositories::DestroyService.new(snippet.repository).execute
+
+ raise DeleteRepositoryError if result[:status] == :error
+ end
+ end
+
+ def attempt_rollback_repositories
+ snippets.each do |snippet|
+ result = Repositories::DestroyRollbackService.new(snippet.repository).execute
+
+ log_rollback_error(snippet) if result[:status] == :error
+ end
+ end
+
+ def log_rollback_error(snippet)
+ Gitlab::AppLogger.error("Repository #{snippet.full_path} in path #{snippet.disk_path} could not be rolled back")
+ end
+
+ def service_response_error(message, http_status)
+ ServiceResponse.error(message: message, http_status: http_status)
+ end
+ end
+end
diff --git a/app/services/snippets/destroy_service.rb b/app/services/snippets/destroy_service.rb
index c1e87e74aa4..977626fcf17 100644
--- a/app/services/snippets/destroy_service.rb
+++ b/app/services/snippets/destroy_service.rb
@@ -4,12 +4,13 @@ module Snippets
class DestroyService
include Gitlab::Allowable
- attr_reader :current_user, :project
+ attr_reader :current_user, :snippet
+
+ DestroyError = Class.new(StandardError)
def initialize(user, snippet)
@current_user = user
@snippet = snippet
- @project = snippet&.project
end
def execute
@@ -24,16 +25,29 @@ module Snippets
)
end
- if snippet.destroy
- ServiceResponse.success(message: 'Snippet was deleted.')
- else
- service_response_error('Failed to remove snippet.', 400)
- end
+ attempt_destroy!
+
+ ServiceResponse.success(message: 'Snippet was deleted.')
+ rescue DestroyError
+ service_response_error('Failed to remove snippet repository.', 400)
+ rescue
+ attempt_rollback_repository
+ service_response_error('Failed to remove snippet.', 400)
end
private
- attr_reader :snippet
+ def attempt_destroy!
+ result = Repositories::DestroyService.new(snippet.repository).execute
+
+ raise DestroyError if result[:status] == :error
+
+ snippet.destroy!
+ end
+
+ def attempt_rollback_repository
+ Repositories::DestroyRollbackService.new(snippet.repository).execute
+ end
def user_can_delete_snippet?
can?(current_user, :admin_snippet, snippet)
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index ef79ee3d06e..587a8516394 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -56,10 +56,13 @@ module Users
MigrateToGhostUserService.new(user).execute unless options[:hard_delete]
+ response = Snippets::BulkDestroyService.new(current_user, user.snippets).execute
+ raise DestroyError, response.message if response.error?
+
# Rails attempts to load all related records into memory before
# destroying: https://github.com/rails/rails/issues/22510
# This ensures we delete records in batches.
- user.destroy_dependent_associations_in_batches
+ user.destroy_dependent_associations_in_batches(exclude: [:snippets])
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
user_data = user.destroy