| ... | @@ -46,10 +46,13 @@ class IssuableFinder |
... | @@ -46,10 +46,13 @@ class IssuableFinder |
|
|
# This is used in unassigning users
|
|
# This is used in unassigning users
|
|
|
NONE = '0'
|
|
NONE = '0'
|
|
|
|
|
|
|
|
|
NEGATABLE_PARAMS_HELPER_KEYS = %i[include_subgroups in].freeze
|
|
|
|
|
|
|
attr_accessor :current_user, :params
|
|
attr_accessor :current_user, :params
|
|
|
|
|
|
|
|
def self.scalar_params
|
|
class << self
|
|
|
@scalar_params ||= %i[
|
|
def scalar_params
|
|
|
|
@scalar_params ||= %i[
|
|
|
assignee_id
|
|
assignee_id
|
|
|
assignee_username
|
|
assignee_username
|
|
|
author_id
|
|
author_id
|
| ... | @@ -60,14 +63,30 @@ class IssuableFinder |
... | @@ -60,14 +63,30 @@ class IssuableFinder |
|
|
search
|
|
search
|
|
|
in
|
|
in
|
|
|
]
|
|
]
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
def self.array_params
|
|
def array_params
|
|
|
@array_params ||= { label_name: [], assignee_username: [] }
|
|
@array_params ||= { label_name: [], assignee_username: [] }
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
# This should not be used in controller strong params!
|
|
|
|
def negatable_scalar_params
|
|
|
|
@negatable_scalar_params ||= scalar_params + %i[project_id group_id]
|
|
|
|
end
|
|
|
|
|
|
|
|
# This should not be used in controller strong params!
|
|
|
|
def negatable_array_params
|
|
|
|
@negatable_array_params ||= array_params.keys.append(:iids)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.valid_params
|
|
# This should not be used in controller strong params!
|
|
|
@valid_params ||= scalar_params + [array_params]
|
|
def negatable_params
|
|
|
|
@negatable_params ||= negatable_scalar_params + negatable_array_params
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid_params
|
|
|
|
@valid_params ||= scalar_params + [array_params] + [{ not: [] }]
|
|
|
|
end
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
def initialize(current_user, params = {})
|
|
def initialize(current_user, params = {})
|
| ... | @@ -79,6 +98,9 @@ class IssuableFinder |
... | @@ -79,6 +98,9 @@ class IssuableFinder |
|
|
items = init_collection
|
|
items = init_collection
|
|
|
items = filter_items(items)
|
|
items = filter_items(items)
|
|
|
|
|
|
|
|
|
# Let's see if we have to negate anything
|
|
|
|
items = by_negation(items)
|
|
|
|
|
|
|
# This has to be last as we use a CTE as an optimization fence
|
|
# This has to be last as we use a CTE as an optimization fence
|
|
|
# for counts by passing the force_cte param and enabling the
|
|
# for counts by passing the force_cte param and enabling the
|
|
|
# attempt_group_search_optimizations feature flag
|
|
# attempt_group_search_optimizations feature flag
|
| ... | @@ -366,6 +388,33 @@ class IssuableFinder |
... | @@ -366,6 +388,33 @@ class IssuableFinder |
|
|
Array(value).last.to_sym
|
|
Array(value).last.to_sym
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
# Negates all params found in `negatable_params`
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
|
|
def by_negation(items)
|
|
|
|
not_params = params[:not].dup
|
|
|
|
# API endpoints send in `nil` values so we test if there are any non-nil
|
|
|
|
return items unless not_params.present? && not_params.values.any?
|
|
|
|
|
|
|
|
not_params.keep_if { |_k, v| v.present? }.each do |(key, value)|
|
|
|
|
# These aren't negatable params themselves, but rather help other searches, so we skip them.
|
|
|
|
# They will be added into all the NOT searches.
|
|
|
|
next if NEGATABLE_PARAMS_HELPER_KEYS.include?(key.to_sym)
|
|
|
|
next unless self.class.negatable_params.include?(key.to_sym)
|
|
|
|
|
|
|
|
# These are "helper" params that are required inside the NOT to get the right results. They usually come in
|
|
|
|
# at the top-level params, but if they do come in inside the `:not` params, they should take precedence.
|
|
|
|
not_helpers = params.slice(*NEGATABLE_PARAMS_HELPER_KEYS).merge(params[:not].slice(*NEGATABLE_PARAMS_HELPER_KEYS))
|
|
|
|
not_param = { key => value }.with_indifferent_access.merge(not_helpers)
|
|
|
|
|
|
|
|
items_to_negate = self.class.new(current_user, not_param).execute
|
|
|
|
|
|
|
|
items = items.where.not(id: items_to_negate)
|
|
|
|
end
|
|
|
|
|
|
|
|
items
|
|
|
|
end
|
|
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
|
def by_scope(items)
|
|
def by_scope(items)
|
|
|
return items.none if current_user_related? && !current_user
|
|
return items.none if current_user_related? && !current_user
|
| ... | |
... | |
| ... | | ... | |