BigW Consortium Gitlab

issuable_finder.rb 7.14 KB
Newer Older
1
# IssuableFinder
2 3 4 5 6 7 8 9 10 11 12
#
# Used to filter Issues and MergeRequests collections by set of params
#
# Arguments:
#   klass - actual class like Issue or MergeRequest
#   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
13
#     milestone_title: string
14 15 16 17 18
#     assignee_id: integer
#     search: string
#     label_name: string
#     sort: string
#
19 20 21
require_relative 'projects_finder'

class IssuableFinder
22
  NONE = '0'
23

24
  attr_accessor :current_user, :params
25

26
  def initialize(current_user, params)
27 28
    @current_user = current_user
    @params = params
29
  end
30

31
  def execute
32 33
    items = init_collection
    items = by_scope(items)
34 35
    items = by_state(items)
    items = by_group(items)
36
    items = by_project(items)
37 38 39
    items = by_search(items)
    items = by_milestone(items)
    items = by_assignee(items)
40
    items = by_author(items)
41
    items = by_label(items)
42
    items = by_due_date(items)
43
    sort(items)
44 45
  end

46 47 48
  def group
    return @group if defined?(@group)

49
    @group =
50 51
      if params[:group_id].present?
        Group.find(params[:group_id])
52
      else
53 54 55 56
        nil
      end
  end

57 58 59 60
  def project?
    params[:project_id].present?
  end

61 62 63
  def project
    return @project if defined?(@project)

64 65
    project = Project.find(params[:project_id])
    project = nil unless Ability.allowed?(current_user, :"read_#{klass.to_ability_name}", project)
66

67
    @project = project
68 69 70 71
  end

  def projects
    return @projects if defined?(@projects)
72 73 74 75 76 77 78 79 80 81
    return @projects = project if project?

    projects =
      if current_user && params[:authorized_only].presence && !current_user_related?
        current_user.authorized_projects
      elsif group
        GroupProjectsFinder.new(group).execute(current_user)
      else
        ProjectsFinder.new.execute(current_user)
      end
82

83
    @projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil)
84 85 86 87 88 89 90 91 92 93
  end

  def search
    params[:search].presence
  end

  def milestones?
    params[:milestone_title].present?
  end

Douwe Maan committed
94
  def filter_by_no_milestone?
95 96 97
    milestones? && params[:milestone_title] == Milestone::None.title
  end

98 99 100 101
  def milestones
    return @milestones if defined?(@milestones)

    @milestones =
102
      if milestones?
103
        scope = Milestone.where(project_id: projects)
104 105

        scope.where(title: params[:milestone_title])
106
      else
107
        Milestone.none
108 109 110
      end
  end

111 112 113 114
  def labels?
    params[:label_name].present?
  end

Douwe Maan committed
115
  def filter_by_no_label?
116
    labels? && params[:label_name].include?(Label::None.title)
117 118
  end

Tap committed
119 120 121
  def labels
    return @labels if defined?(@labels)

122 123
    @labels =
      if labels? && !filter_by_no_label?
124
        LabelsFinder.new(current_user, project_ids: projects, title: label_names).execute(skip_authorization: true)
125 126
      else
        Label.none
Tap committed
127 128 129
      end
  end

130 131 132 133 134 135 136
  def assignee?
    params[:assignee_id].present?
  end

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

137
    @assignee =
138 139 140 141 142 143 144 145 146 147 148 149 150 151
      if assignee? && params[:assignee_id] != NONE
        User.find(params[:assignee_id])
      else
        nil
      end
  end

  def author?
    params[:author_id].present?
  end

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

152
    @author =
153 154 155 156 157 158 159
      if author? && params[:author_id] != NONE
        User.find(params[:author_id])
      else
        nil
      end
  end

160 161
  private

162
  def init_collection
163
    klass.all
164 165 166
  end

  def by_scope(items)
