summaryrefslogtreecommitdiff
path: root/app/finders
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
commita09983ae35713f5a2bbb100981116d31ce99826e (patch)
tree2ee2af7bd104d57086db360a7e6d8c9d5d43667a /app/finders
parent18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff)
downloadgitlab-ce-a09983ae35713f5a2bbb100981116d31ce99826e.tar.gz
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'app/finders')
-rw-r--r--app/finders/branches_finder.rb26
-rw-r--r--app/finders/ci/pipelines_finder.rb2
-rw-r--r--app/finders/ci/pipelines_for_merge_request_finder.rb44
-rw-r--r--app/finders/ci/runner_jobs_finder.rb2
-rw-r--r--app/finders/ci/variables_finder.rb31
-rw-r--r--app/finders/events_finder.rb9
-rw-r--r--app/finders/group_projects_finder.rb55
-rw-r--r--app/finders/issuable_finder/params.rb4
-rw-r--r--app/finders/issues_finder.rb1
-rw-r--r--app/finders/issues_finder/params.rb17
-rw-r--r--app/finders/notes_finder.rb9
-rw-r--r--app/finders/packages/composer/packages_finder.rb16
-rw-r--r--app/finders/packages/conan/package_file_finder.rb28
-rw-r--r--app/finders/packages/conan/package_finder.rb32
-rw-r--r--app/finders/packages/go/module_finder.rb29
-rw-r--r--app/finders/packages/go/version_finder.rb44
-rw-r--r--app/finders/packages/group_packages_finder.rb70
-rw-r--r--app/finders/packages/maven/package_finder.rb62
-rw-r--r--app/finders/packages/npm/package_finder.rb29
-rw-r--r--app/finders/packages/nuget/package_finder.rb31
-rw-r--r--app/finders/packages/package_file_finder.rb36
-rw-r--r--app/finders/packages/package_finder.rb16
-rw-r--r--app/finders/packages/packages_finder.rb41
-rw-r--r--app/finders/packages/tags_finder.rb26
-rw-r--r--app/finders/personal_access_tokens_finder.rb2
-rw-r--r--app/finders/projects_finder.rb10
-rw-r--r--app/finders/resource_milestone_event_finder.rb69
-rw-r--r--app/finders/resource_state_event_finder.rb30
-rw-r--r--app/finders/snippets_finder.rb23
-rw-r--r--app/finders/todos_finder.rb23
30 files changed, 703 insertions, 114 deletions
diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb
index 8001c70a9b2..2eee90a512a 100644
--- a/app/finders/branches_finder.rb
+++ b/app/finders/branches_finder.rb
@@ -5,11 +5,15 @@ class BranchesFinder < GitRefsFinder
super(repository, params)
end
- def execute
- branches = repository.branches_sorted_by(sort)
- branches = by_search(branches)
- branches = by_names(branches)
- branches
+ def execute(gitaly_pagination: false)
+ if gitaly_pagination && names.blank? && search.blank?
+ repository.branches_sorted_by(sort, pagination_params)
+ else
+ branches = repository.branches_sorted_by(sort)
+ branches = by_search(branches)
+ branches = by_names(branches)
+ branches
+ end
end
private
@@ -18,6 +22,18 @@ class BranchesFinder < GitRefsFinder
@params[:names].presence
end
+ def per_page
+ @params[:per_page].presence
+ end
+
+ def page_token
+ "#{Gitlab::Git::BRANCH_REF_PREFIX}#{@params[:page_token]}" if @params[:page_token]
+ end
+
+ def pagination_params
+ { limit: per_page, page_token: page_token }
+ end
+
def by_names(branches)
return branches unless names
diff --git a/app/finders/ci/pipelines_finder.rb b/app/finders/ci/pipelines_finder.rb
index 9e71e92b456..7347a83d294 100644
--- a/app/finders/ci/pipelines_finder.rb
+++ b/app/finders/ci/pipelines_finder.rb
@@ -71,7 +71,7 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def by_status(items)
- return items unless HasStatus::AVAILABLE_STATUSES.include?(params[:status])
+ return items unless Ci::HasStatus::AVAILABLE_STATUSES.include?(params[:status])
items.where(status: params[:status])
end
diff --git a/app/finders/ci/pipelines_for_merge_request_finder.rb b/app/finders/ci/pipelines_for_merge_request_finder.rb
index c01a68d6749..93d139652b9 100644
--- a/app/finders/ci/pipelines_for_merge_request_finder.rb
+++ b/app/finders/ci/pipelines_for_merge_request_finder.rb
@@ -7,14 +7,29 @@ module Ci
EVENT = 'merge_request_event'
- def initialize(merge_request)
+ def initialize(merge_request, current_user)
@merge_request = merge_request
+ @current_user = current_user
end
- attr_reader :merge_request
+ attr_reader :merge_request, :current_user
- delegate :commit_shas, :source_project, :source_branch, to: :merge_request
+ delegate :commit_shas, :target_project, :source_project, :source_branch, to: :merge_request
+ # Fetch all pipelines that the user can read.
+ def execute
+ if can_read_pipeline_in_target_project? && can_read_pipeline_in_source_project?
+ all
+ elsif can_read_pipeline_in_source_project?
+ all.for_project(merge_request.source_project)
+ elsif can_read_pipeline_in_target_project?
+ all.for_project(merge_request.target_project)
+ else
+ Ci::Pipeline.none
+ end
+ end
+
+ # Fetch all pipelines without permission check.
def all
strong_memoize(:all_pipelines) do
next Ci::Pipeline.none unless source_project
@@ -35,13 +50,13 @@ module Ci
def pipelines_using_cte
cte = Gitlab::SQL::CTE.new(:shas, merge_request.all_commits.select(:sha))
- source_pipelines_join = cte.table[:sha].eq(Ci::Pipeline.arel_table[:source_sha])
- source_pipelines = filter_by(triggered_by_merge_request, cte, source_pipelines_join)
- detached_pipelines = filter_by_sha(triggered_by_merge_request, cte)
+ source_sha_join = cte.table[:sha].eq(Ci::Pipeline.arel_table[:source_sha])
+ merged_result_pipelines = filter_by(triggered_by_merge_request, cte, source_sha_join)
+ detached_merge_request_pipelines = filter_by_sha(triggered_by_merge_request, cte)
pipelines_for_branch = filter_by_sha(triggered_for_branch, cte)
Ci::Pipeline.with(cte.to_arel) # rubocop: disable CodeReuse/ActiveRecord
- .from_union([source_pipelines, detached_pipelines, pipelines_for_branch])
+ .from_union([merged_result_pipelines, detached_merge_request_pipelines, pipelines_for_branch])
end
def filter_by_sha(pipelines, cte)
@@ -65,8 +80,7 @@ module Ci
# NOTE: this method returns only parent merge request pipelines.
# Child merge request pipelines have a different source.
def triggered_by_merge_request
- source_project.ci_pipelines
- .where(source: :merge_request_event, merge_request: merge_request) # rubocop: disable CodeReuse/ActiveRecord
+ Ci::Pipeline.triggered_by_merge_request(merge_request)
end
def triggered_for_branch
@@ -86,5 +100,17 @@ module Ci
pipelines.order(Arel.sql(query)) # rubocop: disable CodeReuse/ActiveRecord
end
+
+ def can_read_pipeline_in_target_project?
+ strong_memoize(:can_read_pipeline_in_target_project) do
+ Ability.allowed?(current_user, :read_pipeline, target_project)
+ end
+ end
+
+ def can_read_pipeline_in_source_project?
+ strong_memoize(:can_read_pipeline_in_source_project) do
+ Ability.allowed?(current_user, :read_pipeline, source_project)
+ end
+ end
end
end
diff --git a/app/finders/ci/runner_jobs_finder.rb b/app/finders/ci/runner_jobs_finder.rb
index ffcdb407e7e..9dc3c2a2427 100644
--- a/app/finders/ci/runner_jobs_finder.rb
+++ b/app/finders/ci/runner_jobs_finder.rb
@@ -21,7 +21,7 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def by_status(items)
- return items unless HasStatus::AVAILABLE_STATUSES.include?(params[:status])
+ return items unless Ci::HasStatus::AVAILABLE_STATUSES.include?(params[:status])
items.where(status: params[:status])
end
diff --git a/app/finders/ci/variables_finder.rb b/app/finders/ci/variables_finder.rb
new file mode 100644
index 00000000000..d933643ffb2
--- /dev/null
+++ b/app/finders/ci/variables_finder.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Ci
+ class VariablesFinder
+ attr_reader :project, :params
+
+ def initialize(project, params)
+ @project, @params = project, params
+
+ raise ArgumentError, 'Please provide params[:key]' if params[:key].blank?
+ end
+
+ def execute
+ variables = project.variables
+ variables = by_key(variables)
+ variables = by_environment_scope(variables)
+ variables
+ end
+
+ private
+
+ def by_key(variables)
+ variables.by_key(params[:key])
+ end
+
+ def by_environment_scope(variables)
+ environment_scope = params.dig(:filter, :environment_scope)
+ environment_scope.present? ? variables.by_environment_scope(environment_scope) : variables
+ end
+ end
+end
diff --git a/app/finders/events_finder.rb b/app/finders/events_finder.rb
index 004fbc4cd22..4c619f3d7ea 100644
--- a/app/finders/events_finder.rb
+++ b/app/finders/events_finder.rb
@@ -54,17 +54,10 @@ class EventsFinder
if current_user && scope == 'all'
EventCollection.new(current_user.authorized_projects).all_project_events
else
- # EventCollection is responsible for applying the feature flag
- apply_feature_flags(source.events)
+ source.events
end
end
- def apply_feature_flags(events)
- return events if ::Feature.enabled?(:wiki_events)
-
- events.not_wiki_page
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def by_current_user_access(events)
events.merge(Project.public_or_visible_to_user(current_user))
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
index dd8b2f29425..5f24b15156c 100644
--- a/app/finders/group_projects_finder.rb
+++ b/app/finders/group_projects_finder.rb
@@ -19,6 +19,9 @@
# personal: boolean
# search: string
# non_archived: boolean
+# with_issues_enabled: boolean
+# with_merge_requests_enabled: boolean
+# min_access_level: int
#
class GroupProjectsFinder < ProjectsFinder
DEFAULT_PROJECTS_LIMIT = 100
@@ -42,6 +45,12 @@ class GroupProjectsFinder < ProjectsFinder
private
+ def filter_projects(collection)
+ projects = super
+ projects = by_feature_availability(projects)
+ projects
+ end
+
def limit(collection)
limit = options[:limit]
@@ -49,35 +58,37 @@ class GroupProjectsFinder < ProjectsFinder
end
def init_collection
- projects = if current_user
- collection_with_user
- else
- collection_without_user
- end
+ projects =
+ if only_shared?
+ [shared_projects]
+ elsif only_owned?
+ [owned_projects]
+ else
+ [owned_projects, shared_projects]
+ end
+
+ projects.map! do |project_relation|
+ filter_by_visibility(project_relation)
+ end
union(projects)
end
- def collection_with_user
- if only_shared?
- [shared_projects.public_or_visible_to_user(current_user)]
- elsif only_owned?
- [owned_projects.public_or_visible_to_user(current_user)]
- else
- [
- owned_projects.public_or_visible_to_user(current_user),
- shared_projects.public_or_visible_to_user(current_user)
- ]
- end
+ def by_feature_availability(projects)
+ projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled].present?
+ projects = projects.with_merge_requests_available_for_user(current_user) if params[:with_merge_requests_enabled].present?
+ projects
end
- def collection_without_user
- if only_shared?
- [shared_projects.public_only]
- elsif only_owned?
- [owned_projects.public_only]
+ def filter_by_visibility(relation)
+ if current_user
+ if min_access_level?
+ relation.visible_to_user_and_access_level(current_user, params[:min_access_level])
+ else
+ relation.public_or_visible_to_user(current_user)
+ end
else
- [shared_projects.public_only, owned_projects.public_only]
+ relation.public_only
end
end
diff --git a/app/finders/issuable_finder/params.rb b/app/finders/issuable_finder/params.rb
index 5b48d0817e3..8a194f34f74 100644
--- a/app/finders/issuable_finder/params.rb
+++ b/app/finders/issuable_finder/params.rb
@@ -110,7 +110,9 @@ class IssuableFinder
def group
strong_memoize(:group) do
- if params[:group_id].present?
+ if params[:group_id].is_a?(Group)
+ params[:group_id]
+ elsif params[:group_id].present?
Group.find(params[:group_id])
else
nil
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index 72695a9d501..2b2e6b377b4 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -24,6 +24,7 @@
# created_before: datetime
# updated_after: datetime
# updated_before: datetime
+# confidential: boolean
#
class IssuesFinder < IssuableFinder
CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::REPORTER
diff --git a/app/finders/issues_finder/params.rb b/app/finders/issues_finder/params.rb
index cd92b79265d..668d969f7c0 100644
--- a/app/finders/issues_finder/params.rb
+++ b/app/finders/issues_finder/params.rb
@@ -27,19 +27,14 @@ class IssuesFinder
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
+ strong_memoize(:user_can_see_all_confidential_issues) do
+ parent = project? ? project : group
+ if parent
+ Ability.allowed?(current_user, :read_confidential_issues, parent)
else
- false
+ Ability.allowed?(current_user, :read_all_resources)
end
+ end
end
def user_cannot_see_confidential_issues?
diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb
index 8e57014f66e..1a3f011d9eb 100644
--- a/app/finders/notes_finder.rb
+++ b/app/finders/notes_finder.rb
@@ -158,13 +158,16 @@ class NotesFinder
end
# Notes changed since last fetch
- # Uses overlapping intervals to avoid worrying about race conditions
def since_fetch_at(notes)
return notes unless @params[:last_fetched_at]
# Default to 0 to remain compatible with old clients
- last_fetched_at = Time.at(@params.fetch(:last_fetched_at, 0).to_i)
- notes.updated_after(last_fetched_at - FETCH_OVERLAP)
+ last_fetched_at = @params.fetch(:last_fetched_at, Time.at(0))
+
+ # Use overlapping intervals to avoid worrying about race conditions
+ last_fetched_at -= FETCH_OVERLAP
+
+ notes.updated_after(last_fetched_at)
end
def notes_filter?
diff --git a/app/finders/packages/composer/packages_finder.rb b/app/finders/packages/composer/packages_finder.rb
new file mode 100644
index 00000000000..e63b2ee03fa
--- /dev/null
+++ b/app/finders/packages/composer/packages_finder.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+module Packages
+ module Composer
+ class PackagesFinder < Packages::GroupPackagesFinder
+ def initialize(current_user, group, params = {})
+ @current_user = current_user
+ @group = group
+ @params = params
+ end
+
+ def execute
+ packages_for_group_projects.composer.preload_composer
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/conan/package_file_finder.rb b/app/finders/packages/conan/package_file_finder.rb
new file mode 100644
index 00000000000..edf35388a36
--- /dev/null
+++ b/app/finders/packages/conan/package_file_finder.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Packages
+ module Conan
+ class PackageFileFinder < ::Packages::PackageFileFinder
+ private
+
+ def package_files
+ files = super
+ files = by_conan_file_type(files)
+ files = by_conan_package_reference(files)
+ files
+ end
+
+ def by_conan_file_type(files)
+ return files unless params[:conan_file_type]
+
+ files.with_conan_file_type(params[:conan_file_type])
+ end
+
+ def by_conan_package_reference(files)
+ return files unless params[:conan_package_reference]
+
+ files.with_conan_package_reference(params[:conan_package_reference])
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/conan/package_finder.rb b/app/finders/packages/conan/package_finder.rb
new file mode 100644
index 00000000000..26e9182f4e1
--- /dev/null
+++ b/app/finders/packages/conan/package_finder.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Packages
+ module Conan
+ class PackageFinder
+ attr_reader :current_user, :query
+
+ def initialize(current_user, params)
+ @current_user = current_user
+ @query = params[:query]
+ end
+
+ def execute
+ packages_for_current_user.with_name_like(query).order_name_asc if query
+ end
+
+ private
+
+ def packages
+ Packages::Package.conan
+ end
+
+ def packages_for_current_user
+ packages.for_projects(projects_visible_to_current_user)
+ end
+
+ def projects_visible_to_current_user
+ ::Project.public_or_visible_to_user(current_user)
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/go/module_finder.rb b/app/finders/packages/go/module_finder.rb
new file mode 100644
index 00000000000..ed8bd5599d9
--- /dev/null
+++ b/app/finders/packages/go/module_finder.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Packages
+ module Go
+ class ModuleFinder
+ include Gitlab::Golang
+
+ attr_reader :project, :module_name
+
+ def initialize(project, module_name)
+ module_name = Pathname.new(module_name).cleanpath.to_s
+
+ @project = project
+ @module_name = module_name
+ end
+
+ def execute
+ return if @module_name.blank? || !@module_name.start_with?(local_module_prefix)
+
+ module_path = @module_name[local_module_prefix.length..].split('/')
+ project_path = project.full_path.split('/')
+ module_project_path = module_path.shift(project_path.length)
+ return unless module_project_path == project_path
+
+ Packages::Go::Module.new(@project, @module_name, module_path.join('/'))
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/go/version_finder.rb b/app/finders/packages/go/version_finder.rb
new file mode 100644
index 00000000000..8e2fab8ba35
--- /dev/null
+++ b/app/finders/packages/go/version_finder.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Packages
+ module Go
+ class VersionFinder
+ include Gitlab::Golang
+
+ attr_reader :mod
+
+ def initialize(mod)
+ @mod = mod
+ end
+
+ def execute
+ @mod.project.repository.tags
+ .filter { |tag| semver_tag? tag }
+ .map { |tag| @mod.version_by(ref: tag) }
+ .filter { |ver| ver.valid? }
+ end
+
+ def find(target)
+ case target
+ when String
+ if pseudo_version? target
+ semver = parse_semver(target)
+ commit = pseudo_version_commit(@mod.project, semver)
+ Packages::Go::ModuleVersion.new(@mod, :pseudo, commit, name: target, semver: semver)
+ else
+ @mod.version_by(ref: target)
+ end
+
+ when Gitlab::Git::Ref
+ @mod.version_by(ref: target)
+
+ when ::Commit, Gitlab::Git::Commit
+ @mod.version_by(commit: target)
+
+ else
+ raise ArgumentError.new 'not a valid target'
+ end
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/group_packages_finder.rb b/app/finders/packages/group_packages_finder.rb
new file mode 100644
index 00000000000..ffc8c35fbcc
--- /dev/null
+++ b/app/finders/packages/group_packages_finder.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Packages
+ class GroupPackagesFinder
+ attr_reader :current_user, :group, :params
+
+ InvalidPackageTypeError = Class.new(StandardError)
+
+ def initialize(current_user, group, params = { exclude_subgroups: false, order_by: 'created_at', sort: 'asc' })
+ @current_user = current_user
+ @group = group
+ @params = params
+ end
+
+ def execute
+ return ::Packages::Package.none unless group
+
+ packages_for_group_projects
+ end
+
+ private
+
+ def packages_for_group_projects
+ packages = ::Packages::Package
+ .for_projects(group_projects_visible_to_current_user)
+ .processed
+ .has_version
+ .sort_by_attribute("#{params[:order_by]}_#{params[:sort]}")
+
+ packages = filter_by_package_type(packages)
+ packages = filter_by_package_name(packages)
+ packages
+ end
+
+ def group_projects_visible_to_current_user
+ ::Project
+ .in_namespace(groups)
+ .public_or_visible_to_user(current_user, Gitlab::Access::REPORTER)
+ .with_project_feature
+ .select { |project| Ability.allowed?(current_user, :read_package, project) }
+ end
+
+ def package_type
+ params[:package_type].presence
+ end
+
+ def groups
+ return [group] if exclude_subgroups?
+
+ group.self_and_descendants
+ end
+
+ def exclude_subgroups?
+ params[:exclude_subgroups]
+ end
+
+ def filter_by_package_type(packages)
+ return packages unless package_type
+ raise InvalidPackageTypeError unless Package.package_types.key?(package_type)
+
+ packages.with_package_type(package_type)
+ end
+
+ def filter_by_package_name(packages)
+ return packages unless params[:package_name].present?
+
+ packages.search_by_name(params[:package_name])
+ end
+ end
+end
diff --git a/app/finders/packages/maven/package_finder.rb b/app/finders/packages/maven/package_finder.rb
new file mode 100644
index 00000000000..775db12adb7
--- /dev/null
+++ b/app/finders/packages/maven/package_finder.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+module Packages
+ module Maven
+ class PackageFinder
+ attr_reader :path, :current_user, :project, :group
+
+ def initialize(path, current_user, project: nil, group: nil)
+ @path = path
+ @current_user = current_user
+ @project = project
+ @group = group
+ end
+
+ def execute
+ packages_with_path.last
+ end
+
+ def execute!
+ packages_with_path.last!
+ end
+
+ private
+
+ def base
+ if project
+ packages_for_a_single_project
+ elsif group
+ packages_for_multiple_projects
+ else
+ packages
+ end
+ end
+
+ def packages_with_path
+ base.only_maven_packages_with_path(path)
+ end
+
+ # Produces a query that returns all packages.
+ def packages
+ ::Packages::Package.all
+ end
+
+ # Produces a query that retrieves packages from a single project.
+ def packages_for_a_single_project
+ project.packages
+ end
+
+ # Produces a query that retrieves packages from multiple projects that
+ # the current user can view within a group.
+ def packages_for_multiple_projects
+ ::Packages::Package.for_projects(projects_visible_to_current_user)
+ end
+
+ # Returns the projects that the current user can view within a group.
+ def projects_visible_to_current_user
+ ::Project
+ .in_namespace(group.self_and_descendants.select(:id))
+ .public_or_visible_to_user(current_user)
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/npm/package_finder.rb b/app/finders/packages/npm/package_finder.rb
new file mode 100644
index 00000000000..8599fd07e7f
--- /dev/null
+++ b/app/finders/packages/npm/package_finder.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+module Packages
+ module Npm
+ class PackageFinder
+ attr_reader :project, :package_name
+
+ delegate :find_by_version, to: :execute
+
+ def initialize(project, package_name)
+ @project = project
+ @package_name = package_name
+ end
+
+ def execute
+ packages
+ end
+
+ private
+
+ def packages
+ project.packages
+ .npm
+ .with_name(package_name)
+ .last_of_each_version
+ .preload_files
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/nuget/package_finder.rb b/app/finders/packages/nuget/package_finder.rb
new file mode 100644
index 00000000000..e6fb6712d47
--- /dev/null
+++ b/app/finders/packages/nuget/package_finder.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+module Packages
+ module Nuget
+ class PackageFinder
+ MAX_PACKAGES_COUNT = 50
+
+ def initialize(project, package_name:, package_version: nil, limit: MAX_PACKAGES_COUNT)
+ @project = project
+ @package_name = package_name
+ @package_version = package_version
+ @limit = limit
+ end
+
+ def execute
+ packages.limit_recent(@limit)
+ end
+
+ private
+
+ def packages
+ result = @project.packages
+ .nuget
+ .has_version
+ .processed
+ .with_name_like(@package_name)
+ result = result.with_version(@package_version) if @package_version.present?
+ result
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/package_file_finder.rb b/app/finders/packages/package_file_finder.rb
new file mode 100644
index 00000000000..d015f4adfa6
--- /dev/null
+++ b/app/finders/packages/package_file_finder.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+class Packages::PackageFileFinder
+ attr_reader :package, :file_name, :params
+
+ def initialize(package, file_name, params = {})
+ @package = package
+ @file_name = file_name
+ @params = params
+ end
+
+ def execute
+ package_files.last
+ end
+
+ def execute!
+ package_files.last!
+ end
+
+ private
+
+ def package_files
+ files = package.package_files
+
+ files = by_file_name(files)
+
+ files
+ end
+
+ def by_file_name(files)
+ if params[:with_file_name_like]
+ files.with_file_name_like(file_name)
+ else
+ files.with_file_name(file_name)
+ end
+ end
+end
diff --git a/app/finders/packages/package_finder.rb b/app/finders/packages/package_finder.rb
new file mode 100644
index 00000000000..0e911491da2
--- /dev/null
+++ b/app/finders/packages/package_finder.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+module Packages
+ class PackageFinder
+ def initialize(project, package_id)
+ @project = project
+ @package_id = package_id
+ end
+
+ def execute
+ @project
+ .packages
+ .processed
+ .find(@package_id)
+ end
+ end
+end
diff --git a/app/finders/packages/packages_finder.rb b/app/finders/packages/packages_finder.rb
new file mode 100644
index 00000000000..c533cb266a2
--- /dev/null
+++ b/app/finders/packages/packages_finder.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Packages
+ class PackagesFinder
+ attr_reader :params, :project
+
+ def initialize(project, params = {})
+ @project = project
+ @params = params
+
+ params[:order_by] ||= 'created_at'
+ params[:sort] ||= 'asc'
+ end
+
+ def execute
+ packages = project.packages.processed.has_version
+ packages = filter_by_package_type(packages)
+ packages = filter_by_package_name(packages)
+ packages = order_packages(packages)
+ packages
+ end
+
+ private
+
+ def filter_by_package_type(packages)
+ return packages unless params[:package_type]
+
+ packages.with_package_type(params[:package_type])
+ end
+
+ def filter_by_package_name(packages)
+ return packages unless params[:package_name]
+
+ packages.search_by_name(params[:package_name])
+ end
+
+ def order_packages(packages)
+ packages.sort_by_attribute("#{params[:order_by]}_#{params[:sort]}")
+ end
+ end
+end
diff --git a/app/finders/packages/tags_finder.rb b/app/finders/packages/tags_finder.rb
new file mode 100644
index 00000000000..020b3d8072a
--- /dev/null
+++ b/app/finders/packages/tags_finder.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+class Packages::TagsFinder
+ attr_reader :project, :package_name, :params
+
+ delegate :find_by_name, to: :execute
+
+ def initialize(project, package_name, params = {})
+ @project = project
+ @package_name = package_name
+ @params = params
+ end
+
+ def execute
+ packages = project.packages
+ .with_name(package_name)
+ packages = packages.with_package_type(package_type) if package_type.present?
+
+ Packages::Tag.for_packages(packages)
+ end
+
+ private
+
+ def package_type
+ params[:package_type]
+ end
+end
diff --git a/app/finders/personal_access_tokens_finder.rb b/app/finders/personal_access_tokens_finder.rb
index 7b15a3b0c10..e3d5f2ae8de 100644
--- a/app/finders/personal_access_tokens_finder.rb
+++ b/app/finders/personal_access_tokens_finder.rb
@@ -51,6 +51,8 @@ class PersonalAccessTokensFinder
tokens.active
when 'inactive'
tokens.inactive
+ when 'active_or_expired'
+ tokens.not_revoked.expired.or(tokens.active)
else
tokens
end
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 8846ff54eb2..7c7cd87a7c1 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -23,6 +23,7 @@
# min_access_level: integer
# last_activity_after: datetime
# last_activity_before: datetime
+# repository_storage: string
#
class ProjectsFinder < UnionFinder
include CustomAttributesFilter
@@ -75,6 +76,7 @@ class ProjectsFinder < UnionFinder
collection = by_deleted_status(collection)
collection = by_last_activity_after(collection)
collection = by_last_activity_before(collection)
+ collection = by_repository_storage(collection)
collection
end
@@ -197,6 +199,14 @@ class ProjectsFinder < UnionFinder
end
end
+ def by_repository_storage(items)
+ if params[:repository_storage].present?
+ items.where(repository_storage: params[:repository_storage]) # rubocop: disable CodeReuse/ActiveRecord
+ else
+ items
+ end
+ end
+
def sort(items)
params[:sort].present? ? items.sort_by_attribute(params[:sort]) : items.projects_order_id_desc
end
diff --git a/app/finders/resource_milestone_event_finder.rb b/app/finders/resource_milestone_event_finder.rb
index 7af34f0a4bc..f3b779c8f77 100644
--- a/app/finders/resource_milestone_event_finder.rb
+++ b/app/finders/resource_milestone_event_finder.rb
@@ -1,69 +1,56 @@
# frozen_string_literal: true
class ResourceMilestoneEventFinder
- include FinderMethods
-
- MAX_PER_PAGE = 100
-
- attr_reader :params, :current_user, :eventable
-
- def initialize(current_user, eventable, params = {})
+ def initialize(current_user, eventable)
@current_user = current_user
@eventable = eventable
- @params = params
end
+ # Returns the ResourceMilestoneEvents of the eventable
+ # visible to the user.
+ #
+ # @return ResourceMilestoneEvent::ActiveRecord_AssociationRelation
def execute
- Kaminari.paginate_array(visible_events)
+ eventable.resource_milestone_events.include_relations
+ .where(milestone_id: readable_milestone_ids) # rubocop: disable CodeReuse/ActiveRecord
end
private
- def visible_events
- @visible_events ||= visible_to_user(events)
- end
+ attr_reader :current_user, :eventable
- def events
- @events ||= eventable.resource_milestone_events.include_relations.page(page).per(per_page)
- end
+ def readable_milestone_ids
+ readable_milestones = events_milestones.select do |milestone|
+ parent_availabilities[key_for_parent(milestone.parent)]
+ end
- def visible_to_user(events)
- events.select { |event| visible_for_user?(event) }
+ readable_milestones.map(&:id).uniq
end
- def visible_for_user?(event)
- milestone = event_milestones[event.milestone_id]
- return if milestone.blank?
+ # rubocop: disable CodeReuse/ActiveRecord
+ def events_milestones
+ @events_milestones ||= Milestone.where(id: unique_milestone_ids_from_events)
+ .includes(:project, :group)
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
- parent = milestone.parent
- parent_availabilities[key_for_parent(parent)]
+ def relevant_milestone_parents
+ events_milestones.map(&:parent).uniq
end
def parent_availabilities
- @parent_availabilities ||= relevant_parents.to_h do |parent|
+ @parent_availabilities ||= relevant_milestone_parents.to_h do |parent|
[key_for_parent(parent), Ability.allowed?(current_user, :read_milestone, parent)]
end
end
- def key_for_parent(parent)
- "#{parent.class.name}_#{parent.id}"
- end
-
- def event_milestones
- @milestones ||= events.map(&:milestone).uniq.to_h do |milestone|
- [milestone.id, milestone]
- end
- end
-
- def relevant_parents
- @relevant_parents ||= event_milestones.map { |_id, milestone| milestone.parent }
+ # rubocop: disable CodeReuse/ActiveRecord
+ def unique_milestone_ids_from_events
+ eventable.resource_milestone_events.select(:milestone_id).distinct
end
+ # rubocop: enable CodeReuse/ActiveRecord
- def per_page
- [params[:per_page], MAX_PER_PAGE].compact.min
- end
-
- def page
- params[:page] || 1
+ def key_for_parent(parent)
+ "#{parent.class.name}_#{parent.id}"
end
end
diff --git a/app/finders/resource_state_event_finder.rb b/app/finders/resource_state_event_finder.rb
new file mode 100644
index 00000000000..7f4ac3332cd
--- /dev/null
+++ b/app/finders/resource_state_event_finder.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class ResourceStateEventFinder
+ include FinderMethods
+
+ def initialize(current_user, eventable)
+ @current_user = current_user
+ @eventable = eventable
+ end
+
+ def execute
+ return ResourceStateEvent.none unless can_read_eventable?
+
+ eventable.resource_state_events.includes(:user) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def can_read_eventable?
+ return unless eventable
+
+ Ability.allowed?(current_user, read_ability, eventable)
+ end
+
+ private
+
+ attr_reader :current_user, :eventable
+
+ def read_ability
+ :"read_#{eventable.class.to_ability_name}"
+ end
+end
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index 4f63810423b..941abb70400 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -43,7 +43,7 @@ class SnippetsFinder < UnionFinder
include Gitlab::Utils::StrongMemoize
attr_accessor :current_user, :params
- delegate :explore, :only_personal, :only_project, :scope, to: :params
+ delegate :explore, :only_personal, :only_project, :scope, :sort, to: :params
def initialize(current_user = nil, params = {})
@current_user = current_user
@@ -69,7 +69,9 @@ class SnippetsFinder < UnionFinder
items = init_collection
items = by_ids(items)
- items.with_optional_visibility(visibility_from_scope).fresh
+ items = items.with_optional_visibility(visibility_from_scope)
+
+ items.order_by(sort_param)
end
private
@@ -115,7 +117,7 @@ class SnippetsFinder < UnionFinder
queries << snippets_of_authorized_projects if current_user
end
- find_union(queries, Snippet)
+ prepared_union(queries)
end
def snippets_for_a_single_project
@@ -202,6 +204,21 @@ class SnippetsFinder < UnionFinder
params[:project].is_a?(Project) ? params[:project] : Project.find_by_id(params[:project])
end
end
+
+ def sort_param
+ sort.presence || 'id_desc'
+ end
+
+ def prepared_union(queries)
+ return Snippet.none if queries.empty?
+ return queries.first if queries.length == 1
+
+ # The queries are going to be part of a global `where`
+ # therefore we only need to retrieve the `id` column
+ # which will speed the query
+ queries.map! { |rel| rel.select(:id) }
+ Snippet.id_in(find_union(queries, Snippet))
+ end
end
SnippetsFinder.prepend_if_ee('EE::SnippetsFinder')
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index 672bbd52b07..a2054f73c9d 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -11,7 +11,7 @@
# author_id: integer
# project_id; integer
# state: 'pending' (default) or 'done'
-# type: 'Issue' or 'MergeRequest'
+# type: 'Issue' or 'MergeRequest' or ['Issue', 'MergeRequest']
#
class TodosFinder
@@ -40,13 +40,14 @@ class TodosFinder
def execute
return Todo.none if current_user.nil?
+ raise ArgumentError, invalid_type_message unless valid_types?
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_types(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
@@ -123,12 +124,16 @@ class TodosFinder
end
end
- def type?
- type.present? && self.class.todo_types.include?(type)
+ def types
+ @types ||= Array(params[:type]).reject(&:blank?)
end
- def type
- params[:type]
+ def valid_types?
+ types.all? { |type| self.class.todo_types.include?(type) }
+ end
+
+ def invalid_type_message
+ _("Unsupported todo type passed. Supported todo types are: %{todo_types}") % { todo_types: self.class.todo_types.to_a.join(', ') }
end
def sort(items)
@@ -193,9 +198,9 @@ class TodosFinder
items.with_states(params[:state])
end
- def by_type(items)
- if type?
- items.for_type(type)
+ def by_types(items)
+ if types.any?
+ items.for_type(types)
else
items
end