summaryrefslogtreecommitdiff
path: root/app/finders/issuable_finder.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/finders/issuable_finder.rb')
-rw-r--r--app/finders/issuable_finder.rb381
1 files changed, 62 insertions, 319 deletions
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 6d5b1ca3bc5..5687b375cf0 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -38,19 +38,14 @@ class IssuableFinder
include CreatedAtFilter
include Gitlab::Utils::StrongMemoize
- requires_cross_project_access unless: -> { project? }
-
- # This is used as a common filter for None / Any
- FILTER_NONE = 'none'
- FILTER_ANY = 'any'
-
- # This is used in unassigning users
- NONE = '0'
+ requires_cross_project_access unless: -> { params.project? }
NEGATABLE_PARAMS_HELPER_KEYS = %i[include_subgroups in].freeze
attr_accessor :current_user, :params
+ delegate(*%i[assignee milestones], to: :params)
+
class << self
def scalar_params
@scalar_params ||= %i[
@@ -91,9 +86,13 @@ class IssuableFinder
end
end
+ def params_class
+ IssuableFinder::Params
+ end
+
def initialize(current_user, params = {})
@current_user = current_user
- @params = params
+ @params = params_class.new(params, current_user, klass)
end
def execute
@@ -161,7 +160,7 @@ class IssuableFinder
# of a CTE. The CTE will not be used if the sort doesn't support it,
# but will always be used for the counts here as we ignore sorting
# anyway.
- labels_count = label_names.any? ? label_names.count : 1
+ labels_count = params.label_names.any? ? params.label_names.count : 1
labels_count = 1 if use_cte_for_search?
finder.execute.reorder(nil).group(:state_id).count.each do |key, value|
@@ -174,192 +173,10 @@ class IssuableFinder
end
# rubocop: enable CodeReuse/ActiveRecord
- def group
- return @group if defined?(@group)
-
- @group =
- if params[:group_id].present?
- Group.find(params[:group_id])
- else
- nil
- end
- end
-
- def related_groups
- if project? && project && project.group && Ability.allowed?(current_user, :read_group, project.group)
- project.group.self_and_ancestors
- elsif group
- [group]
- elsif current_user
- Gitlab::ObjectHierarchy.new(current_user.authorized_groups, current_user.groups).all_objects
- else
- []
- end
- end
-
- def project?
- params[:project_id].present?
- end
-
- def project
- return @project if defined?(@project)
-
- project = Project.find(params[:project_id])
- project = nil unless Ability.allowed?(current_user, :"read_#{klass.to_ability_name}", project)
-
- @project = project
- end
-
- def projects
- return @projects if defined?(@projects)
-
- return @projects = [project] if project?
-
- projects =
- if current_user && params[:authorized_only].presence && !current_user_related?
- current_user.authorized_projects(min_access_level)
- else
- projects_public_or_visible_to_user
- end
-
- @projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil) # rubocop: disable CodeReuse/ActiveRecord
- end
-
- def projects_public_or_visible_to_user
- projects =
- if group
- if params[:projects]
- find_group_projects.id_in(params[:projects])
- else
- find_group_projects
- end
- elsif params[:projects]
- Project.id_in(params[:projects])
- else
- Project
- end
-
- projects.public_or_visible_to_user(current_user, min_access_level)
- end
-
- def find_group_projects
- return Project.none unless group
-
- if params[:include_subgroups]
- Project.where(namespace_id: group.self_and_descendants) # rubocop: disable CodeReuse/ActiveRecord
- else
- group.projects
- end
- end
-
def search
params[:search].presence
end
- def milestones?
- params[:milestone_title].present?
- end
-
- def milestones
- return @milestones if defined?(@milestones)
-
- @milestones =
- if milestones?
- if project?
- group_id = project.group&.id
- project_id = project.id
- end
-
- group_id = group.id if group
-
- search_params =
- { title: params[:milestone_title], project_ids: project_id, group_ids: group_id }
-
- MilestonesFinder.new(search_params).execute # rubocop: disable CodeReuse/Finder
- else
- Milestone.none
- end
- end
-
- def labels?
- params[:label_name].present?
- end
-
- def filter_by_no_label?
- downcased = label_names.map(&:downcase)
-
- downcased.include?(FILTER_NONE)
- end
-
- def filter_by_any_label?
- label_names.map(&:downcase).include?(FILTER_ANY)
- end
-
- def labels
- return @labels if defined?(@labels)
-
- @labels =
- if labels? && !filter_by_no_label?
- LabelsFinder.new(current_user, project_ids: projects, title: label_names).execute(skip_authorization: true) # rubocop: disable CodeReuse/Finder
- else
- Label.none
- end
- end
-
- def assignee_id?
- params[:assignee_id].present?
- end
-
- def assignee_username?
- params[:assignee_username].present?
- end
-
- def assignee
- assignees.first
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def assignees
- strong_memoize(:assignees) do
- if assignee_id?
- User.where(id: params[:assignee_id])
- elsif assignee_username?
- User.where(username: params[:assignee_username])
- else
- User.none
- end
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def author_id?
- params[:author_id].present? && params[:author_id] != NONE
- end
-
- def author_username?
- params[:author_username].present? && params[:author_username] != NONE
- end
-
- def no_author?
- # author_id takes precedence over author_username
- params[:author_id] == NONE || params[:author_username] == NONE
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def author
- return @author if defined?(@author)
-
- @author =
- if author_id?
- User.find_by(id: params[:author_id])
- elsif author_username?
- User.find_by_username(params[:author_username])
- else
- nil
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
def use_cte_for_search?
strong_memoize(:use_cte_for_search) do
next false unless search
@@ -370,10 +187,6 @@ class IssuableFinder
end
end
- def releases?
- params[:release_tag].present?
- end
-
private
def force_cte?
@@ -431,7 +244,7 @@ class IssuableFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_scope(items)
- return items.none if current_user_related? && !current_user
+ return items.none if params.current_user_related? && !current_user
case params[:scope]
when 'created_by_me', 'authored'
@@ -480,16 +293,13 @@ class IssuableFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_project(items)
- items =
- if project?
- items.of_projects(projects).references_project
- elsif projects
- items.merge(projects.reorder(nil)).join_project
- else
- items.none
- end
-
- items
+ if params.project?
+ items.of_projects(params.projects).references_project
+ elsif params.projects
+ items.merge(params.projects.reorder(nil)).join_project
+ else
+ items.none
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -519,42 +329,34 @@ class IssuableFinder
def sort(items)
# Ensure we always have an explicit sort order (instead of inheriting
# multiple orders when combining ActiveRecord::Relation objects).
- params[:sort] ? items.sort_by_attribute(params[:sort], excluded_labels: label_names) : items.reorder(id: :desc)
+ params[:sort] ? items.sort_by_attribute(params[:sort], excluded_labels: params.label_names) : items.reorder(id: :desc)
end
# rubocop: enable CodeReuse/ActiveRecord
- def filter_by_no_assignee?
- params[:assignee_id].to_s.downcase == FILTER_NONE
- end
-
- def filter_by_any_assignee?
- params[:assignee_id].to_s.downcase == FILTER_ANY
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def by_author(items)
- if author
- items = items.where(author_id: author.id)
- elsif no_author?
- items = items.where(author_id: nil)
- elsif author_id? || author_username? # author not found
- items = items.none
+ if params.author
+ items.where(author_id: params.author.id)
+ elsif params.no_author?
+ items.where(author_id: nil)
+ elsif params.author_id? || params.author_username? # author not found
+ items.none
+ else
+ items
end
-
- items
end
# rubocop: enable CodeReuse/ActiveRecord
def by_assignee(items)
- return items.assigned_to(assignees) if not_query? && assignees.any?
+ return items.assigned_to(params.assignees) if not_query? && params.assignees.any?
- if filter_by_no_assignee?
+ if params.filter_by_no_assignee?
items.unassigned
- elsif filter_by_any_assignee?
+ elsif params.filter_by_any_assignee?
items.assigned
- elsif assignee
- items.assigned_to(assignee)
- elsif assignee_id? || assignee_username? # assignee not found
+ elsif params.assignee
+ items.assigned_to(params.assignee)
+ elsif params.assignee_id? || params.assignee_username? # assignee not found
items.none
else
items
@@ -563,106 +365,56 @@ class IssuableFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_milestone(items)
- if milestones?
- if filter_by_no_milestone?
- items = items.left_joins_milestones.where(milestone_id: [-1, nil])
- elsif filter_by_any_milestone?
- items = items.any_milestone
- elsif filter_by_upcoming_milestone?
- upcoming_ids = Milestone.upcoming_ids(projects, related_groups)
- items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
- elsif filter_by_started_milestone?
- items = items.left_joins_milestones.merge(Milestone.started)
- else
- items = items.with_milestone(params[:milestone_title])
- end
+ return items unless params.milestones?
+
+ if params.filter_by_no_milestone?
+ items.left_joins_milestones.where(milestone_id: [-1, nil])
+ elsif params.filter_by_any_milestone?
+ items.any_milestone
+ elsif params.filter_by_upcoming_milestone?
+ upcoming_ids = Milestone.upcoming_ids(params.projects, params.related_groups)
+ items.left_joins_milestones.where(milestone_id: upcoming_ids)
+ elsif params.filter_by_started_milestone?
+ items.left_joins_milestones.merge(Milestone.started)
+ else
+ items.with_milestone(params[:milestone_title])
end
-
- items
end
# rubocop: enable CodeReuse/ActiveRecord
def by_release(items)
- return items unless releases?
+ return items unless params.releases?
- if filter_by_no_release?
+ if params.filter_by_no_release?
items.without_release
- elsif filter_by_any_release?
+ elsif params.filter_by_any_release?
items.any_release
else
items.with_release(params[:release_tag], params[:project_id])
end
end
- def filter_by_no_milestone?
- # Accepts `No Milestone` for compatibility
- params[:milestone_title].to_s.downcase == FILTER_NONE || params[:milestone_title] == Milestone::None.title
- end
-
- def filter_by_any_milestone?
- # Accepts `Any Milestone` for compatibility
- params[:milestone_title].to_s.downcase == FILTER_ANY || params[:milestone_title] == Milestone::Any.title
- end
-
- def filter_by_upcoming_milestone?
- params[:milestone_title] == Milestone::Upcoming.name
- end
-
- def filter_by_started_milestone?
- params[:milestone_title] == Milestone::Started.name
- end
-
- def filter_by_no_release?
- params[:release_tag].to_s.downcase == FILTER_NONE
- end
-
- def filter_by_any_release?
- params[:release_tag].to_s.downcase == FILTER_ANY
- end
-
def by_label(items)
- return items unless labels?
-
- items =
- if filter_by_no_label?
- items.without_label
- elsif filter_by_any_label?
- items.any_label
- else
- items.with_label(label_names, params[:sort], not_query: not_query?)
- end
+ return items unless params.labels?
- items
- end
-
- def by_my_reaction_emoji(items)
- if params[:my_reaction_emoji].present? && current_user
- items =
- if filter_by_no_reaction?
- items.not_awarded(current_user)
- elsif filter_by_any_reaction?
- items.awarded(current_user)
- else
- items.awarded(current_user, params[:my_reaction_emoji])
- end
+ if params.filter_by_no_label?
+ items.without_label
+ elsif params.filter_by_any_label?
+ items.any_label
+ else
+ items.with_label(params.label_names, params[:sort], not_query: not_query?)
end
-
- items
- end
-
- def filter_by_no_reaction?
- params[:my_reaction_emoji].to_s.downcase == FILTER_NONE
end
- def filter_by_any_reaction?
- params[:my_reaction_emoji].to_s.downcase == FILTER_ANY
- end
+ def by_my_reaction_emoji(items)
+ return items unless params[:my_reaction_emoji] && current_user
- def label_names
- if labels?
- params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
+ if params.filter_by_no_reaction?
+ items.not_awarded(current_user)
+ elsif params.filter_by_any_reaction?
+ items.awarded(current_user)
else
- []
+ items.awarded(current_user, params[:my_reaction_emoji])
end
end
@@ -670,15 +422,6 @@ class IssuableFinder
params[:non_archived].present? ? items.non_archived : items
end
- def current_user_related?
- scope = params[:scope]
- scope == 'created_by_me' || scope == 'authored' || scope == 'assigned_to_me'
- end
-
- def min_access_level
- ProjectFeature.required_minimum_access_level(klass)
- end
-
def not_query?
!!params[:not_query]
end