Add User#nested_groups and User#nested_projects methods
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
This commit is contained in:
parent
51c4b20c48
commit
52c5f9c97f
7 changed files with 73 additions and 4 deletions
|
@ -60,6 +60,21 @@ module Routable
|
|||
joins(:route).where(wheres.join(' OR '))
|
||||
end
|
||||
end
|
||||
|
||||
# Builds a relation to find multiple objects that are nested under user membership
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# Klass.member_descendants(1)
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def member_descendants(user_id)
|
||||
joins(:route).
|
||||
joins("INNER JOIN routes r2 ON routes.path LIKE CONCAT(r2.path, '/%')
|
||||
INNER JOIN members ON members.source_id = r2.source_id
|
||||
AND members.source_type = r2.source_type").
|
||||
where('members.user_id = ?', user_id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -194,7 +194,7 @@ class Namespace < ActiveRecord::Base
|
|||
paths << path
|
||||
end
|
||||
|
||||
self.class.joins(:route).where('routes.path IN (?)', paths).order_id_asc
|
||||
self.class.joins(:route).where('routes.path IN (?)', paths).reorder('routes.path ASC')
|
||||
else
|
||||
self.class.none
|
||||
end
|
||||
|
@ -202,7 +202,7 @@ class Namespace < ActiveRecord::Base
|
|||
|
||||
# Scopes the model on direct and indirect children of the record
|
||||
def descendants
|
||||
self.class.joins(:route).where('routes.path LIKE ?', "#{route.path}/%").order_id_asc
|
||||
self.class.joins(:route).where('routes.path LIKE ?', "#{route.path}/%").reorder('routes.path ASC')
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -15,8 +15,9 @@ class Route < ActiveRecord::Base
|
|||
# rubocop:disable Rails/FindEach
|
||||
Route.where('path LIKE ?', "#{path_was}/%").each do |route|
|
||||
# Note that update column skips validation and callbacks.
|
||||
# We need this to avoid recursive call of rename_children method
|
||||
# We need this to avoid recursive call of rename_descendants method
|
||||
route.update_column(:path, route.path.sub(path_was, path))
|
||||
end
|
||||
# rubocop:enable Rails/FindEach
|
||||
end
|
||||
end
|
||||
|
|
|
@ -439,6 +439,15 @@ class User < ActiveRecord::Base
|
|||
Group.where("namespaces.id IN (#{union.to_sql})")
|
||||
end
|
||||
|
||||
def nested_groups
|
||||
Group.member_descendants(id)
|
||||
end
|
||||
|
||||
def nested_projects
|
||||
Project.joins(:namespace).where('namespaces.parent_id IS NOT NULL').
|
||||
member_descendants(id)
|
||||
end
|
||||
|
||||
def refresh_authorized_projects
|
||||
Users::RefreshAuthorizedProjectsService.new(self).execute
|
||||
end
|
||||
|
|
|
@ -119,7 +119,8 @@ module Users
|
|||
user.personal_projects.select("#{user.id} AS user_id, projects.id AS project_id, #{Gitlab::Access::MASTER} AS access_level"),
|
||||
user.groups_projects.select_for_project_authorization,
|
||||
user.projects.select_for_project_authorization,
|
||||
user.groups.joins(:shared_projects).select_for_project_authorization
|
||||
user.groups.joins(:shared_projects).select_for_project_authorization,
|
||||
user.nested_projects.select_for_project_authorization
|
||||
]
|
||||
|
||||
Gitlab::SQL::Union.new(relations)
|
||||
|
|
|
@ -68,4 +68,14 @@ describe Group, 'Routable' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.member_descendants' do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:nested_group) { create(:group, parent: group) }
|
||||
|
||||
before { group.add_owner(user) }
|
||||
subject { described_class.member_descendants(user.id) }
|
||||
|
||||
it { is_expected.to eq([nested_group]) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1356,6 +1356,39 @@ describe User, models: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#nested_groups' do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:group) { create(:group) }
|
||||
let!(:nested_group) { create(:group, parent: group) }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
|
||||
# Add more data to ensure method does not include wrong groups
|
||||
create(:group).add_owner(create(:user))
|
||||
end
|
||||
|
||||
it { expect(user.nested_groups).to eq([nested_group]) }
|
||||
end
|
||||
|
||||
describe '#nested_projects' do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:group) { create(:group) }
|
||||
let!(:nested_group) { create(:group, parent: group) }
|
||||
let!(:project) { create(:project, namespace: group) }
|
||||
let!(:nested_project) { create(:project, namespace: nested_group) }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
|
||||
# Add more data to ensure method does not include wrong projects
|
||||
other_project = create(:project, namespace: create(:group, :nested))
|
||||
other_project.add_developer(create(:user))
|
||||
end
|
||||
|
||||
it { expect(user.nested_projects).to eq([nested_project]) }
|
||||
end
|
||||
|
||||
describe '#refresh_authorized_projects', redis: true do
|
||||
let(:project1) { create(:empty_project) }
|
||||
let(:project2) { create(:empty_project) }
|
||||
|
|
Loading…
Reference in a new issue