From be339468192c656bf9de0bb77d7e487f338902bf Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Tue, 21 May 2019 16:20:27 -0300 Subject: Delete unauthorized Todos when project is private Delete Todos for guest users when project visibility level is updated to private. --- app/models/todo.rb | 3 ++ app/services/projects/update_service.rb | 1 + app/services/todos/destroy/base_service.rb | 2 +- .../todos/destroy/confidential_issue_service.rb | 35 +++++++++++++++++----- .../todos_destroyer/confidential_issue_worker.rb | 4 +-- 5 files changed, 34 insertions(+), 11 deletions(-) (limited to 'app') diff --git a/app/models/todo.rb b/app/models/todo.rb index 5dcc3e9945a..f1fc5e599eb 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -38,7 +38,9 @@ class Todo < ApplicationRecord self end }, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations + belongs_to :user + belongs_to :issue, -> { where("target_type = 'Issue'") }, foreign_key: :target_id delegate :name, :email, to: :author, prefix: true, allow_nil: true @@ -59,6 +61,7 @@ class Todo < ApplicationRecord scope :for_target, -> (id) { where(target_id: id) } scope :for_commit, -> (id) { where(commit_id: id) } scope :with_api_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: :route }]) } + scope :joins_issue_and_assignees, -> { left_joins(issue: :assignees) } state_machine :state, initial: :pending do event :done do diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb index dfa7bd20254..2bc04470342 100644 --- a/app/services/projects/update_service.rb +++ b/app/services/projects/update_service.rb @@ -64,6 +64,7 @@ module Projects if project.previous_changes.include?(:visibility_level) && project.private? # don't enqueue immediately to prevent todos removal in case of a mistake + TodosDestroyer::ConfidentialIssueWorker.perform_in(Todo::WAIT_FOR_DELETE, nil, project.id) TodosDestroyer::ProjectPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id) elsif (project_changed_feature_keys & todos_features_changes).present? TodosDestroyer::PrivateFeaturesWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id) diff --git a/app/services/todos/destroy/base_service.rb b/app/services/todos/destroy/base_service.rb index f3f1dbb5698..7378f10e7c4 100644 --- a/app/services/todos/destroy/base_service.rb +++ b/app/services/todos/destroy/base_service.rb @@ -13,7 +13,7 @@ module Todos # rubocop: disable CodeReuse/ActiveRecord def without_authorized(items) - items.where('user_id NOT IN (?)', authorized_users) + items.where('todos.user_id NOT IN (?)', authorized_users) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/services/todos/destroy/confidential_issue_service.rb b/app/services/todos/destroy/confidential_issue_service.rb index 6276e332448..6cdd8c16894 100644 --- a/app/services/todos/destroy/confidential_issue_service.rb +++ b/app/services/todos/destroy/confidential_issue_service.rb @@ -2,36 +2,55 @@ module Todos module Destroy + # Service class for deleting todos that belongs to confidential issues. + # It deletes todos for users that are not at least reporters, issue author or assignee. + # + # Accepts issue_id or project_id as argument. + # When issue_id is passed it deletes matching todos for one confidential issue. + # When project_id is passed it deletes matching todos for all confidential issues of the project. class ConfidentialIssueService < ::Todos::Destroy::BaseService extend ::Gitlab::Utils::Override - attr_reader :issue + attr_reader :issues # rubocop: disable CodeReuse/ActiveRecord - def initialize(issue_id) - @issue = Issue.find_by(id: issue_id) + def initialize(issue_id: nil, project_id: nil) + @issues = + if issue_id + Issue.where(id: issue_id) + elsif project_id + project_confidential_issues(project_id) + end end # rubocop: enable CodeReuse/ActiveRecord private + def project_confidential_issues(project_id) + project = Project.find(project_id) + + project.issues.confidential_only + end + override :todos # rubocop: disable CodeReuse/ActiveRecord def todos - Todo.where(target: issue) - .where('user_id != ?', issue.author_id) - .where('user_id NOT IN (?)', issue.assignees.select(:id)) + Todo.joins_issue_and_assignees + .where(target: issues) + .where('issues.confidential = ?', true) + .where('todos.user_id != issues.author_id') + .where('todos.user_id != issue_assignees.user_id') end # rubocop: enable CodeReuse/ActiveRecord override :todos_to_remove? def todos_to_remove? - issue&.confidential? + issues&.any?(&:confidential?) end override :project_ids def project_ids - issue.project_id + issues&.distinct&.select(:project_id) end override :authorized_users diff --git a/app/workers/todos_destroyer/confidential_issue_worker.rb b/app/workers/todos_destroyer/confidential_issue_worker.rb index 481fde8c83d..240a5f98ad5 100644 --- a/app/workers/todos_destroyer/confidential_issue_worker.rb +++ b/app/workers/todos_destroyer/confidential_issue_worker.rb @@ -5,8 +5,8 @@ module TodosDestroyer include ApplicationWorker include TodosDestroyerQueue - def perform(issue_id) - ::Todos::Destroy::ConfidentialIssueService.new(issue_id).execute + def perform(issue_id = nil, project_id = nil) + ::Todos::Destroy::ConfidentialIssueService.new(issue_id: issue_id, project_id: project_id).execute end end end -- cgit v1.2.3