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

entity_leave_service.rb « destroy « todos « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 387c5ce063a89f893b6bb50d9e29b8c57d12048d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# frozen_string_literal: true

module Todos
  module Destroy
    class EntityLeaveService < ::Todos::Destroy::BaseService
      extend ::Gitlab::Utils::Override

      attr_reader :user, :entity

      def initialize(user_id, entity_id, entity_type)
        unless %w[Group Project].include?(entity_type)
          raise ArgumentError, "#{entity_type} is not an entity user can leave"
        end

        @user = UserFinder.new(user_id).find_by_id
        @entity = entity_type.constantize.find_by(id: entity_id) # rubocop: disable CodeReuse/ActiveRecord
      end

      def execute
        return unless entity && user

        # if at least reporter, all entities including confidential issues can be accessed
        return if user_has_reporter_access?

        remove_confidential_resource_todos
        remove_group_todos

        if entity.private?
          remove_project_todos
        else
          enqueue_private_features_worker
        end
      end

      private

      def enqueue_private_features_worker
        projects.each do |project|
          TodosDestroyer::PrivateFeaturesWorker.perform_async(project.id, user.id)
        end
      end

      def remove_confidential_resource_todos
        # Deletes todos for confidential issues
        Todo
          .for_target(confidential_issues.select(:id))
          .for_type(Issue.name)
          .for_user(user)
          .delete_all

        # Deletes todos for internal notes on unauthorized projects
        Todo
          .for_type(Issue.name)
          .for_internal_notes
          .for_project(non_authorized_reporter_projects) # Only Reporter+ can read internal notes
          .for_user(user)
          .delete_all
      end

      def remove_project_todos
        # Issues are viewable by guests (even in private projects), so remove those todos
        # from projects without guest access
        Todo
          .for_project(non_authorized_guest_projects)
          .for_user(user)
          .delete_all

        # MRs require reporter access, so remove those todos that are not authorized
        Todo
          .for_project(non_authorized_reporter_projects)
          .for_type(MergeRequest.name)
          .for_user(user)
          .delete_all
      end

      def remove_group_todos
        return unless entity.is_a?(Namespace)

        Todo
          .for_group(unauthorized_private_groups)
          .for_user(user)
          .delete_all
      end

      def projects
        condition = case entity
                    when Project
                      { id: entity.id }
                    when Namespace
                      { namespace_id: non_authorized_reporter_groups }
                    end

        Project.where(condition) # rubocop: disable CodeReuse/ActiveRecord
      end

      def authorized_reporter_projects
        user.authorized_projects(Gitlab::Access::REPORTER).select(:id)
      end

      def authorized_guest_projects
        user.authorized_projects(Gitlab::Access::GUEST).select(:id)
      end

      def non_authorized_reporter_projects
        projects.id_not_in(authorized_reporter_projects)
      end

      def non_authorized_guest_projects
        projects.id_not_in(authorized_guest_projects)
      end

      def authorized_reporter_groups
        GroupsFinder.new(user, min_access_level: Gitlab::Access::REPORTER).execute.select(:id)
      end

      # rubocop: disable CodeReuse/ActiveRecord
      def unauthorized_private_groups
        return [] unless entity.is_a?(Namespace)

        groups = entity.self_and_descendants.private_only

        groups.select(:id)
          .id_not_in(GroupsFinder.new(user, all_available: false).execute.select(:id).reorder(nil))
      end
      # rubocop: enable CodeReuse/ActiveRecord

      def non_authorized_reporter_groups
        entity.self_and_descendants.select(:id)
          .id_not_in(authorized_reporter_groups)
      end

      def user_has_reporter_access?
        return unless entity.is_a?(Namespace)

        entity.member?(User.find(user.id), Gitlab::Access::REPORTER)
      end

      def confidential_issues
        assigned_ids = IssueAssignee.select(:issue_id).for_assignee(user)

        Issue
          .in_projects(projects)
          .confidential_only
          .not_in_projects(authorized_reporter_projects)
          .not_authored_by(user)
          .id_not_in(assigned_ids)
      end
    end
  end
end

Todos::Destroy::EntityLeaveService.prepend_mod_with('Todos::Destroy::EntityLeaveService')