summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Van Landuyt <bob@vanlanduyt.co>2017-09-04 16:23:55 +0200
committerBob Van Landuyt <bob@vanlanduyt.co>2017-10-04 22:46:49 +0200
commit063b5312111ccea62f84fa9f68a2262dc1f66e64 (patch)
tree44f6dbae88e55dc6c1e24ac6aa888e6cb2f3ea3a
parent283e13b836f805af149c271088bc9305e0ce0ada (diff)
downloadgitlab-ce-063b5312111ccea62f84fa9f68a2262dc1f66e64.tar.gz
Add a separate finder for collecting children of groups
-rw-r--r--app/finders/group_children_finder.rb54
-rw-r--r--spec/finders/group_children_finder_spec.rb71
2 files changed, 125 insertions, 0 deletions
diff --git a/app/finders/group_children_finder.rb b/app/finders/group_children_finder.rb
new file mode 100644
index 00000000000..d95dfa2a877
--- /dev/null
+++ b/app/finders/group_children_finder.rb
@@ -0,0 +1,54 @@
+class GroupChildrenFinder
+ include Gitlab::Allowable
+
+ attr_reader :current_user, :parent_group, :params
+
+ def initialize(current_user = nil, parent_group:, params: {})
+ @current_user = current_user
+ @parent_group = parent_group
+ @params = params
+ end
+
+ def execute
+ Kaminari.paginate_array(children)
+ end
+
+ # This allows us to fetch only the count without loading the objects. Unless
+ # the objects were already loaded.
+ def total_count
+ @total_count ||= if defined?(@children)
+ children.size
+ else
+ child_groups.count + projects.count
+ end
+ end
+
+ private
+
+ def children
+ @children ||= child_groups + projects
+ end
+
+ def child_groups
+ return Group.none unless Group.supports_nested_groups?
+ return Group.none unless can?(current_user, :read_group, parent_group)
+
+ groups = GroupsFinder.new(current_user,
+ parent: parent_group,
+ all_available: true,
+ all_children_for_parent: params[:filter_groups].present?).execute
+
+ groups = groups.search(params[:filter]) if params[:filter].present?
+ groups = groups.includes(:route).includes(:children)
+ groups.sort(params[:sort])
+ end
+
+ def projects
+ return Project.none unless can?(current_user, :read_group, parent_group)
+
+ projects = GroupProjectsFinder.new(group: parent_group, params: params, current_user: current_user).execute
+ projects = projects.includes(:route)
+ projects = projects.search(params[:filter]) if params[:filter].present?
+ projects.sort(params[:sort])
+ end
+end
diff --git a/spec/finders/group_children_finder_spec.rb b/spec/finders/group_children_finder_spec.rb
new file mode 100644
index 00000000000..afd96e27a1d
--- /dev/null
+++ b/spec/finders/group_children_finder_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+
+describe GroupChildrenFinder do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:params) { {} }
+ subject(:finder) { described_class.new(user, parent_group: group, params: params) }
+
+ before do
+ group.add_owner(user)
+ end
+
+ describe '#execute' do
+ it 'includes projects' do
+ project = create(:project, namespace: group)
+
+ expect(finder.execute).to contain_exactly(project)
+ end
+
+ context 'with a filter' do
+ let(:params) { { filter: 'test' } }
+
+ it 'includes only projects matching the filter' do
+ _other_project = create(:project, namespace: group)
+ matching_project = create(:project, namespace: group, name: 'testproject')
+
+ expect(finder.execute).to contain_exactly(matching_project)
+ end
+ end
+ end
+
+ context 'with nested groups', :nested_groups do
+ let!(:project) { create(:project, namespace: group) }
+ let!(:subgroup) { create(:group, parent: group) }
+
+ describe '#execute' do
+ it 'contains projects and subgroups' do
+ expect(finder.execute).to contain_exactly(subgroup, project)
+ end
+
+ context 'with a filter' do
+ let(:params) { { filter: 'test' } }
+
+ it 'contains only matching projects and subgroups' do
+ matching_project = create(:project, namespace: group, name: 'Testproject')
+ matching_subgroup = create(:group, name: 'testgroup', parent: group)
+
+ expect(finder.execute).to contain_exactly(matching_subgroup, matching_project)
+ end
+ end
+ end
+
+ describe '#total_count' do
+ it 'counts the array children were already loaded' do
+ finder.instance_variable_set(:@children, [double])
+
+ expect(finder).not_to receive(:child_groups)
+ expect(finder).not_to receive(:projects)
+
+ expect(finder.total_count).to eq(1)
+ end
+
+ it 'performs a count without loading children when they are not loaded yet' do
+ expect(finder).to receive(:child_groups).and_call_original
+ expect(finder).to receive(:projects).and_call_original
+
+ expect(finder.total_count).to eq(2)
+ end
+ end
+ end
+end