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
164
165
|
# 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)
#
# 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
def initialize(current_user = nil, params = {})
@current_user = current_user
@params = params
end
def execute
items = all_groups.map do |item|
item = by_parent(item)
item = by_custom_attributes(item)
item = filter_group_ids(item)
item = exclude_group_ids(item)
item = by_search(item)
item
end
find_union(items, Group).with_route.order_id_desc
end
private
attr_reader :current_user, :params
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 = []
groups = get_groups_for_user if current_user
groups << Group.unscoped.public_to_user(current_user) if include_public_groups?
groups << Group.none if groups.empty?
groups
end
def groups_for_ancestors
current_user.authorized_groups
end
def groups_for_descendants
current_user.groups
end
# rubocop: disable CodeReuse/ActiveRecord
def groups_with_min_access_level
groups = current_user
.groups
.where('members.access_level >= ?', params[:min_access_level])
if Feature.enabled?(:use_traversal_ids_groups_finder, current_user)
groups.self_and_descendants
else
Gitlab::ObjectHierarchy
.new(groups)
.base_and_descendants
end
end
# rubocop: enable CodeReuse/ActiveRecord
def exclude_group_ids(groups)
return groups unless params[:exclude_group_ids]
groups.id_not_in(params[:exclude_group_ids])
end
def filter_group_ids(groups)
return groups unless params[:filter_group_ids]
groups.id_in(params[:filter_group_ids])
end
# rubocop: disable CodeReuse/ActiveRecord
def by_parent(groups)
return groups unless params[:parent]
if include_parent_descendants?
groups.id_in(params[:parent].descendants)
else
groups.where(parent: params[:parent])
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def by_search(groups)
return groups unless params[:search].present?
groups.search(params[:search], include_parents: params[:parent].blank?)
end
# rubocop: enable CodeReuse/ActiveRecord
def owned_groups
current_user&.owned_groups || Group.none
end
def include_public_groups?
current_user.nil? || all_available?
end
def all_available?
params.fetch(:all_available, true)
end
def include_parent_descendants?
params.fetch(:include_parent_descendants, false)
end
def min_access_level?
current_user && params[:min_access_level].present?
end
def include_ancestors?
params.fetch(:include_ancestors, true)
end
def get_groups_for_user
groups = []
if Feature.enabled?(:use_traversal_ids_groups_finder, current_user)
groups << if include_ancestors?
current_user.authorized_groups.self_and_ancestors
else
current_user.authorized_groups
end
groups << current_user.groups.self_and_descendants
elsif include_ancestors?
groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects
else
groups << current_user.authorized_groups
groups << Gitlab::ObjectHierarchy.new(groups_for_descendants).base_and_descendants
end
groups
end
end
|