Commit 98e1a2d5 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch 'refactor_issuable_finder' into 'master'

Add (IssuableFinder|IssuesFinder)::Params class

See merge request gitlab-org/gitlab!27704
parents 713d19c2 e252b6f9
......@@ -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
......
# frozen_string_literal: true
class IssuableFinder
class Params < SimpleDelegator
include Gitlab::Utils::StrongMemoize
# This is used as a common filter for None / Any
FILTER_NONE = 'none'
FILTER_ANY = 'any'
# This is used in unassigning users
NONE = '0'
alias_method :params, :__getobj__
attr_accessor :current_user, :klass
def initialize(params, current_user, klass)
@current_user = current_user
@klass = klass
# We turn the params into a HashWithIndifferentAccess. We must use #to_h first because sometimes
# we get ActionController::Params and IssuableFinder::Params objects here.
super(params.to_h.with_indifferent_access)
end
def present?
params.present?
end
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
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
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?
params[:label_name].present?
end
def milestones?
params[:milestone_title].present?
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 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 releases?
params[:release_tag].present?
end
def project?
params[:project_id].present?
end
def group
strong_memoize(:group) do
if params[:group_id].present?
Group.find(params[:group_id])
else
nil
end
end
end
def related_groups
if 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
strong_memoize(:project) do
project = Project.find(params[:project_id])
project = nil unless Ability.allowed?(current_user, :"read_#{klass.to_ability_name}", project)
project
end
end
def projects
strong_memoize(:projects) do
next [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.with_feature_available_for_user(klass, current_user).reorder(nil) # rubocop: disable CodeReuse/ActiveRecord
end
end
# rubocop: disable CodeReuse/ActiveRecord
def author
strong_memoize(:author) do
if author_id?
User.find_by(id: params[:author_id])
elsif author_username?
User.find_by_username(params[:author_username])
else
nil
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
# 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 assignee
assignees.first
end
def label_names
if labels?
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
else
[]
end
end
def labels
strong_memoize(:labels) do
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
end
def milestones
strong_memoize(:milestones) do
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
end
def current_user_related?
scope = params[:scope]
scope == 'created_by_me' || scope == 'authored' || scope == 'assigned_to_me'
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
# We use Hash#merge in a few places, so let's support it
def merge(other)
self.class.new(params.merge(other), current_user, klass)
end
# Just for symmetry, and in case someone tries to use it
def merge!(other)
params.merge!(other)
end
private
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 min_access_level
ProjectFeature.required_minimum_access_level(klass)
end
def method_missing(method_name, *args, &block)
if method_name[-1] == '?'
params[method_name[0..-2].to_sym].present?
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
method_name[-1] == '?'
end
end
end
......@@ -38,10 +38,14 @@ class IssuesFinder < IssuableFinder
end
# rubocop: enable CodeReuse/ActiveRecord
def params_class
IssuesFinder::Params
end
# 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?
return Issue.all if params.user_can_see_all_confidential_issues?
return Issue.where('issues.confidential IS NOT TRUE') if params.user_cannot_see_confidential_issues?
Issue.where('
issues.confidential IS NOT TRUE
......@@ -57,17 +61,13 @@ class IssuesFinder < IssuableFinder
private
def init_collection
if public_only?
if params.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)
issues = super
issues = by_due_date(issues)
......@@ -82,67 +82,19 @@ class IssuesFinder < IssuableFinder
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
return items unless params.due_date?
if params.filter_by_no_due_date?
items.without_due_date
elsif params.filter_by_overdue?
items.due_before(Date.today)
elsif params.filter_by_due_this_week?
items.due_between(Date.today.beginning_of_week, Date.today.end_of_week)
elsif params.filter_by_due_this_month?
items.due_between(Date.today.beginning_of_month, Date.today.end_of_month)
elsif params.filter_by_due_next_month_and_previous_two_weeks?
items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month)
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.can_read_all_resources?
@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
end
......
# frozen_string_literal: true
class IssuesFinder
class Params < IssuableFinder::Params
def public_only?
params.fetch(:public_only, false)
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 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.can_read_all_resources?
@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
end
end
IssuableFinder::Params.prepend_if_ee('EE::IssuesFinder::Params')
......@@ -21,7 +21,7 @@ module Issuable
params.delete(key) unless params[key].present?
end
if params[:assignee_ids] == [IssuableFinder::NONE.to_s]
if params[:assignee_ids] == [IssuableFinder::Params::NONE.to_s]
params[:assignee_ids] = []
end
......
......@@ -46,7 +46,7 @@ class IssuableBaseService < BaseService
assignee_ids = params[:assignee_ids].select { |assignee_id| assignee_can_read?(issuable, assignee_id) }
if params[:assignee_ids].map(&:to_s) == [IssuableFinder::NONE]
if params[:assignee_ids].map(&:to_s) == [IssuableFinder::Params::NONE]
params[:assignee_ids] = []
elsif assignee_ids.any?
params[:assignee_ids] = assignee_ids
......@@ -70,7 +70,7 @@ class IssuableBaseService < BaseService
milestone_id = params[:milestone_id]
return unless milestone_id
params[:milestone_id] = '' if milestone_id == IssuableFinder::NONE
params[:milestone_id] = '' if milestone_id == IssuableFinder::Params::NONE
groups = project.group&.self_and_ancestors&.select(:id)
milestone =
......
......@@ -25,11 +25,11 @@ module EE
# rubocop: disable CodeReuse/ActiveRecord
def by_weight(items)
return items unless weights?
return items unless params.weights?
if filter_by_no_weight?
if params.filter_by_no_weight?
items.where(weight: [-1, nil])
elsif filter_by_any_weight?
elsif params.filter_by_any_weight?
items.where.not(weight: [-1, nil])
else
items.where(weight: params[:weight])
......@@ -37,26 +37,10 @@ module EE
end
# rubocop: enable CodeReuse/ActiveRecord
def weights?
params[:weight].present? && params[:weight] != ::Issue::WEIGHT_ALL
end
def filter_by_no_weight?
params[:weight].to_s.downcase == ::IssuesFinder::FILTER_NONE
end
def filter_by_any_weight?
params[:weight].to_s.downcase == ::IssuesFinder::FILTER_ANY
end
def assignee_ids?
params[:assignee_ids].present?
end
override :by_assignee
def by_assignee(items)
if assignees.any? && !not_query?
assignees.each do |assignee|
if params.assignees.any? && !not_query?
params.assignees.each do |assignee|
items = items.assigned_to(assignee)
end
......@@ -66,42 +50,13 @@ module EE
super
end
override :assignees
# rubocop: disable CodeReuse/ActiveRecord
def assignees
strong_memoize(:assignees) do
if assignee_ids?
::User.where(id: params[:assignee_ids])
else
super
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
def by_epic?
params[:epic_id].present?
end
def filter_by_no_epic?
params[:epic_id].to_s.downcase == ::IssuesFinder::FILTER_NONE
end
def epics
if params[:include_subepics]
::Gitlab::ObjectHierarchy.new(::Epic.for_ids(params[:epic_id])).base_and_descendants.select(:id)
else
params[:epic_id]
end
end
def by_epic(items)
return items unless by_epic?
return items unless params.by_epic?
if filter_by_no_epic?
if params.filter_by_no_epic?
items.no_epic
else
items.in_epics(epics)
items.in_epics(params.epics)
end
end
end
......
# frozen_string_literal: true
module EE
module IssuesFinder
module Params
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
def by_epic?
params[:epic_id].present?
end
def filter_by_no_epic?
params[:epic_id].to_s.downcase == ::IssuableFinder::Params::FILTER_NONE
end
def weights?
params[:weight].present? && params[:weight] != ::Issue::WEIGHT_ALL
end
def filter_by_no_weight?
params[:weight].to_s.downcase == ::IssuableFinder::Params::FILTER_NONE
end
def filter_by_any_weight?
params[:weight].to_s.downcase == ::IssuableFinder::Params::FILTER_ANY
end
override :assignees
# rubocop: disable CodeReuse/ActiveRecord
def assignees
strong_memoize(:assignees) do
if assignee_ids?
::User.where(id: params[:assignee_ids])
else
super
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
def epics
if params[:include_subepics]
::Gitlab::ObjectHierarchy.new(::Epic.for_ids(params[:epic_id])).base_and_descendants.select(:id)
else
params[:epic_id]
end
end
end
end
end
......@@ -42,14 +42,14 @@ module MergeRequests
#
# @return [Boolean] whether special condition "None" is being used
def by_no_approvals?
includes_special_label?(IssuableFinder::FILTER_NONE)
includes_special_label?(IssuableFinder::Params::FILTER_NONE)
end
# Is param using special condition: "Any" ?
#
# @return [Boolean] whether special condition "Any"" is being used
def by_any_approvals?
includes_special_label?(IssuableFinder::FILTER_ANY)
includes_special_label?(IssuableFinder::Params::FILTER_ANY)
end
# Check if we have the special label in ids or usernames field
......
......@@ -30,11 +30,11 @@ module MergeRequests
private
def by_no_approvers?
includes_custom_label?(IssuableFinder::FILTER_NONE)
includes_custom_label?(IssuableFinder::Params::FILTER_NONE)
end
def by_any_approvers?
includes_custom_label?(IssuableFinder::FILTER_ANY)
includes_custom_label?(IssuableFinder::Params::FILTER_ANY)
end
def includes_custom_label?(label)
......
......@@ -19,7 +19,7 @@ class MergeRequestsComplianceFinder < MergeRequestsFinder
.limit(1)
.to_sql
sql = find_group_projects.arel.as('projects').to_sql
sql = params.find_group_projects.arel.as('projects').to_sql
records = Project
.select('projects.id, events.target_id as merge_request_id')
.from([Arel.sql("#{sql} JOIN LATERAL (#{lateral}) #{Event.table_name} ON true")])
......
......@@ -87,7 +87,7 @@ describe IssuesFinder do
let_it_be(:issue_subepic) { create(:issue, project: project1, epic: sub_epic) }
context 'filter issues with no epic' do
let(:params) { { epic_id: ::IssuesFinder::FILTER_NONE } }
let(:params) { { epic_id: ::IssuableFinder::Params::FILTER_NONE } }
it 'returns filtered issues' do
expect(issues).to contain_exactly(issue1, issue2, issue3, issue4)
......
......@@ -315,25 +315,25 @@ describe API::Epics do
end
it 'returns an array of epics with any label' do
get api(url), params: { labels: IssuesFinder::FILTER_ANY }
get api(url), params: { labels: IssuableFinder::Params::FILTER_ANY }
expect_paginated_array_response(epic2.id)
end
it 'returns an array of epics with any label with labels param as array' do
get api(url), params: { labels: [IssuesFinder::FILTER_ANY] }
get api(url), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
expect_paginated_array_response(epic2.id)
end
it 'returns an array of epics with no label' do
get api(url), params: { labels: IssuesFinder::FILTER_NONE }
get api(url), params: { labels: IssuableFinder::Params::FILTER_NONE }
expect_paginated_array_response(epic.id)
end
it 'returns an array of epics with no label with labels param as array' do
get api(url), params: { labels: [IssuesFinder::FILTER_NONE] }
get api(url), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
expect_paginated_array_response(epic.id)
end
......
......@@ -38,7 +38,7 @@ module API
value = params[attr_name]
return if value.is_a?(Integer) ||
[IssuableFinder::FILTER_NONE, IssuableFinder::FILTER_ANY].include?(value.to_s.downcase)
[IssuableFinder::Params::FILTER_NONE, IssuableFinder::Params::FILTER_ANY].include?(value.to_s.downcase)
raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
message: "should be an integer, 'None' or 'Any'"
......@@ -50,7 +50,7 @@ module API
value = params[attr_name]
return if value.is_a?(Array) ||
[IssuableFinder::FILTER_NONE, IssuableFinder::FILTER_ANY].include?(value.to_s.downcase)
[IssuableFinder::Params::FILTER_NONE, IssuableFinder::Params::FILTER_ANY].include?(value.to_s.downcase)
raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
message: "should be an array, 'None' or 'Any'"
......
......@@ -24,7 +24,7 @@ describe 'User filters issues' do
let(:issue) { @issue }
it 'allows filtering by issues with no specified assignee' do
visit project_issues_path(project, assignee_id: IssuableFinder::FILTER_NONE)
visit project_issues_path(project, assignee_id: IssuableFinder::Params::FILTER_NONE)
expect(page).to have_content 'foobar'
expect(page).not_to have_content 'barbaz'
......
......@@ -35,7 +35,7 @@ describe 'Merge requests > User lists merge requests' do
end
it 'filters on no assignee' do
visit_merge_requests(project, assignee_id: IssuableFinder::FILTER_NONE)
visit_merge_requests(project, assignee_id: IssuableFinder::Params::FILTER_NONE)
expect(current_path).to eq(project_merge_requests_path(project))
expect(page).to have_content 'merge-test'
......
......@@ -429,7 +429,7 @@ describe IssuesFinder do
end
context 'filtering by no label' do
let(:params) { { label_name: described_class::FILTER_NONE } }
let(:params) { { label_name: described_class::Params::FILTER_NONE } }
it 'returns issues with no labels' do
expect(issues).to contain_exactly(issue1, issue4)
......@@ -437,7 +437,7 @@ describe IssuesFinder do
end
context 'filtering by any label' do
let(:params) { { label_name: described_class::FILTER_ANY } }
let(:params) { { label_name: described_class::Params::FILTER_ANY } }
it 'returns issues that have one or more label' do
create_list(:label_link, 2, label: create(:label, project: project2), target: issue3)
......
......@@ -51,11 +51,11 @@ describe Resolvers::IssuesResolver do
end
it 'filters by any assignee' do
expect(resolve_issues(assignee_id: IssuableFinder::FILTER_ANY)).to contain_exactly(issue2)
expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_ANY)).to contain_exactly(issue2)
end
it 'filters by no assignee' do
expect(resolve_issues(assignee_id: IssuableFinder::FILTER_NONE)).to contain_exactly(issue1)
expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_NONE)).to contain_exactly(issue1)
end
it 'filters by labels' do
......
......@@ -475,27 +475,27 @@ describe API::Issues do
end
it 'returns an array of group issues with any label' do
get api(base_url, user), params: { labels: IssuesFinder::FILTER_ANY }
get api(base_url, user), params: { labels: IssuableFinder::Params::FILTER_ANY }
expect_paginated_array_response(group_issue.id)
expect(json_response.first['id']).to eq(group_issue.id)
end
it 'returns an array of group issues with any label with labels param as array' do
get api(base_url, user), params: { labels: [IssuesFinder::FILTER_ANY] }
get api(base_url, user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
expect_paginated_array_response(group_issue.id)
expect(json_response.first['id']).to eq(group_issue.id)
end
it 'returns an array of group issues with no label' do
get api(base_url, user), params: { labels: IssuesFinder::FILTER_NONE }
get api(base_url, user), params: { labels: IssuableFinder::Params::FILTER_NONE }
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
end
it 'returns an array of group issues with no label with labels param as array' do
get api(base_url, user), params: { labels: [IssuesFinder::FILTER_NONE] }
get api(base_url, user), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id])
end
......
......@@ -350,25 +350,25 @@ describe API::Issues do
end
it 'returns an array of project issues with any label' do
get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_ANY }
get api("#{base_url}/issues", user), params: { labels: IssuableFinder::Params::FILTER_ANY }
expect_paginated_array_response(issue.id)
end
it 'returns an array of project issues with any label with labels param as array' do
get api("#{base_url}/issues", user), params: { labels: [IssuesFinder::FILTER_ANY] }
get api("#{base_url}/issues", user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
expect_paginated_array_response(issue.id)
end
it 'returns an array of project issues with no label' do
get api("#{base_url}/issues", user), params: { labels: IssuesFinder::FILTER_NONE }
get api("#{base_url}/issues", user), params: { labels: IssuableFinder::Params::FILTER_NONE }
expect_paginated_array_response([confidential_issue.id, closed_issue.id])
end
it 'returns an array of project issues with no label with labels param as array' do
get api("#{base_url}/issues", user), params: { labels: [IssuesFinder::FILTER_NONE] }
get api("#{base_url}/issues", user), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
expect_paginated_array_response([confidential_issue.id, closed_issue.id])
end
......
......@@ -476,25 +476,25 @@ describe API::Issues do
end
it 'returns an array of issues with any label' do
get api('/issues', user), params: { labels: IssuesFinder::FILTER_ANY }
get api('/issues', user), params: { labels: IssuableFinder::Params::FILTER_ANY }
expect_paginated_array_response(issue.id)
end
it 'returns an array of issues with any label with labels param as array' do
get api('/issues', user), params: { labels: [IssuesFinder::FILTER_ANY] }
get api('/issues', user), params: { labels: [IssuableFinder::Params::FILTER_ANY] }
expect_paginated_array_response(issue.id)
end
it 'returns an array of issues with no label' do
get api('/issues', user), params: { labels: IssuesFinder::FILTER_NONE }
get api('/issues', user), params: { labels: IssuableFinder::Params::FILTER_NONE }
expect_paginated_array_response(closed_issue.id)
end
it 'returns an array of issues with no label with labels param as array' do
get api('/issues', user), params: { labels: [IssuesFinder::FILTER_NONE] }
get api('/issues', user), params: { labels: [IssuableFinder::Params::FILTER_NONE] }
expect_paginated_array_response(closed_issue.id)
end
......
......@@ -281,14 +281,14 @@ describe API::MergeRequests do
end
it 'returns an array of merge requests with any label when filtering by any label' do
get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_ANY }
get api(endpoint_path, user), params: { labels: IssuableFinder::Params::FILTER_ANY }
expect_paginated_array_response([merge_request.id])
expect(json_response.first['id']).to eq(merge_request.id)
end
it 'returns an array of merge requests without a label when filtering by no label' do
get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_NONE }
get api(endpoint_path, user), params: { labels: IssuableFinder::Params::FILTER_NONE }
expect_response_contain_exactly(
merge_request_merged.id, merge_request_locked.id, merge_request_closed.id
......
......@@ -245,9 +245,9 @@ describe Issuable::BulkUpdateService do
end
end
context "when the new assignee ID is #{IssuableFinder::NONE}" do
context "when the new assignee ID is #{IssuableFinder::Params::NONE}" do
it 'unassigns the issues' do
expect { bulk_update(merge_request, assignee_ids: [IssuableFinder::NONE]) }
expect { bulk_update(merge_request, assignee_ids: [IssuableFinder::Params::NONE]) }
.to change { merge_request.reload.assignee_ids }.to([])
end
end
......@@ -282,9 +282,9 @@ describe Issuable::BulkUpdateService do
end
end
context "when the new assignee ID is #{IssuableFinder::NONE}" do
context "when the new assignee ID is #{IssuableFinder::Params::NONE}" do
it "unassigns the issues" do
expect { bulk_update(issue, assignee_ids: [IssuableFinder::NONE.to_s]) }
expect { bulk_update(issue, assignee_ids: [IssuableFinder::Params::NONE.to_s]) }
.to change { issue.reload.assignees.count }.from(1).to(0)
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment