Commit 43b74afd authored by Andreas Brandl's avatar Andreas Brandl

Rename to UserInteractedProjects.

This is to avoid a mix-up with the existing concept of 'user
contributions'. See `User#contributed_projects` or
`Event#contributions`.
parent 986f470d
......@@ -65,7 +65,7 @@ class Event < ActiveRecord::Base
# Callbacks
after_create :reset_project_activity
after_create :set_last_repository_updated_at, if: :push?
after_create :track_user_contributed_projects
after_create :track_user_interacted_projects
# Scopes
scope :recent, -> { reorder(id: :desc) }
......@@ -391,10 +391,10 @@ class Event < ActiveRecord::Base
.update_all(last_repository_updated_at: created_at)
end
def track_user_contributed_projects
def track_user_interacted_projects
# Note the call to .available? is due to earlier migrations
# that would otherwise conflict with the call to .track
# (because the table does not exist yet).
UserContributedProjects.track(self) if UserContributedProjects.available?
UserInteractedProjects.track(self) if UserInteractedProjects.available?
end
end
class UserContributedProjects < ActiveRecord::Base
class UserInteractedProjects < ActiveRecord::Base
belongs_to :user
belongs_to :project
......@@ -52,7 +52,7 @@ class UserContributedProjects < ActiveRecord::Base
private
def cached_exists?(project_id:, user_id:, &block)
cache_key = "user_contributed_projects:#{project_id}:#{user_id}"
cache_key = "user_interacted_projects:#{project_id}:#{user_id}"
Rails.cache.fetch(cache_key, expires_in: CACHE_EXPIRY_TIME, &block)
end
end
......
---
title: Keep track of projects a user contributed to.
title: Keep track of projects a user interacted with.
merge_request: 17327
author:
type: other
class CreateUserContributedProjectsTable < ActiveRecord::Migration
class CreateUserInteractedProjectsTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
......@@ -6,16 +6,16 @@ class CreateUserContributedProjectsTable < ActiveRecord::Migration
disable_ddl_transaction!
def up
create_table :user_contributed_projects, id: false do |t|
create_table :user_interacted_projects, id: false do |t|
t.references :user, null: false
t.references :project, null: false
end
add_concurrent_foreign_key :user_contributed_projects, :users, column: :user_id, on_delete: :cascade
add_concurrent_foreign_key :user_contributed_projects, :projects, column: :project_id, on_delete: :cascade
add_concurrent_foreign_key :user_interacted_projects, :users, column: :user_id, on_delete: :cascade
add_concurrent_foreign_key :user_interacted_projects, :projects, column: :project_id, on_delete: :cascade
end
def down
drop_table :user_contributed_projects
drop_table :user_interacted_projects
end
end
class BuildUserContributedProjectsTable < ActiveRecord::Migration
class BuildUserInteractedProjectsTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
......@@ -13,13 +13,13 @@ class BuildUserContributedProjectsTable < ActiveRecord::Migration
MysqlStrategy.new
end.up
add_concurrent_index :user_contributed_projects, [:project_id, :user_id], unique: true
add_concurrent_index :user_interacted_projects, [:project_id, :user_id], unique: true
end
def down
execute "TRUNCATE user_contributed_projects"
execute "TRUNCATE user_interacted_projects"
remove_concurrent_index_by_name :user_contributed_projects, 'index_user_contributed_projects_on_project_id_and_user_id'
remove_concurrent_index_by_name :user_interacted_projects, 'index_user_interacted_projects_on_project_id_and_user_id'
end
private
......@@ -31,22 +31,22 @@ class BuildUserContributedProjectsTable < ActiveRecord::Migration
SLEEP_TIME = 5
def up
with_index(:events, [:author_id, :project_id], name: 'events_user_contributions_temp', where: 'project_id IS NOT NULL') do
with_index(:events, [:author_id, :project_id], name: 'events_user_interactions_temp', where: 'project_id IS NOT NULL') do
iteration = 0
records = 0
begin
Rails.logger.info "Building user_contributed_projects table, batch ##{iteration}"
Rails.logger.info "Building user_interacted_projects table, batch ##{iteration}"
result = execute <<~SQL
INSERT INTO user_contributed_projects (user_id, project_id)
INSERT INTO user_interacted_projects (user_id, project_id)
SELECT e.user_id, e.project_id
FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
LEFT JOIN user_contributed_projects ucp USING (user_id, project_id)
LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
WHERE ucp.user_id IS NULL
LIMIT #{BATCH_SIZE}
SQL
iteration += 1
records += result.cmd_tuples
Rails.logger.info "Building user_contributed_projects table, batch ##{iteration} complete, created #{records} overall"
Rails.logger.info "Building user_interacted_projects table, batch ##{iteration} complete, created #{records} overall"
Kernel.sleep(SLEEP_TIME) if result.cmd_tuples > 0
rescue ActiveRecord::InvalidForeignKey => e
Rails.logger.info "Retry on InvalidForeignKey: #{e}"
......@@ -54,7 +54,7 @@ class BuildUserContributedProjectsTable < ActiveRecord::Migration
end while result.cmd_tuples > 0
end
execute "ANALYZE user_contributed_projects"
execute "ANALYZE user_interacted_projects"
end
......@@ -73,10 +73,10 @@ class BuildUserContributedProjectsTable < ActiveRecord::Migration
def up
execute <<~SQL
INSERT INTO user_contributed_projects (user_id, project_id)
INSERT INTO user_interacted_projects (user_id, project_id)
SELECT e.user_id, e.project_id
FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
LEFT JOIN user_contributed_projects ucp USING (user_id, project_id)
LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
WHERE ucp.user_id IS NULL
SQL
end
......
......@@ -1815,13 +1815,6 @@ ActiveRecord::Schema.define(version: 20180304204842) do
add_index "user_callouts", ["user_id", "feature_name"], name: "index_user_callouts_on_user_id_and_feature_name", unique: true, using: :btree
add_index "user_callouts", ["user_id"], name: "index_user_callouts_on_user_id", using: :btree
create_table "user_contributed_projects", id: false, force: :cascade do |t|
t.integer "user_id", null: false
t.integer "project_id", null: false
end
add_index "user_contributed_projects", ["project_id", "user_id"], name: "index_user_contributed_projects_on_project_id_and_user_id", unique: true, using: :btree
create_table "user_custom_attributes", force: :cascade do |t|
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
......@@ -1833,6 +1826,13 @@ ActiveRecord::Schema.define(version: 20180304204842) do
add_index "user_custom_attributes", ["key", "value"], name: "index_user_custom_attributes_on_key_and_value", using: :btree
add_index "user_custom_attributes", ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true, using: :btree
create_table "user_interacted_projects", id: false, force: :cascade do |t|
t.integer "user_id", null: false
t.integer "project_id", null: false
end
add_index "user_interacted_projects", ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree
create_table "user_synced_attributes_metadata", force: :cascade do |t|
t.boolean "name_synced", default: false
t.boolean "email_synced", default: false
......@@ -2101,9 +2101,9 @@ ActiveRecord::Schema.define(version: 20180304204842) do
add_foreign_key "trending_projects", "projects", on_delete: :cascade
add_foreign_key "u2f_registrations", "users"
add_foreign_key "user_callouts", "users", on_delete: :cascade
add_foreign_key "user_contributed_projects", "projects", name: "fk_6fe26e92ae", on_delete: :cascade
add_foreign_key "user_contributed_projects", "users", name: "fk_285db038d3", on_delete: :cascade
add_foreign_key "user_custom_attributes", "users", on_delete: :cascade
add_foreign_key "user_interacted_projects", "projects", name: "fk_722ceba4f7", on_delete: :cascade
add_foreign_key "user_interacted_projects", "users", name: "fk_0894651f08", on_delete: :cascade
add_foreign_key "user_synced_attributes_metadata", "users", on_delete: :cascade
add_foreign_key "users_star_projects", "projects", name: "fk_22cd27ddfc", on_delete: :cascade
add_foreign_key "web_hook_logs", "web_hooks", on_delete: :cascade
......
......@@ -50,18 +50,18 @@ describe Event do
end
end
describe 'after_create :track_user_contributed_projects' do
describe 'after_create :track_user_interacted_projects' do
let(:event) { build(:push_event, project: project, author: project.owner) }
it 'passes event to UserContributedProjects.track' do
expect(UserContributedProjects).to receive(:available?).and_return(true)
expect(UserContributedProjects).to receive(:track).with(event)
it 'passes event to UserInteractedProjects.track' do
expect(UserInteractedProjects).to receive(:available?).and_return(true)
expect(UserInteractedProjects).to receive(:track).with(event)
event.save
end
it 'does not call UserContributedProjects.track if its not yet available' do
expect(UserContributedProjects).to receive(:available?).and_return(false)
expect(UserContributedProjects).not_to receive(:track)
it 'does not call UserInteractedProjects.track if its not yet available' do
expect(UserInteractedProjects).to receive(:available?).and_return(false)
expect(UserInteractedProjects).not_to receive(:track)
event.save
end
end
......
require 'spec_helper'
describe UserContributedProjects do
describe UserInteractedProjects do
describe '.track' do
subject { described_class.track(event) }
let(:event) { build(:event) }
......
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