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

groups_finder.rb « finders « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 2e25c97cabede4db9d07a8c62e63d4bf43c1f6e6 (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
153
154
155
156
157
158
159
160
161
162
163
# frozen_string_literal: true

# GroupsFinder
#
# Used to filter Groups by a set of params
#
# Arguments:
#   current_user - which user is requesting groups
#   params:
#     owned: boolean
#     parent: Group
#     all_available: boolean (defaults to true)
#     min_access_level: integer
#     search: string
#     exclude_group_ids: array of integers
#     filter_group_ids: array of integers - only include groups from the specified list of ids
#     include_parent_descendants: boolean (defaults to false) - includes descendant groups when
#                                 filtering by parent. The parent param must be present.
#     include_ancestors: boolean (defaults to true)
#     organization: Scope the groups to the Organizations::Organization
#
# Users with full private access can see all groups. The `owned` and `parent`
# params can be used to restrict the groups that are returned.
#
# Anonymous users will never return any `owned` groups. They will return all
# public groups instead, even if `all_available` is set to false.
class GroupsFinder < UnionFinder
  include CustomAttributesFilter

  attr_reader :current_user, :params

  def initialize(current_user = nil, params = {})
    @current_user = current_user
    @params = params
  end

  def execute
    # filtered_groups can contain an array of scopes, so these
    # are combined into a single query using UNION.
    find_union(filtered_groups, Group).with_route.order_id_desc
  end

  private

  def filtered_groups
    all_groups.map do |groups|
      filter_groups(groups)
    end
  end

  def all_groups
    return [owned_groups] if params[:owned]
    return [groups_with_min_access_level] if min_access_level?
    return [Group.all] if current_user&.can_read_all_resources? && all_available?

    groups = [
      membership_groups,
      authorized_groups,
      public_groups
    ].compact

    groups << Group.none if groups.empty?

    groups
  end

  def owned_groups
    current_user&.owned_groups || Group.none
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def groups_with_min_access_level
    current_user
      .groups
      .where('members.access_level >= ?', params[:min_access_level])
      .self_and_descendants
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def membership_groups
    return unless current_user

    current_user.groups.self_and_descendants
  end

  def authorized_groups
    return unless current_user

    if params.fetch(:include_ancestors, true)
      current_user.authorized_groups.self_and_ancestors
    else
      current_user.authorized_groups
    end
  end

  def public_groups
    # By default, all groups public to the user are included. This is controlled by
    # the :all_available argument, which defaults to true
    return unless include_public_groups?

    Group.unscoped.public_to_user(current_user)
  end

  def filter_groups(groups)
    groups = by_organization(groups)
    groups = by_parent(groups)
    groups = by_custom_attributes(groups)
    groups = filter_group_ids(groups)
    groups = exclude_group_ids(groups)
    by_search(groups)
  end

  def by_organization(groups)
    organization = params[:organization]
    return groups unless organization

    groups.in_organization(organization)
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def by_parent(groups)
    return groups unless params[:parent]

    if params.fetch(:include_parent_descendants, false)
      groups.id_in(params[:parent].descendants)
    else
      groups.where(parent: params[:parent])
    end
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def filter_group_ids(groups)
    return groups unless params[:filter_group_ids]

    groups.id_in(params[:filter_group_ids])
  end

  def exclude_group_ids(groups)
    return groups unless params[:exclude_group_ids]

    groups.id_not_in(params[:exclude_group_ids])
  end

  def by_search(groups)
    return groups unless params[:search].present?

    groups.search(params[:search], include_parents: params[:parent].blank?)
  end

  def min_access_level?
    current_user && params[:min_access_level].present?
  end

  def include_public_groups?
    current_user.nil? || all_available?
  end

  def all_available?
    params.fetch(:all_available, true)
  end
end

GroupsFinder.prepend_mod_with('GroupsFinder')