summaryrefslogtreecommitdiff
path: root/app/finders/projects_finder.rb
blob: 4a6c2fbd71c8f9679b933c11557af69946e653a7 (plain)
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
class ProjectsFinder
  # Returns all projects, optionally including group projects a user has access
  # to.
  #
  # ## Examples
  #
  # Retrieving all public projects:
  #
  #     ProjectsFinder.new.execute
  #
  # Retrieving all public/internal projects and those the given user has access
  # to:
  #
  #     ProjectsFinder.new.execute(some_user)
  #
  # Retrieving all public/internal projects as well as the group's projects the
  # user has access to:
  #
  #     ProjectsFinder.new.execute(some_user, group: some_group)
  #
  # Returns an ActiveRecord::Relation.
  def execute(current_user = nil, options = {})
    group = options[:group]

    if group
      segments = group_projects(current_user, group)
    else
      segments = all_projects(current_user)
    end

    if segments.length > 1
      union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })

      Project.where("projects.id IN (#{union.to_sql})")
    else
      segments.first
    end
  end

  private

  def group_projects(current_user, group)
    return [group.projects.public_only] unless current_user

    if current_user.external?
      [
        group_projects_for_user(current_user, group),
        group.projects.public_only
      ]
    else
      [
        group_projects_for_user(current_user, group),
        group.projects.public_and_internal_only
      ]
    end
  end

  def all_projects(current_user)
    return [public_projects] unless current_user

    if current_user.external?
      [current_user.authorized_projects, public_projects]
    else
      [current_user.authorized_projects, public_and_internal_projects]
    end
  end

  def group_projects_for_user(current_user, group)
    if group.users.include?(current_user)
      group.projects
    else
      group.projects.visible_to_user(current_user)
    end
  end

  def public_projects
    Project.unscoped.public_only
  end

  def public_and_internal_projects
    Project.unscoped.public_and_internal_only
  end
end