summaryrefslogtreecommitdiff
path: root/app/finders/labels_finder.rb
blob: 5c9fce211ecb4cba776919d8b50121466fe3d198 (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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
class LabelsFinder < UnionFinder
  prepend FinderWithCrossProjectAccess
  include FinderMethods
  include Gitlab::Utils::StrongMemoize

  requires_cross_project_access unless: -> { project? }

  def initialize(current_user, params = {})
    @current_user = current_user
    @params = params
  end

  def execute(skip_authorization: false)
    @skip_authorization = skip_authorization
    items = find_union(label_ids, Label) || Label.none
    items = with_title(items)
    sort(items)
  end

  private

  attr_reader :current_user, :params, :skip_authorization

  def label_ids
    label_ids = []

    if project?
      if project
        if project.group.present?
          labels_table = Label.arel_table

          label_ids << Label.where(
            labels_table[:type].eq('GroupLabel').and(labels_table[:group_id].eq(project.group.id)).or(
              labels_table[:type].eq('ProjectLabel').and(labels_table[:project_id].eq(project.id))
            )
          )
        else
          label_ids << project.labels
        end
      end
    elsif only_group_labels?
      label_ids << Label.where(group_id: group_ids)
    else
      label_ids << Label.where(group_id: projects.group_ids)
      label_ids << Label.where(project_id: projects.select(:id))
    end

    label_ids
  end

  def sort(items)
    items.reorder(title: :asc)
  end

  def with_title(items)
    return items if title.nil?
    return items.none if title.blank?

    items.where(title: title)
  end

  def group_ids
    strong_memoize(:group_ids) do
      group = Group.find(params[:group_id])
      groups = params[:include_ancestor_groups].present? ? group.self_and_ancestors : [group]
      groups_user_can_read_labels(groups).map(&:id)
    end
  end

  def group?
    params[:group_id].present?
  end

  def project?
    params[:project_id].present?
  end

  def projects?
    params[:project_ids]
  end

  def only_group_labels?
    params[:only_group_labels]
  end

  def title
    params[:title] || params[:name]
  end

  def project
    return @project if defined?(@project)

    if project?
      @project = Project.find(params[:project_id])
      @project = nil unless authorized_to_read_labels?(@project)
    else
      @project = nil
    end

    @project
  end

  def projects
    return @projects if defined?(@projects)

    @projects = if skip_authorization
                  Project.all
                else
                  ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute
                end

    @projects = @projects.in_namespace(params[:group_id]) if group?
    @projects = @projects.where(id: params[:project_ids]) if projects?
    @projects = @projects.reorder(nil)

    @projects
  end

  def authorized_to_read_labels?(label_parent)
    return true if skip_authorization

    Ability.allowed?(current_user, :read_label, label_parent)
  end

  def groups_user_can_read_labels(groups)
    DeclarativePolicy.user_scope do
      groups.select { |group| authorized_to_read_labels?(group) }
    end
  end
end