From 7d2859e98bd58f6a3b11db6718fe63d95f692b06 Mon Sep 17 00:00:00 2001 From: Andreas Brandl Date: Thu, 1 Mar 2018 12:26:45 +0100 Subject: [PATCH] Leverage user_contributed_projects to find recent events. Closes #40525. --- app/finders/user_recent_events_finder.rb | 45 ++++++++++++++++--- app/models/user.rb | 4 +- .../40525-listing-user-activity-timeouts.yml | 5 +++ spec/models/user_spec.rb | 1 - 4 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/40525-listing-user-activity-timeouts.yml diff --git a/app/finders/user_recent_events_finder.rb b/app/finders/user_recent_events_finder.rb index 6f7f7c30d92..65d6e019746 100644 --- a/app/finders/user_recent_events_finder.rb +++ b/app/finders/user_recent_events_finder.rb @@ -12,6 +12,8 @@ class UserRecentEventsFinder attr_reader :current_user, :target_user, :params + LIMIT = 20 + def initialize(current_user, target_user, params = {}) @current_user = current_user @target_user = target_user @@ -19,15 +21,44 @@ class UserRecentEventsFinder end def execute - target_user - .recent_events - .merge(projects_for_current_user) - .references(:project) + recent_events(params[:offset] || 0) + .joins(:project) .with_associations - .limit_recent(20, params[:offset]) + .limit_recent(LIMIT, params[:offset]) end - def projects_for_current_user - ProjectsFinder.new(current_user: current_user).execute + private + + 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 + + # Workaround for https://github.com/rails/rails/issues/24193 + Event.from([Arel.sql(sql)]) + end + + def target_events + Event.where(author: target_user) + end + + def projects + # Compile a list of projects `current_user` interacted with + # and `target_user` is allowed to see. + + authorized = target_user + .project_interactions + .joins(:project_authorizations) + .where(project_authorizations: { user: current_user }) + .select(:id) + + visible = target_user + .project_interactions + .where(visibility_level: [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]) + .select(:id) + + Gitlab::SQL::Union.new([authorized, visible]).to_sql end end diff --git a/app/models/user.rb b/app/models/user.rb index 9c60adf0c90..29d8fd07259 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -114,13 +114,15 @@ class User < ActiveRecord::Base has_many :project_authorizations has_many :authorized_projects, through: :project_authorizations, source: :project + has_many :user_interacted_projects + has_many :project_interactions, through: :user_interacted_projects, source: :project, class_name: 'Project' + has_many :snippets, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent has_many :notes, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent has_many :issues, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent has_many :merge_requests, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent has_many :events, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent has_many :subscriptions, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent - has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event" has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_one :abuse_report, dependent: :destroy, foreign_key: :user_id # rubocop:disable Cop/ActiveRecordDependent has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" # rubocop:disable Cop/ActiveRecordDependent diff --git a/changelogs/unreleased/40525-listing-user-activity-timeouts.yml b/changelogs/unreleased/40525-listing-user-activity-timeouts.yml new file mode 100644 index 00000000000..39ce873dba6 --- /dev/null +++ b/changelogs/unreleased/40525-listing-user-activity-timeouts.yml @@ -0,0 +1,5 @@ +--- +title: Improve database response time for user activity listing. +merge_request: 17454 +author: +type: performance diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 00b5226d874..5680eb24985 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -27,7 +27,6 @@ describe User do it { is_expected.to have_many(:keys).dependent(:destroy) } it { is_expected.to have_many(:deploy_keys).dependent(:destroy) } it { is_expected.to have_many(:events).dependent(:destroy) } - it { is_expected.to have_many(:recent_events).class_name('Event') } it { is_expected.to have_many(:issues).dependent(:destroy) } it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:merge_requests).dependent(:destroy) }