summaryrefslogtreecommitdiff
path: root/app/finders/issues_finder.rb
blob: a0504ca087964baf3f5d28bc4e873b427e115116 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# frozen_string_literal: true

# Finders::Issues class
#
# Used to filter Issues collections by set of params
#
# Arguments:
#   current_user - which user use
#   params:
#     scope: 'created_by_me' or 'assigned_to_me' or 'all'
#     state: 'open' or 'closed' or 'all'
#     group_id: integer
#     project_id: integer
#     milestone_title: string
#     assignee_id: integer
#     search: string
#     in: 'title', 'description', or a string joining them with comma
#     label_name: string
#     sort: string
#     my_reaction_emoji: string
#     public_only: boolean
#     due_date: date or '0', '', 'overdue', 'week', or 'month'
#     created_after: datetime
#     created_before: datetime
#     updated_after: datetime
#     updated_before: datetime
#
class IssuesFinder < IssuableFinder
  CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::REPORTER

  def self.scalar_params
    @scalar_params ||= super + [:due_date]
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def klass
    Issue.includes(:author)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  # rubocop: disable CodeReuse/ActiveRecord
  def with_confidentiality_access_check
    return Issue.all if user_can_see_all_confidential_issues?
    return Issue.where('issues.confidential IS NOT TRUE') if user_cannot_see_confidential_issues?

    Issue.where('
      issues.confidential IS NOT TRUE
      OR (issues.confidential = TRUE
        AND (issues.author_id = :user_id
          OR EXISTS (SELECT TRUE FROM issue_assignees WHERE user_id = :user_id AND issue_id = issues.id)
          OR issues.project_id IN(:project_ids)))',
      user_id: current_user.id,
      project_ids: current_user.authorized_projects(CONFIDENTIAL_ACCESS_LEVEL).select(:id))
  end
  # rubocop: enable CodeReuse/ActiveRecord

  private

  def init_collection
    if public_only?
      Issue.public_only
    else
      with_confidentiality_access_check
    end
  end

  def public_only?
    params.fetch(:public_only, false)
  end

  def filter_items(items)
    by_due_date(super)
  end

  def by_due_date(items)
    if due_date?
      if filter_by_no_due_date?
        items = items.without_due_date
      elsif filter_by_overdue?
        items = items.due_before(Date.today)
      elsif filter_by_due_this_week?
        items = items.due_between(Date.today.beginning_of_week, Date.today.end_of_week)
      elsif filter_by_due_this_month?
        items = items.due_between(Date.today.beginning_of_month, Date.today.end_of_month)
      elsif filter_by_due_next_month_and_previous_two_weeks?
        items = items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month)
      end
    end

    items
  end

  def filter_by_no_due_date?
    due_date? && params[:due_date] == Issue::NoDueDate.name
  end

  def filter_by_overdue?
    due_date? && params[:due_date] == Issue::Overdue.name
  end

  def filter_by_due_this_week?
    due_date? && params[:due_date] == Issue::DueThisWeek.name
  end

  def filter_by_due_this_month?
    due_date? && params[:due_date] == Issue::DueThisMonth.name
  end

  def filter_by_due_next_month_and_previous_two_weeks?
    due_date? && params[:due_date] == Issue::DueNextMonthAndPreviousTwoWeeks.name
  end

  def due_date?
    params[:due_date].present?
  end

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

    return @user_can_see_all_confidential_issues = false if current_user.blank?
    return @user_can_see_all_confidential_issues = true if current_user.full_private_access?

    @user_can_see_all_confidential_issues =
      if project? && project
        project.team.max_member_access(current_user.id) >= CONFIDENTIAL_ACCESS_LEVEL
      elsif group
        group.max_member_access_for_user(current_user) >= CONFIDENTIAL_ACCESS_LEVEL
      else
        false
      end
  end

  def user_cannot_see_confidential_issues?
    return false if user_can_see_all_confidential_issues?

    current_user.blank?
  end

  def by_assignee(items)
    if filter_by_no_assignee?
      items.unassigned
    elsif filter_by_any_assignee?
      items.assigned
    elsif assignee
      items.assigned_to(assignee)
    elsif assignee_id? || assignee_username? # assignee not found
      items.none
    else
      items
    end
  end
end