Douwe Maan committed
167 168
    case params[:scope]
    when 'created-by-me', 'authored'
169
      items.where(author_id: current_user.id)
Douwe Maan committed
170
    when 'assigned-to-me'
171
      items.where(assignee_id: current_user.id)
172
    else
Douwe Maan committed
173
      items
174 175 176 177
    end
  end

  def by_state(items)
178 179 180 181
    params[:state] ||= 'all'

    if items.respond_to?(params[:state])
      items.public_send(params[:state])
182
    else
183
      items
184 185 186 187
    end
  end

  def by_group(items)
188
    # Selection by group is already covered by `by_project` and `projects`
189 190 191 192
    items
  end

  def by_project(items)
193
    items =
194 195 196 197
      if project?
        items.of_projects(projects).references_project
      elsif projects
        items.merge(projects.reorder(nil)).join_project
198 199 200
      else
        items.none
      end
201 202 203 204 205

    items
  end

  def by_search(items)
barthc committed
206 207 208 209 210 211 212 213
    if search
      items =
        if search =~ iid_pattern
          items.where(iid: $~[:iid])
        else
          items.full_search(search)
        end
    end
214 215 216 217 218

    items
  end

  def sort(items)
219 220
    # Ensure we always have an explicit sort order (instead of inheriting
    # multiple orders when combining ActiveRecord::Relation objects).
221
    params[:sort] ? items.sort(params[:sort], excluded_labels: label_names) : items.reorder(id: :desc)
222 223 224
  end

  def by_assignee(items)
225 226
    if assignee?
      items = items.where(assignee_id: assignee.try(:id))
227 228 229 230 231
    end

    items
  end

232
  def by_author(items)
233 234
    if author?
      items = items.where(author_id: author.try(:id))
235 236 237 238 239
    end

    items
  end

tiagonbotelho committed
240
  def filter_by_upcoming_milestone?
241
    params[:milestone_title] == Milestone::Upcoming.name
242 243
  end

244 245
  def by_milestone(items)
    if milestones?
Douwe Maan committed
246
      if filter_by_no_milestone?
247
        items = items.left_joins_milestones.where(milestone_id: [-1, nil])
tiagonbotelho committed
248
      elsif filter_by_upcoming_milestone?
249
        upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
250
        items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
251
      else
252
        items = items.with_milestone(params[:milestone_title])
253 254 255 256 257 258 259 260 261 262

        if projects
          items = items.where(milestones: { project_id: projects })
        end
      end
    end

    items
  end

263
  def by_label(items)
264
    if labels?
Douwe Maan committed
265
      if filter_by_no_label?
266
        items = items.without_label
267
      else
268
        items = items.with_label(label_names, params[:sort])
269

270
        if projects
271
          label_ids = LabelsFinder.new(current_user, project_ids: projects).execute(skip_authorization: true).select(:id)
272
          items = items.where(labels: { id: label_ids })
273
        end
274
      end
275 276
    end

277
    items
278
  end
279

280 281 282
  def by_due_date(items)
    if due_date?
      if filter_by_no_due_date?
283 284
        items = items.without_due_date
      elsif filter_by_overdue?
Rémy Coutable committed
285
        items = items.due_before(Date.today)
286
      elsif filter_by_due_this_week?
Rémy Coutable committed
287
        items = items.due_between(Date.today.beginning_of_week, Date.today.end_of_week)
288
      elsif filter_by_due_this_month?
Rémy Coutable committed
289
        items = items.due_between(Date.today.beginning_of_month, Date.today.end_of_month)
290 291
      end
    end
Rémy Coutable committed
292

293 294
    items
  end
295

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
  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 due_date?
    params[:due_date].present? && klass.column_names.include?('due_date')
  end

Tap committed
316
  def label_names
Thijs Wouters committed
317 318 319 320 321
    if labels?
      params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
    else
      []
    end
Tap committed
322 323
  end

324 325 326
  def current_user_related?
    params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
  end
327
end