38b8ae641f
This refactors the TodoService class according to our code reuse guidelines. The resulting code is a wee bit more verbose, but it allows us to decouple the column names from the input, resulting in fewer changes being necessary when we change the schema. One particular noteworthy line in TodoService is the following: todos_ids = todos.update_state(state) Technically this is a violation of the guidelines, because `update_state` is a class method, which services are not supposed to use (safe for a few allowed ones). I decided to keep this, since there is no alternative. `update_state` doesn't produce a relation so it doesn't belong in a Finder, and we can't move it to another Service either. As such I opted to just use the method directly. Cases like this may happen more frequently, at which point we should update our documentation with some sort of recommendation. For now, I want to refrain from doing so until we have a few more examples.
182 lines
3.1 KiB
Ruby
182 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# TodosFinder
|
|
#
|
|
# Used to filter Todos by set of params
|
|
#
|
|
# Arguments:
|
|
# current_user - which user use
|
|
# params:
|
|
# action_id: integer
|
|
# author_id: integer
|
|
# project_id; integer
|
|
# state: 'pending' (default) or 'done'
|
|
# type: 'Issue' or 'MergeRequest'
|
|
#
|
|
|
|
class TodosFinder
|
|
prepend FinderWithCrossProjectAccess
|
|
include FinderMethods
|
|
include Gitlab::Utils::StrongMemoize
|
|
|
|
requires_cross_project_access unless: -> { project? }
|
|
|
|
NONE = '0'.freeze
|
|
|
|
TODO_TYPES = Set.new(%w(Issue MergeRequest Epic)).freeze
|
|
|
|
attr_accessor :current_user, :params
|
|
|
|
def initialize(current_user, params = {})
|
|
@current_user = current_user
|
|
@params = params
|
|
end
|
|
|
|
def execute
|
|
items = current_user.todos
|
|
items = by_action_id(items)
|
|
items = by_action(items)
|
|
items = by_author(items)
|
|
items = by_state(items)
|
|
items = by_type(items)
|
|
items = by_group(items)
|
|
# Filtering by project HAS TO be the last because we use
|
|
# the project IDs yielded by the todos query thus far
|
|
items = by_project(items)
|
|
|
|
sort(items)
|
|
end
|
|
|
|
# Returns `true` if the current user has any todos for the given target.
|
|
#
|
|
# target - The value of the `target_type` column, such as `Issue`.
|
|
def any_for_target?(target)
|
|
current_user.todos.any_for_target?(target)
|
|
end
|
|
|
|
private
|
|
|
|
def action_id?
|
|
action_id.present? && Todo::ACTION_NAMES.key?(action_id.to_i)
|
|
end
|
|
|
|
def action_id
|
|
params[:action_id]
|
|
end
|
|
|
|
def to_action_id
|
|
Todo::ACTION_NAMES.key(action.to_sym)
|
|
end
|
|
|
|
def action?
|
|
action.present? && to_action_id
|
|
end
|
|
|
|
def action
|
|
params[:action]
|
|
end
|
|
|
|
def author?
|
|
params[:author_id].present?
|
|
end
|
|
|
|
def author
|
|
strong_memoize(:author) do
|
|
if author? && params[:author_id] != NONE
|
|
User.find(params[:author_id])
|
|
end
|
|
end
|
|
end
|
|
|
|
def project?
|
|
params[:project_id].present?
|
|
end
|
|
|
|
def group?
|
|
params[:group_id].present?
|
|
end
|
|
|
|
def project
|
|
strong_memoize(:project) do
|
|
Project.find_without_deleted(params[:project_id]) if project?
|
|
end
|
|
end
|
|
|
|
def group
|
|
strong_memoize(:group) do
|
|
Group.find(params[:group_id])
|
|
end
|
|
end
|
|
|
|
def type?
|
|
type.present? && TODO_TYPES.include?(type)
|
|
end
|
|
|
|
def type
|
|
params[:type]
|
|
end
|
|
|
|
def sort(items)
|
|
if params[:sort]
|
|
items.sort_by_attribute(params[:sort])
|
|
else
|
|
items.order_id_desc
|
|
end
|
|
end
|
|
|
|
def by_action(items)
|
|
if action?
|
|
items.for_action(to_action_id)
|
|
else
|
|
items
|
|
end
|
|
end
|
|
|
|
def by_action_id(items)
|
|
if action_id?
|
|
items.for_action(action_id)
|
|
else
|
|
items
|
|
end
|
|
end
|
|
|
|
def by_author(items)
|
|
if author?
|
|
items.for_author(author)
|
|
else
|
|
items
|
|
end
|
|
end
|
|
|
|
def by_project(items)
|
|
if project?
|
|
items.for_project(project)
|
|
else
|
|
items
|
|
end
|
|
end
|
|
|
|
def by_group(items)
|
|
if group?
|
|
items.for_group_and_descendants(group)
|
|
else
|
|
items
|
|
end
|
|
end
|
|
|
|
def by_state(items)
|
|
if params[:state].to_s == 'done'
|
|
items.done
|
|
else
|
|
items.pending
|
|
end
|
|
end
|
|
|
|
def by_type(items)
|
|
if type?
|
|
items.for_type(type)
|
|
else
|
|
items
|
|
end
|
|
end
|
|
end
|