Loading app/controllers/groups_controller.rb +2 −0 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,8 @@ def show end end def subgroups def subgroups return not_found unless Group.supports_nested_groups? @nested_groups = GroupsFinder.new(current_user, parent: group).execute @nested_groups = GroupsFinder.new(current_user, parent: group).execute @nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present? @nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present? end end Loading app/models/concerns/routable.rb +0 −83 Original line number Original line Diff line number Diff line Loading @@ -84,89 +84,6 @@ def where_full_path_in(paths) joins(:route).where(wheres.join(' OR ')) joins(:route).where(wheres.join(' OR ')) end end 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 # Builds a relation to find multiple objects that are nested under user # membership. Includes the parent, as opposed to `#member_descendants` # which only includes the descendants. # # Usage: # # Klass.member_self_and_descendants(1) # # Returns an ActiveRecord::Relation. def member_self_and_descendants(user_id) joins(:route). joins("INNER JOIN routes r2 ON routes.path LIKE CONCAT(r2.path, '/%') OR routes.path = 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 # Returns all objects in a hierarchy, where any node in the hierarchy is # under the user membership. # # Usage: # # Klass.member_hierarchy(1) # # Examples: # # Given the following group tree... # # _______group_1_______ # | | # | | # nested_group_1 nested_group_2 # | | # | | # nested_group_1_1 nested_group_2_1 # # # ... the following results are returned: # # * the user is a member of group 1 # => 'group_1', # 'nested_group_1', nested_group_1_1', # 'nested_group_2', 'nested_group_2_1' # # * the user is a member of nested_group_2 # => 'group1', # 'nested_group_2', 'nested_group_2_1' # # * the user is a member of nested_group_2_1 # => 'group1', # 'nested_group_2', 'nested_group_2_1' # # Returns an ActiveRecord::Relation. def member_hierarchy(user_id) paths = member_self_and_descendants(user_id).pluck('routes.path') return none if paths.empty? wheres = paths.map do |path| "#{connection.quote(path)} = routes.path OR #{connection.quote(path)} LIKE CONCAT(routes.path, '/%')" end joins(:route).where(wheres.join(' OR ')) end end end def full_name def full_name Loading app/models/concerns/select_for_project_authorization.rb +5 −1 Original line number Original line Diff line number Diff line Loading @@ -3,7 +3,11 @@ module SelectForProjectAuthorization module ClassMethods module ClassMethods def select_for_project_authorization def select_for_project_authorization select("members.user_id, projects.id AS project_id, members.access_level") select("projects.id AS project_id, members.access_level") end def select_as_master_for_project_authorization select(["projects.id AS project_id", "#{Gitlab::Access::MASTER} AS access_level"]) end end end end end end app/models/group.rb +5 −1 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,10 @@ class Group < Namespace after_save :update_two_factor_requirement after_save :update_two_factor_requirement class << self class << self def supports_nested_groups? Gitlab::Database.postgresql? end # Searches for groups matching the given query. # Searches for groups matching the given query. # # # This method uses ILIKE on PostgreSQL and LIKE on MySQL. # This method uses ILIKE on PostgreSQL and LIKE on MySQL. Loading Loading @@ -78,7 +82,7 @@ def select_for_project_authorization if current_scope.joins_values.include?(:shared_projects) if current_scope.joins_values.include?(:shared_projects) joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id') joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id') .where('project_namespace.share_with_group_lock = ?', false) .where('project_namespace.share_with_group_lock = ?', false) .select("members.user_id, projects.id AS project_id, LEAST(project_group_links.group_access, members.access_level) AS access_level") .select("projects.id AS project_id, LEAST(project_group_links.group_access, members.access_level) AS access_level") else else super super end end Loading app/models/namespace.rb +9 −15 Original line number Original line Diff line number Diff line Loading @@ -176,26 +176,20 @@ def shared_runners_enabled? projects.with_shared_runners.any? projects.with_shared_runners.any? end end # Scopes the model on ancestors of the record # Returns all the ancestors of the current namespaces. def ancestors def ancestors if parent_id return self.class.none unless parent_id path = route ? route.path : full_path paths = [] until path.blank? Gitlab::GroupHierarchy. path = path.rpartition('/').first new(self.class.where(id: parent_id)). paths << path base_and_ancestors end end self.class.joins(:route).where('routes.path IN (?)', paths).reorder('routes.path ASC') # Returns all the descendants of the current namespace. else self.class.none end end # Scopes the model on direct and indirect children of the record def descendants def descendants self.class.joins(:route).merge(Route.inside_path(route.path)).reorder('routes.path ASC') Gitlab::GroupHierarchy. new(self.class.where(parent_id: id)). base_and_descendants end end def user_ids_for_project_authorizations def user_ids_for_project_authorizations Loading Loading
app/controllers/groups_controller.rb +2 −0 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,8 @@ def show end end def subgroups def subgroups return not_found unless Group.supports_nested_groups? @nested_groups = GroupsFinder.new(current_user, parent: group).execute @nested_groups = GroupsFinder.new(current_user, parent: group).execute @nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present? @nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present? end end Loading
app/models/concerns/routable.rb +0 −83 Original line number Original line Diff line number Diff line Loading @@ -84,89 +84,6 @@ def where_full_path_in(paths) joins(:route).where(wheres.join(' OR ')) joins(:route).where(wheres.join(' OR ')) end end 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 # Builds a relation to find multiple objects that are nested under user # membership. Includes the parent, as opposed to `#member_descendants` # which only includes the descendants. # # Usage: # # Klass.member_self_and_descendants(1) # # Returns an ActiveRecord::Relation. def member_self_and_descendants(user_id) joins(:route). joins("INNER JOIN routes r2 ON routes.path LIKE CONCAT(r2.path, '/%') OR routes.path = 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 # Returns all objects in a hierarchy, where any node in the hierarchy is # under the user membership. # # Usage: # # Klass.member_hierarchy(1) # # Examples: # # Given the following group tree... # # _______group_1_______ # | | # | | # nested_group_1 nested_group_2 # | | # | | # nested_group_1_1 nested_group_2_1 # # # ... the following results are returned: # # * the user is a member of group 1 # => 'group_1', # 'nested_group_1', nested_group_1_1', # 'nested_group_2', 'nested_group_2_1' # # * the user is a member of nested_group_2 # => 'group1', # 'nested_group_2', 'nested_group_2_1' # # * the user is a member of nested_group_2_1 # => 'group1', # 'nested_group_2', 'nested_group_2_1' # # Returns an ActiveRecord::Relation. def member_hierarchy(user_id) paths = member_self_and_descendants(user_id).pluck('routes.path') return none if paths.empty? wheres = paths.map do |path| "#{connection.quote(path)} = routes.path OR #{connection.quote(path)} LIKE CONCAT(routes.path, '/%')" end joins(:route).where(wheres.join(' OR ')) end end end def full_name def full_name Loading
app/models/concerns/select_for_project_authorization.rb +5 −1 Original line number Original line Diff line number Diff line Loading @@ -3,7 +3,11 @@ module SelectForProjectAuthorization module ClassMethods module ClassMethods def select_for_project_authorization def select_for_project_authorization select("members.user_id, projects.id AS project_id, members.access_level") select("projects.id AS project_id, members.access_level") end def select_as_master_for_project_authorization select(["projects.id AS project_id", "#{Gitlab::Access::MASTER} AS access_level"]) end end end end end end
app/models/group.rb +5 −1 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,10 @@ class Group < Namespace after_save :update_two_factor_requirement after_save :update_two_factor_requirement class << self class << self def supports_nested_groups? Gitlab::Database.postgresql? end # Searches for groups matching the given query. # Searches for groups matching the given query. # # # This method uses ILIKE on PostgreSQL and LIKE on MySQL. # This method uses ILIKE on PostgreSQL and LIKE on MySQL. Loading Loading @@ -78,7 +82,7 @@ def select_for_project_authorization if current_scope.joins_values.include?(:shared_projects) if current_scope.joins_values.include?(:shared_projects) joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id') joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id') .where('project_namespace.share_with_group_lock = ?', false) .where('project_namespace.share_with_group_lock = ?', false) .select("members.user_id, projects.id AS project_id, LEAST(project_group_links.group_access, members.access_level) AS access_level") .select("projects.id AS project_id, LEAST(project_group_links.group_access, members.access_level) AS access_level") else else super super end end Loading
app/models/namespace.rb +9 −15 Original line number Original line Diff line number Diff line Loading @@ -176,26 +176,20 @@ def shared_runners_enabled? projects.with_shared_runners.any? projects.with_shared_runners.any? end end # Scopes the model on ancestors of the record # Returns all the ancestors of the current namespaces. def ancestors def ancestors if parent_id return self.class.none unless parent_id path = route ? route.path : full_path paths = [] until path.blank? Gitlab::GroupHierarchy. path = path.rpartition('/').first new(self.class.where(id: parent_id)). paths << path base_and_ancestors end end self.class.joins(:route).where('routes.path IN (?)', paths).reorder('routes.path ASC') # Returns all the descendants of the current namespace. else self.class.none end end # Scopes the model on direct and indirect children of the record def descendants def descendants self.class.joins(:route).merge(Route.inside_path(route.path)).reorder('routes.path ASC') Gitlab::GroupHierarchy. new(self.class.where(parent_id: id)). base_and_descendants end end def user_ids_for_project_authorizations def user_ids_for_project_authorizations Loading