Commit 75eed4eb authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Implement project collection service

Main purpose is move big amount of methods from user, group, project
models and place filtering logic in one place.
It also fixes 500 error on group page for PostgreSQL
Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent 9f20580e
...@@ -99,7 +99,7 @@ class GroupsController < ApplicationController ...@@ -99,7 +99,7 @@ class GroupsController < ApplicationController
end end
def projects def projects
@projects ||= group.projects_accessible_to(current_user).sorted_by_activity @projects ||= Projects::CollectService.new.execute(current_user, group: group)
end end
def project_ids def project_ids
......
...@@ -50,7 +50,7 @@ class Ability ...@@ -50,7 +50,7 @@ class Ability
else else
nil nil
end end
if group && group.has_projects_accessible_to?(nil) if group && group.has_projects_accessible_to?(nil)
[:read_group] [:read_group]
else else
...@@ -184,7 +184,7 @@ class Ability ...@@ -184,7 +184,7 @@ class Ability
def group_abilities user, group def group_abilities user, group
rules = [] rules = []
if user.admin? || group.users.include?(user) || group.has_projects_accessible_to?(user) if user.admin? || Projects::CollectService.new.execute(user, group: group).any?
rules << :read_group rules << :read_group
end end
......
...@@ -116,21 +116,28 @@ class Project < ActiveRecord::Base ...@@ -116,21 +116,28 @@ class Project < ActiveRecord::Base
scope :personal, ->(user) { where(namespace_id: user.namespace_id) } scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
scope :non_archived, -> { where(archived: false) } scope :non_archived, -> { where(archived: false) }
enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
class << self class << self
def public_and_internal_levels
[Project::PUBLIC, Project::INTERNAL]
end
def abandoned def abandoned
where('projects.last_activity_at < ?', 6.months.ago) where('projects.last_activity_at < ?', 6.months.ago)
end end
def publicish(user) def publicish(user)
visibility_levels = [Project::PUBLIC] visibility_levels = [Project::PUBLIC]
visibility_levels += [Project::INTERNAL] if user visibility_levels += [Project::INTERNAL] if user
where(visibility_level: visibility_levels) where(visibility_level: visibility_levels)
end end
def accessible_to(user) def accessible_to(user)
accessible_ids = publicish(user).pluck(:id) accessible_ids = publicish(user).pluck(:id)
accessible_ids += user.authorized_projects.pluck(:id) if user accessible_ids += user.authorized_projects.pluck(:id) if user
......
# Projects::CollectService class
#
# Used to collect projects user has access to
#
module Projects
class CollectService
def execute(current_user, options)
group = options[:group]
if group
group_projects(current_user, group)
else
all_projects(current_user)
end
end
private
def group_projects(current_user, group)
if current_user
if group.users.include?(current_user)
# User is group member
#
# Return ALL group projects
group.projects
else
projects_members = UsersProject.where(
project_id: group.projects,
user_id: current_user
)
if projects_members.any?
# User is a project member
#
# Return only:
# public projects
# internal projects
# joined projects
#
group.projects.where(
"projects.id IN (?) OR projects.visibility_level IN (?)",
projects_members.pluck(:project_id),
Project.public_and_internal_levels
)
else
# User has no access to group or group projects
#
# Return only:
# public projects
# internal projects
#
group.projects.public_and_internal_only
end
end
else
# Not authenticated
#
# Return only:
# public projects
group.projects.public_only
end
end
end
def all_projects
# TODO: implement
raise 'Not implemented yet'
end
end
require 'spec_helper'
describe Projects::CollectService do
let(:user) { create :user }
let(:group) { create :group }
let(:project1) { create(:empty_project, group: group, visibility_level: Project::PUBLIC) }
let(:project2) { create(:empty_project, group: group, visibility_level: Project::INTERNAL) }
let(:project3) { create(:empty_project, group: group, visibility_level: Project::PRIVATE) }
let(:project4) { create(:empty_project, group: group, visibility_level: Project::PRIVATE) }
context 'non authenticated' do
subject { Projects::CollectService.new.execute(nil, group: group) }
it { should include(project1) }
it { should_not include(project2) }
it { should_not include(project3) }
it { should_not include(project4) }
end
context 'authenticated' do
subject { Projects::CollectService.new.execute(user, group: group) }
it { should include(project1) }
it { should include(project2) }
it { should_not include(project3) }
it { should_not include(project4) }
end
context 'authenticated, project member' do
before { project3.team << [user, :developer] }
subject { Projects::CollectService.new.execute(user, group: group) }
it { should include(project1) }
it { should include(project2) }
it { should include(project3) }
it { should_not include(project4) }
end
context 'authenticated, group member' do
before { group.add_user(user, Gitlab::Access::DEVELOPER) }
subject { Projects::CollectService.new.execute(user, group: group) }
it { should include(project1) }
it { should include(project2) }
it { should include(project3) }
it { should include(project4) }
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment