BigW Consortium Gitlab

issuable_finder.rb 7.03 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
    if project?
      @project = Project.find(params[:project_id])
66

67 68
      unless Ability.abilities.allowed?(current_user, :read_project, @project)
        @project = nil
69
      end
70 71 72 73 74 75 76 77 78 79
    else
      @project = nil
    end

    @project
  end

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

80
    if project?
81
      @projects = project
82
    elsif current_user && params[:authorized_only].presence && !current_user_related?
83
      @projects = current_user.authorized_projects.reorder(nil)
84 85
    elsif group
      @projects = GroupProjectsFinder.new(group).execute(current_user).reorder(nil)
86
    else
87
      @projects = ProjectsFinder.new.execute(current_user).reorder(nil)
88
    end
89 90 91 92 93 94 95 96 97 98
  end

  def search
    params[:search].presence
  end

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

Douwe Maan committed
99
  def filter_by_no_milestone?
100 101 102
    milestones? && params[:milestone_title] == Milestone::None.title
  end

103 104 105 106
  def milestones
    return @milestones if defined?(@milestones)

    @milestones =
107
      if milestones?
108
        scope = Milestone.where(project_id: projects)
109 110

        scope.where(title: params[:milestone_title])
111 112 113 114 115
      else
        nil
      end
  end

116 117 118 119
  def labels?
    params[:label_name].present?
  end

Douwe Maan committed
120
  def filter_by_no_label?
121
    labels? && params[:label_name].include?(Label::None.title)
122 123
  end

Tap committed
124 125 126 127 128 129 130
  def labels
    return @labels if defined?(@labels)

    if labels? && !filter_by_no_label?
      @labels = Label.where(title: label_names)

      if projects
Tap committed
131
        @labels = @labels.where(project: projects)
Tap committed
132 133 134 135 136 137
      end
    else
      @labels = Label.none
    end
  end

138 139 140 141 142 143 144
  def assignee?
    params[:assignee_id].present?
  end

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

145
    @assignee =
146 147 148 149 150 151 152 153 154 155 156 157 158 159
      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)

160
    @author =
161 162 163 164 165 166 167
      if author? && params[:author_id] != NONE
        User.find(params[:author_id])
      else
        nil
      end
  end

168 169
  private

170
  def init_collection
171
    klass.all
172 173 174
  end

  def by_scope(items)
Douwe Maan committed
175 176
    case params[:scope]
    when 'created-by-me', 'authored'
177
      items.where(author_id: current_user.id)
Douwe Maan committed
178
    when 'assigned-to-me'
179
      items.where(assignee_id: current_user.id)
180
    else
Douwe Maan committed
181
      items
182 183 184 185 186 187 188
    end
  end

  def by_state(items)
    case params[:state]
    when 'closed'
      items.closed
189 190
    when 'merged'
      items.respond_to?(:merged) ? items.merged : items.closed
191 192 193 194 195 196 197 198 199 200
    when 'all'
      items
    when 'opened'
      items.opened
    else
      raise 'You must specify default state'
    end
  end

  def by_group(items)
201
    # Selection by group is already covered by `by_project` and `projects`
202 203 204 205
    items
  end

  def by_project(items)
206
    items =
207 208 209 210
      if project?
        items.of_projects(projects).references_project
      elsif projects
        items.merge(projects.reorder(nil)).join_project
211 212 213
      else
        items.none
      end
214 215 216 217 218

    items
  end

  def by_search(items)
219
    items = items.search(search) if search
220 221 222 223 224

    items
  end

  def sort(items)
225 226
    # Ensure we always have an explicit sort order (instead of inheriting
    # multiple orders when combining ActiveRecord::Relation objects).
227
    params[:sort] ? items.sort(params[:sort], excluded_labels: label_names) : items.reorder(id: :desc)
228 229 230
  end

  def by_assignee(items)
231 232
    if assignee?
      items = items.where(assignee_id: assignee.try(:id))
233 234 235 236 237
    end

    items
  end

238
  def by_author(items)
239 240
    if author?
      items = items.where(author_id: author.try(:id))
241 242 243 244 245
    end

    items
  end

tiagonbotelho committed
246
  def filter_by_upcoming_milestone?
247
    params[:milestone_title] == Milestone::Upcoming.name
248 249
  end

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

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

    items
  end

269
  def by_label(items)
270
    if labels?
Douwe Maan committed
271
      if filter_by_no_label?
272
        items = items.without_label
273
      else
274
        items = items.with_label(label_names, params[:sort])
275 276
        if projects
          items = items.where(labels: { project_id: projects })
277
        end
278
      end
279 280
    end

281
    items
282
  end
283

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

297 298
    items
  end
299

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
  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
320
  def label_names
Thijs Wouters committed
321 322 323 324 325
    if labels?
      params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
    else
      []
    end
Tap committed
326 327
  end

328 329 330
  def current_user_related?
    params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
  end
331
end