From 859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 18 Feb 2021 10:34:06 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-9-stable-ee --- app/finders/autocomplete/users_finder.rb | 10 ++- app/finders/ci/jobs_finder.rb | 7 +- .../daily_build_group_report_results_finder.rb | 88 ++++++++++++++++++++++ app/finders/concerns/packages/finder_helper.rb | 33 ++++++++ app/finders/container_repositories_finder.rb | 9 ++- app/finders/deployments_finder.rb | 85 ++++++++++++++------- app/finders/labels_finder.rb | 6 +- app/finders/license_template_finder.rb | 5 ++ app/finders/merge_request/metrics_finder.rb | 65 ++++++++++++++++ .../merge_requests/oldest_per_commit_finder.rb | 33 ++++++++ app/finders/packages/group_packages_finder.rb | 30 +------- app/finders/packages/nuget/package_finder.rb | 2 +- app/finders/packages/packages_finder.rb | 21 +----- .../repositories/commits_with_trailer_finder.rb | 82 ++++++++++++++++++++ app/finders/repositories/previous_tag_finder.rb | 51 +++++++++++++ app/finders/template_finder.rb | 16 ++++ app/finders/terraform/states_finder.rb | 28 +++++++ app/finders/user_recent_events_finder.rb | 43 ++++++----- 18 files changed, 515 insertions(+), 99 deletions(-) create mode 100644 app/finders/ci/testing/daily_build_group_report_results_finder.rb create mode 100644 app/finders/merge_request/metrics_finder.rb create mode 100644 app/finders/merge_requests/oldest_per_commit_finder.rb create mode 100644 app/finders/repositories/commits_with_trailer_finder.rb create mode 100644 app/finders/repositories/previous_tag_finder.rb create mode 100644 app/finders/terraform/states_finder.rb (limited to 'app/finders') diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb index 8dc3c2320ed..ff5d9ea7d19 100644 --- a/app/finders/autocomplete/users_finder.rb +++ b/app/finders/autocomplete/users_finder.rb @@ -38,7 +38,9 @@ module Autocomplete end end - items.uniq + items.uniq.tap do |unique_items| + preload_associations(unique_items) + end end private @@ -91,6 +93,12 @@ module Autocomplete User.none end end + + # rubocop: disable CodeReuse/ActiveRecord + def preload_associations(items) + ActiveRecord::Associations::Preloader.new.preload(items, :status) + end + # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/finders/ci/jobs_finder.rb b/app/finders/ci/jobs_finder.rb index 78791d737da..4408c9cdb6d 100644 --- a/app/finders/ci/jobs_finder.rb +++ b/app/finders/ci/jobs_finder.rb @@ -45,11 +45,12 @@ module Ci return unless pipeline raise Gitlab::Access::AccessDeniedError unless can?(current_user, :read_build, pipeline) - jobs_by_type(pipeline, type).latest + jobs_scope = jobs_by_type(pipeline, type) + params[:include_retried] ? jobs_scope : jobs_scope.latest end def filter_by_scope(builds) - return filter_by_statuses!(params[:scope], builds) if params[:scope].is_a?(Array) + return filter_by_statuses!(builds) if params[:scope].is_a?(Array) case params[:scope] when 'pending' @@ -63,7 +64,7 @@ module Ci end end - def filter_by_statuses!(statuses, builds) + def filter_by_statuses!(builds) unknown_statuses = params[:scope] - ::CommitStatus::AVAILABLE_STATUSES raise ArgumentError, 'Scope contains invalid value(s)' unless unknown_statuses.empty? diff --git a/app/finders/ci/testing/daily_build_group_report_results_finder.rb b/app/finders/ci/testing/daily_build_group_report_results_finder.rb new file mode 100644 index 00000000000..70d9e55dc47 --- /dev/null +++ b/app/finders/ci/testing/daily_build_group_report_results_finder.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +# DailyBuildGroupReportResultsFinder +# +# Used to filter DailyBuildGroupReportResults by set of params +# +# Arguments: +# current_user +# params: +# project: integer +# group: integer +# coverage: boolean +# ref_path: string +# start_date: date +# end_date: date +# sort: boolean +# limit: integer + +module Ci + module Testing + class DailyBuildGroupReportResultsFinder + include Gitlab::Allowable + + MAX_ITEMS = 1_000 + + attr_reader :params, :current_user + + def initialize(params: {}, current_user: nil) + @params = params + @current_user = current_user + end + + def execute + return Ci::DailyBuildGroupReportResult.none unless query_allowed? + + collection = Ci::DailyBuildGroupReportResult.by_projects(params[:project]) + collection = filter_report_results(collection) + collection + end + + private + + def query_allowed? + can?(current_user, :read_build_report_results, params[:project]) + end + + def filter_report_results(collection) + collection = by_coverage(collection) + collection = by_ref_path(collection) + collection = by_dates(collection) + + collection = sort(collection) + collection = limit_by(collection) + collection + end + + def by_coverage(items) + params[:coverage].present? ? items.with_coverage : items + end + + def by_ref_path(items) + params[:ref_path].present? ? items.by_ref_path(params[:ref_path]) : items.with_default_branch + end + + def by_dates(items) + params[:start_date].present? && params[:end_date].present? ? items.by_dates(params[:start_date], params[:end_date]) : items + end + + def sort(items) + params[:sort].present? ? items.ordered_by_date_and_group_name : items + end + + # rubocop: disable CodeReuse/ActiveRecord + def limit_by(items) + items.limit(limit) + end + # rubocop: enable CodeReuse/ActiveRecord + + def limit + return MAX_ITEMS unless params[:limit].present? + + [params[:limit].to_i, MAX_ITEMS].min + end + end + end +end + +Ci::Testing::DailyBuildGroupReportResultsFinder.prepend_if_ee('::EE::Ci::Testing::DailyBuildGroupReportResultsFinder') diff --git a/app/finders/concerns/packages/finder_helper.rb b/app/finders/concerns/packages/finder_helper.rb index 524e7aa7ff9..30bc0ff7909 100644 --- a/app/finders/concerns/packages/finder_helper.rb +++ b/app/finders/concerns/packages/finder_helper.rb @@ -4,6 +4,9 @@ module Packages module FinderHelper extend ActiveSupport::Concern + InvalidPackageTypeError = Class.new(StandardError) + InvalidStatusError = Class.new(StandardError) + private def packages_visible_to_user(user, within_group:) @@ -25,5 +28,35 @@ module Packages ::Project.in_namespace(namespace_ids) .public_or_visible_to_user(user, ::Gitlab::Access::REPORTER) end + + def package_type + params[:package_type].presence + end + + def filter_by_package_type(packages) + return packages unless package_type + raise InvalidPackageTypeError unless ::Packages::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 + + def filter_with_version(packages) + return packages if params[:include_versionless].present? + + packages.has_version + end + + def filter_by_status(packages) + return packages.displayable unless params[:status].present? + raise InvalidStatusError unless Package.statuses.key?(params[:status]) + + packages.with_status(params[:status]) + end end end diff --git a/app/finders/container_repositories_finder.rb b/app/finders/container_repositories_finder.rb index 5109efb361b..14e4d6799d8 100644 --- a/app/finders/container_repositories_finder.rb +++ b/app/finders/container_repositories_finder.rb @@ -14,7 +14,8 @@ class ContainerRepositoriesFinder return unless authorized? repositories = @subject.is_a?(Project) ? project_repositories : group_repositories - filter_by_image_name(repositories) + repositories = filter_by_image_name(repositories) + sort(repositories) end private @@ -39,6 +40,12 @@ class ContainerRepositoriesFinder repositories.search_by_name(@params[:name]) end + def sort(repositories) + return repositories unless @params[:sort] + + repositories.order_by(@params[:sort]) + end + def authorized? Ability.allowed?(@user, :read_container_image, @subject) end diff --git a/app/finders/deployments_finder.rb b/app/finders/deployments_finder.rb index 4038f93cf2d..89a28d9dfb8 100644 --- a/app/finders/deployments_finder.rb +++ b/app/finders/deployments_finder.rb @@ -1,57 +1,56 @@ # frozen_string_literal: true +# WARNING: This finder does not check permissions! +# +# Arguments: +# params: +# project: Project model - Find deployments for this project +# updated_after: DateTime +# updated_before: DateTime +# finished_after: DateTime +# finished_before: DateTime +# environment: String +# status: String (see Deployment.statuses) +# order_by: String (see ALLOWED_SORT_VALUES constant) +# sort: String (asc | desc) class DeploymentsFinder - attr_reader :project, :params + attr_reader :params - ALLOWED_SORT_VALUES = %w[id iid created_at updated_at ref].freeze + ALLOWED_SORT_VALUES = %w[id iid created_at updated_at ref finished_at].freeze DEFAULT_SORT_VALUE = 'id' ALLOWED_SORT_DIRECTIONS = %w[asc desc].freeze DEFAULT_SORT_DIRECTION = 'asc' - def initialize(project, params = {}) - @project = project + def initialize(params = {}) @params = params end def execute items = init_collection items = by_updated_at(items) + items = by_finished_at(items) items = by_environment(items) items = by_status(items) - sort(items) + items = preload_associations(items) + items = sort(items) + + items end private - # rubocop: disable CodeReuse/ActiveRecord def init_collection - project - .deployments - .includes( - :user, - environment: [], - deployable: { - job_artifacts: [], - pipeline: { - project: { - route: [], - namespace: :route - } - }, - project: { - namespace: :route - } - } - ) + if params[:project] + params[:project].deployments + else + Deployment.none + end end - # rubocop: enable CodeReuse/ActiveRecord - # rubocop: disable CodeReuse/ActiveRecord def sort(items) - items.order(sort_params) + items.order(sort_params) # rubocop: disable CodeReuse/ActiveRecord end - # rubocop: enable CodeReuse/ActiveRecord def by_updated_at(items) items = items.updated_before(params[:updated_before]) if params[:updated_before].present? @@ -60,6 +59,13 @@ class DeploymentsFinder items end + def by_finished_at(items) + items = items.finished_before(params[:finished_before]) if params[:finished_before].present? + items = items.finished_after(params[:finished_after]) if params[:finished_after].present? + + items + end + def by_environment(items) if params[:environment].present? items.for_environment_name(params[:environment]) @@ -87,4 +93,27 @@ class DeploymentsFinder sort_values['id'] = sort_values.delete('created_at') if sort_values['created_at'] # Sorting by `id` produces the same result as sorting by `created_at` end end + + # rubocop: disable CodeReuse/ActiveRecord + def preload_associations(scope) + scope.includes( + :user, + environment: [], + deployable: { + job_artifacts: [], + pipeline: { + project: { + route: [], + namespace: :route + } + }, + project: { + namespace: :route + } + } + ) + end + # rubocop: enable CodeReuse/ActiveRecord end + +DeploymentsFinder.prepend_if_ee('EE::DeploymentsFinder') diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb index 4358cf249f7..bedd6891d02 100644 --- a/app/finders/labels_finder.rb +++ b/app/finders/labels_finder.rb @@ -100,6 +100,10 @@ class LabelsFinder < UnionFinder strong_memoize(:group_ids) do groups = groups_to_include(group) + # Because we are sure that all groups are in the same hierarchy tree + # we can preset root group for all of them to optimize permission checks + Group.preset_root_ancestor_for(groups) + groups_user_can_read_labels(groups).map(&:id) end end @@ -173,7 +177,7 @@ class LabelsFinder < UnionFinder end if group? - @projects = if params[:include_subgroups] + @projects = if params[:include_descendant_groups] @projects.in_namespace(group.self_and_descendants.select(:id)) else @projects.in_namespace(group.id) diff --git a/app/finders/license_template_finder.rb b/app/finders/license_template_finder.rb index 4d68b963dc3..c4cb33235af 100644 --- a/app/finders/license_template_finder.rb +++ b/app/finders/license_template_finder.rb @@ -28,6 +28,10 @@ class LicenseTemplateFinder end end + def template_names + ::Gitlab::Template::BaseTemplate.template_names_by_category(vendored_licenses) + end + private def vendored_licenses @@ -36,6 +40,7 @@ class LicenseTemplateFinder LicenseTemplate.new( key: license.key, name: license.name, + project: project, nickname: license.nickname, category: (license.featured? ? :Popular : :Other), content: license.content, diff --git a/app/finders/merge_request/metrics_finder.rb b/app/finders/merge_request/metrics_finder.rb new file mode 100644 index 00000000000..d93e53d1636 --- /dev/null +++ b/app/finders/merge_request/metrics_finder.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +class MergeRequest::MetricsFinder + include Gitlab::Allowable + + def initialize(current_user, params = {}) + @current_user = current_user + @params = params + end + + def execute + return klass.none if target_project.blank? || user_not_authorized? + + items = init_collection + items = by_target_project(items) + items = by_merged_after(items) + items = by_merged_before(items) + + items + end + + private + + attr_reader :current_user, :params + + def by_target_project(items) + items.by_target_project(target_project) + end + + def by_merged_after(items) + return items unless merged_after + + items.merged_after(merged_after) + end + + def by_merged_before(items) + return items unless merged_before + + items.merged_before(merged_before) + end + + def user_not_authorized? + !can?(current_user, :read_merge_request, target_project) + end + + def init_collection + klass.all + end + + def klass + MergeRequest::Metrics + end + + def target_project + params[:target_project] + end + + def merged_after + params[:merged_after] + end + + def merged_before + params[:merged_before] + end +end diff --git a/app/finders/merge_requests/oldest_per_commit_finder.rb b/app/finders/merge_requests/oldest_per_commit_finder.rb new file mode 100644 index 00000000000..f50db43d7d2 --- /dev/null +++ b/app/finders/merge_requests/oldest_per_commit_finder.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module MergeRequests + # OldestPerCommitFinder is used to retrieve the oldest merge requests for + # every given commit, grouped per commit SHA. + # + # This finder is useful when you need to efficiently retrieve the first/oldest + # merge requests for multiple commits, and you want to do so in batches; + # instead of running a query for every commit. + class OldestPerCommitFinder + def initialize(project) + @project = project + end + + # Returns a Hash that maps a commit ID to the oldest merge request that + # introduced that commit. + def execute(commits) + id_rows = MergeRequestDiffCommit + .oldest_merge_request_id_per_commit(@project.id, commits.map(&:id)) + + mrs = MergeRequest + .preload_target_project + .id_in(id_rows.map { |r| r[:merge_request_id] }) + .index_by(&:id) + + id_rows.each_with_object({}) do |row, hash| + if (mr = mrs[row[:merge_request_id]]) + hash[row[:sha]] = mr + end + end + end + end +end diff --git a/app/finders/packages/group_packages_finder.rb b/app/finders/packages/group_packages_finder.rb index 860c4068b31..db5161d6e16 100644 --- a/app/finders/packages/group_packages_finder.rb +++ b/app/finders/packages/group_packages_finder.rb @@ -2,9 +2,7 @@ module Packages class GroupPackagesFinder - attr_reader :current_user, :group, :params - - InvalidPackageTypeError = Class.new(StandardError) + include ::Packages::FinderHelper def initialize(current_user, group, params = { exclude_subgroups: false, order_by: 'created_at', sort: 'asc' }) @current_user = current_user @@ -20,6 +18,8 @@ module Packages private + attr_reader :current_user, :group, :params + def packages_for_group_projects packages = ::Packages::Package .including_build_info @@ -32,6 +32,7 @@ module Packages packages = filter_with_version(packages) packages = filter_by_package_type(packages) packages = filter_by_package_name(packages) + packages = filter_by_status(packages) packages end @@ -46,10 +47,6 @@ module Packages .with_feature_available_for_user(:repository, current_user) end - def package_type - params[:package_type].presence - end - def groups return [group] if exclude_subgroups? @@ -59,24 +56,5 @@ module Packages 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 - - def filter_with_version(packages) - return packages if params[:include_versionless].present? - - packages.has_version - end end end diff --git a/app/finders/packages/nuget/package_finder.rb b/app/finders/packages/nuget/package_finder.rb index 8f585f045a1..2f66bd145ee 100644 --- a/app/finders/packages/nuget/package_finder.rb +++ b/app/finders/packages/nuget/package_finder.rb @@ -5,7 +5,7 @@ module Packages class PackageFinder include ::Packages::FinderHelper - MAX_PACKAGES_COUNT = 50 + MAX_PACKAGES_COUNT = 300 def initialize(current_user, project_or_group, package_name:, package_version: nil, limit: MAX_PACKAGES_COUNT) @current_user = current_user diff --git a/app/finders/packages/packages_finder.rb b/app/finders/packages/packages_finder.rb index 72a63224d2f..bd9e62e3f2a 100644 --- a/app/finders/packages/packages_finder.rb +++ b/app/finders/packages/packages_finder.rb @@ -2,7 +2,7 @@ module Packages class PackagesFinder - attr_reader :params, :project + include ::Packages::FinderHelper def initialize(project, params = {}) @project = project @@ -21,29 +21,14 @@ module Packages packages = filter_with_version(packages) packages = filter_by_package_type(packages) packages = filter_by_package_name(packages) + packages = filter_by_status(packages) packages = order_packages(packages) packages end private - def filter_with_version(packages) - return packages if params[:include_versionless].present? - - packages.has_version - end - - 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 + attr_reader :params, :project def order_packages(packages) packages.sort_by_attribute("#{params[:order_by]}_#{params[:sort]}") diff --git a/app/finders/repositories/commits_with_trailer_finder.rb b/app/finders/repositories/commits_with_trailer_finder.rb new file mode 100644 index 00000000000..4bd643c345b --- /dev/null +++ b/app/finders/repositories/commits_with_trailer_finder.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module Repositories + # Finder for obtaining commits between two refs, with a Git trailer set. + class CommitsWithTrailerFinder + # The maximum number of commits to retrieve per page. + # + # This value is arbitrarily chosen. Lowering it means more Gitaly calls, but + # less data being loaded into memory at once. Increasing it has the opposite + # effect. + # + # This amount is based around the number of commits that usually go in a + # GitLab release. Some examples for GitLab's own releases: + # + # * 13.6.0: 4636 commits + # * 13.5.0: 5912 commits + # * 13.4.0: 5541 commits + # + # Using this limit should result in most (very large) projects only needing + # 5-10 Gitaly calls, while keeping memory usage at a reasonable amount. + COMMITS_PER_PAGE = 1024 + + # The `project` argument specifies the project for which to obtain the + # commits. + # + # The `from` and `to` arguments specify the range of commits to include. The + # commit specified in `from` won't be included itself. The commit specified + # in `to` _is_ included. + # + # The `per_page` argument specifies how many commits are retrieved in a single + # Gitaly API call. + def initialize(project:, from:, to:, per_page: COMMITS_PER_PAGE) + @project = project + @from = from + @to = to + @per_page = per_page + end + + # Fetches all commits that have the given trailer set. + # + # The commits are yielded to the supplied block in batches. This allows + # other code to process these commits in batches too, instead of first + # having to load all commits into memory. + # + # Example: + # + # CommitsWithTrailerFinder.new(...).each_page('Signed-off-by') do |commits| + # commits.each do |commit| + # ... + # end + # end + def each_page(trailer) + return to_enum(__method__, trailer) unless block_given? + + offset = 0 + response = fetch_commits + + while response.any? + commits = [] + + response.each do |commit| + commits.push(commit) if commit.trailers.key?(trailer) + end + + yield commits + + offset += response.length + response = fetch_commits(offset) + end + end + + private + + def fetch_commits(offset = 0) + range = "#{@from}..#{@to}" + + @project + .repository + .commits(range, limit: @per_page, offset: offset, trailers: true) + end + end +end diff --git a/app/finders/repositories/previous_tag_finder.rb b/app/finders/repositories/previous_tag_finder.rb new file mode 100644 index 00000000000..150a6332c29 --- /dev/null +++ b/app/finders/repositories/previous_tag_finder.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Repositories + # A finder class for getting the tag of the last release before a given + # version. + # + # Imagine a project with the following tags: + # + # * v1.0.0 + # * v1.1.0 + # * v2.0.0 + # + # If the version supplied is 2.1.0, the tag returned will be v2.0.0. And when + # the version is 1.1.1, or 1.2.0, the returned tag will be v1.1.0. + # + # This finder expects that all tags to consider meet the following + # requirements: + # + # * They start with the letter "v" + # * They use semantic versioning for the tag format + # + # Tags not meeting these requirements are ignored. + class PreviousTagFinder + TAG_REGEX = /\Av(?#{Gitlab::Regex.unbounded_semver_regex})\z/.freeze + + def initialize(project) + @project = project + end + + def execute(new_version) + tags = {} + versions = [new_version] + + @project.repository.tags.each do |tag| + matches = tag.name.match(TAG_REGEX) + + next unless matches + + version = matches[:version] + tags[version] = tag + versions << version + end + + VersionSorter.sort!(versions) + + index = versions.index(new_version) + + tags[versions[index - 1]] if index&.positive? + end + end +end diff --git a/app/finders/template_finder.rb b/app/finders/template_finder.rb index dac7c526474..36f8d144908 100644 --- a/app/finders/template_finder.rb +++ b/app/finders/template_finder.rb @@ -21,6 +21,18 @@ class TemplateFinder new(type, project, params) end end + + def all_template_names(project, type) + return {} if !VENDORED_TEMPLATES.key?(type.to_s) && type.to_s != 'licenses' + + build(type, project).template_names + end + + # This is issues and merge requests description templates only. + # This will be removed once we introduce group level inherited templates + def all_template_names_array(project, type) + all_template_names(project, type).values.flatten.uniq + end end attr_reader :type, :project, :params @@ -43,6 +55,10 @@ class TemplateFinder vendored_templates.all(project) end end + + def template_names + vendored_templates.template_names(project) + end end TemplateFinder.prepend_if_ee('::EE::TemplateFinder') diff --git a/app/finders/terraform/states_finder.rb b/app/finders/terraform/states_finder.rb new file mode 100644 index 00000000000..bbe90fead2b --- /dev/null +++ b/app/finders/terraform/states_finder.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Terraform + class StatesFinder + def initialize(project, current_user, params: {}) + @project = project + @current_user = current_user + @params = params + end + + def execute + return ::Terraform::State.none unless can_read_terraform_states? + + states = project.terraform_states + states = states.with_name(params[:name]) if params[:name].present? + + states.ordered_by_name + end + + private + + attr_reader :project, :current_user, :params + + def can_read_terraform_states? + current_user.can?(:read_terraform_state, project) + end + end +end diff --git a/app/finders/user_recent_events_finder.rb b/app/finders/user_recent_events_finder.rb index f376b26ab9c..596a413782e 100644 --- a/app/finders/user_recent_events_finder.rb +++ b/app/finders/user_recent_events_finder.rb @@ -15,40 +15,47 @@ class UserRecentEventsFinder requires_cross_project_access - attr_reader :current_user, :target_user, :params + attr_reader :current_user, :target_user, :params, :event_filter DEFAULT_LIMIT = 20 MAX_LIMIT = 100 - def initialize(current_user, target_user, params = {}) + def initialize(current_user, target_user, event_filter, params = {}) @current_user = current_user @target_user = target_user @params = params + @event_filter = event_filter || EventFilter.new(EventFilter::ALL) end - # rubocop: disable CodeReuse/ActiveRecord def execute + if target_user.is_a? User + execute_single + else + execute_multi + end + end + + private + + def execute_single return Event.none unless can?(current_user, :read_user_profile, target_user) - recent_events(params[:offset] || 0) - .joins(:project) + event_filter.apply_filter(target_events .with_associations .limit_recent(limit, params[:offset]) + .order_created_desc) end - # rubocop: enable CodeReuse/ActiveRecord - - private # rubocop: disable CodeReuse/ActiveRecord - def recent_events(offset) - sql = <<~SQL - (#{projects}) AS projects_for_join - JOIN (#{target_events.to_sql}) AS #{Event.table_name} - ON #{Event.table_name}.project_id = projects_for_join.id - SQL + def execute_multi + users = [] + @target_user.each do |user| + users.append(user.id) if can?(current_user, :read_user_profile, user) + end + + return Event.none if users.empty? - # Workaround for https://github.com/rails/rails/issues/24193 - Event.from([Arel.sql(sql)]) + event_filter.apply_filter(Event.where(author: users).limit_recent(limit, params[:offset] || 0)) end # rubocop: enable CodeReuse/ActiveRecord @@ -58,10 +65,6 @@ class UserRecentEventsFinder end # rubocop: enable CodeReuse/ActiveRecord - def projects - target_user.project_interactions.to_sql - end - def limit return DEFAULT_LIMIT unless params[:limit].present? -- cgit v1.2.3