Store discussion_id on Note for faster discussion lookup.
This commit is contained in:
parent
f3acf9fd24
commit
4a13aa9f34
13 changed files with 191 additions and 47 deletions
|
@ -5,8 +5,6 @@ class Projects::DiscussionsController < Projects::ApplicationController
|
||||||
before_action :authorize_resolve_discussion!
|
before_action :authorize_resolve_discussion!
|
||||||
|
|
||||||
def resolve
|
def resolve
|
||||||
return render_404 unless discussion.resolvable?
|
|
||||||
|
|
||||||
discussion.resolve!(current_user)
|
discussion.resolve!(current_user)
|
||||||
|
|
||||||
MergeRequests::ResolvedDiscussionNotificationService.new(project, current_user).execute(merge_request)
|
MergeRequests::ResolvedDiscussionNotificationService.new(project, current_user).execute(merge_request)
|
||||||
|
@ -18,8 +16,6 @@ class Projects::DiscussionsController < Projects::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def unresolve
|
def unresolve
|
||||||
return render_404 unless discussion.resolvable?
|
|
||||||
|
|
||||||
discussion.unresolve!
|
discussion.unresolve!
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
|
@ -34,7 +30,7 @@ class Projects::DiscussionsController < Projects::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussion
|
def discussion
|
||||||
@discussion ||= @merge_request.find_discussion(params[:id]) || render_404
|
@discussion ||= @merge_request.find_diff_discussion(params[:id]) || render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_resolve_discussion!
|
def authorize_resolve_discussion!
|
||||||
|
|
|
@ -49,7 +49,7 @@ module NotesHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
if use_legacy_diff_note
|
if use_legacy_diff_note
|
||||||
discussion_id = LegacyDiffNote.build_discussion_id(
|
discussion_id = LegacyDiffNote.discussion_id(
|
||||||
@comments_target[:noteable_type],
|
@comments_target[:noteable_type],
|
||||||
@comments_target[:noteable_id] || @comments_target[:commit_id],
|
@comments_target[:noteable_id] || @comments_target[:commit_id],
|
||||||
line_code
|
line_code
|
||||||
|
@ -57,10 +57,10 @@ module NotesHelper
|
||||||
|
|
||||||
data.merge!(
|
data.merge!(
|
||||||
note_type: LegacyDiffNote.name,
|
note_type: LegacyDiffNote.name,
|
||||||
discussion_id: Digest::SHA1.hexdigest(discussion_id)
|
discussion_id: discussion_id
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
discussion_id = DiffNote.build_discussion_id(
|
discussion_id = DiffNote.discussion_id(
|
||||||
@comments_target[:noteable_type],
|
@comments_target[:noteable_type],
|
||||||
@comments_target[:noteable_id] || @comments_target[:commit_id],
|
@comments_target[:noteable_id] || @comments_target[:commit_id],
|
||||||
position
|
position
|
||||||
|
@ -69,7 +69,7 @@ module NotesHelper
|
||||||
data.merge!(
|
data.merge!(
|
||||||
position: position.to_json,
|
position: position.to_json,
|
||||||
note_type: DiffNote.name,
|
note_type: DiffNote.name,
|
||||||
discussion_id: Digest::SHA1.hexdigest(discussion_id)
|
discussion_id: discussion_id
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,9 @@ class DiffNote < Note
|
||||||
validate :positions_complete
|
validate :positions_complete
|
||||||
validate :verify_supported
|
validate :verify_supported
|
||||||
|
|
||||||
|
after_initialize :ensure_original_discussion_id
|
||||||
before_validation :set_original_position, :update_position, on: :create
|
before_validation :set_original_position, :update_position, on: :create
|
||||||
before_validation :set_line_code
|
before_validation :set_line_code, :set_original_discussion_id
|
||||||
after_save :keep_around_commits
|
after_save :keep_around_commits
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
@ -33,14 +34,6 @@ class DiffNote < Note
|
||||||
{ position: position.to_json }
|
{ position: position.to_json }
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussion_id
|
|
||||||
@discussion_id ||= Digest::SHA1.hexdigest(self.class.build_discussion_id(noteable_type, noteable_id || commit_id, position))
|
|
||||||
end
|
|
||||||
|
|
||||||
def original_discussion_id
|
|
||||||
@original_discussion_id ||= Digest::SHA1.hexdigest(self.class.build_discussion_id(noteable_type, noteable_id || commit_id, original_position))
|
|
||||||
end
|
|
||||||
|
|
||||||
def position=(new_position)
|
def position=(new_position)
|
||||||
if new_position.is_a?(String)
|
if new_position.is_a?(String)
|
||||||
new_position = JSON.parse(new_position) rescue nil
|
new_position = JSON.parse(new_position) rescue nil
|
||||||
|
@ -106,11 +99,7 @@ class DiffNote < Note
|
||||||
def discussion
|
def discussion
|
||||||
return unless resolvable?
|
return unless resolvable?
|
||||||
|
|
||||||
discussion_notes = self.noteable.notes.fresh.select { |n| n.discussion_id == self.discussion_id }
|
self.noteable.find_diff_discussion(self.discussion_id)
|
||||||
|
|
||||||
return if discussion_notes.empty?
|
|
||||||
|
|
||||||
Discussion.new(discussion_notes)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_discussion
|
def to_discussion
|
||||||
|
@ -139,6 +128,26 @@ class DiffNote < Note
|
||||||
self.line_code = self.position.line_code(self.project.repository)
|
self.line_code = self.position.line_code(self.project.repository)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ensure_original_discussion_id
|
||||||
|
return unless self.persisted?
|
||||||
|
return if self.original_discussion_id
|
||||||
|
|
||||||
|
set_original_discussion_id
|
||||||
|
update_column(:original_discussion_id, self.original_discussion_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_original_discussion_id
|
||||||
|
self.original_discussion_id = Digest::SHA1.hexdigest(build_original_discussion_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_discussion_id
|
||||||
|
self.class.build_discussion_id(noteable_type, noteable_id || commit_id, position)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_original_discussion_id
|
||||||
|
self.class.build_discussion_id(noteable_type, noteable_id || commit_id, original_position)
|
||||||
|
end
|
||||||
|
|
||||||
def update_position
|
def update_position
|
||||||
return unless supported?
|
return unless supported?
|
||||||
return if for_commit?
|
return if for_commit?
|
||||||
|
|
|
@ -93,7 +93,7 @@ class Discussion
|
||||||
return false unless resolvable?
|
return false unless resolvable?
|
||||||
|
|
||||||
current_user == self.noteable.author ||
|
current_user == self.noteable.author ||
|
||||||
current_user.can?(:push_code, self.project)
|
current_user.can?(:resolve_note, self.project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve!(current_user)
|
def resolve!(current_user)
|
||||||
|
|
|
@ -8,8 +8,8 @@ class LegacyDiffNote < Note
|
||||||
before_create :set_diff
|
before_create :set_diff
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def build_discussion_id(noteable_type, noteable_id, line_code, active = true)
|
def build_discussion_id(noteable_type, noteable_id, line_code)
|
||||||
[super(noteable_type, noteable_id), line_code, active].join("-")
|
[super(noteable_type, noteable_id), line_code].join("-")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -21,10 +21,6 @@ class LegacyDiffNote < Note
|
||||||
{ line_code: line_code }
|
{ line_code: line_code }
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussion_id
|
|
||||||
@discussion_id ||= Digest::SHA1.hexdigest(self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code))
|
|
||||||
end
|
|
||||||
|
|
||||||
def project_repository
|
def project_repository
|
||||||
if RequestStore.active?
|
if RequestStore.active?
|
||||||
RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
|
RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
|
||||||
|
@ -119,4 +115,8 @@ class LegacyDiffNote < Note
|
||||||
diffs = noteable.raw_diffs(Commit.max_diff_options)
|
diffs = noteable.raw_diffs(Commit.max_diff_options)
|
||||||
diffs.find { |d| d.new_path == self.diff.new_path }
|
diffs.find { |d| d.new_path == self.diff.new_path }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_discussion_id
|
||||||
|
self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -425,16 +425,23 @@ class MergeRequest < ActiveRecord::Base
|
||||||
discussions
|
discussions
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_discussion(discussion_id)
|
def diff_discussions
|
||||||
discussions.find { |d| d.id == discussion_id }
|
@diff_discussions ||= self.notes.diff_notes.discussions
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_diff_discussion(discussion_id)
|
||||||
|
notes = self.notes.diff_notes.where(discussion_id: discussion_id).fresh.to_a
|
||||||
|
return if notes.empty?
|
||||||
|
|
||||||
|
Discussion.new(notes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussions_resolvable?
|
def discussions_resolvable?
|
||||||
discussions.any?(&:resolvable?)
|
diff_discussions.any?(&:resolvable?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussions_resolved?
|
def discussions_resolved?
|
||||||
discussions_resolvable? && discussions.none?(&:to_be_resolved?)
|
discussions_resolvable? && diff_discussions.none?(&:to_be_resolved?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def hook_attrs
|
def hook_attrs
|
||||||
|
|
|
@ -70,7 +70,9 @@ class Note < ActiveRecord::Base
|
||||||
project: [:project_members, { group: [:group_members] }])
|
project: [:project_members, { group: [:group_members] }])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
after_initialize :ensure_discussion_id
|
||||||
before_validation :nullify_blank_type, :nullify_blank_line_code
|
before_validation :nullify_blank_type, :nullify_blank_line_code
|
||||||
|
before_validation :set_discussion_id
|
||||||
after_save :keep_around_commit
|
after_save :keep_around_commit
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
@ -82,6 +84,10 @@ class Note < ActiveRecord::Base
|
||||||
[:discussion, noteable_type.try(:underscore), noteable_id].join("-")
|
[:discussion, noteable_type.try(:underscore), noteable_id].join("-")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.discussion_id(*args)
|
||||||
|
Digest::SHA1.hexdigest(build_discussion_id(*args))
|
||||||
|
end
|
||||||
|
|
||||||
def discussions
|
def discussions
|
||||||
Discussion.for_notes(all)
|
Discussion.for_notes(all)
|
||||||
end
|
end
|
||||||
|
@ -142,15 +148,6 @@ class Note < ActiveRecord::Base
|
||||||
resolvable? && !resolved?
|
resolvable? && !resolved?
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussion_id
|
|
||||||
@discussion_id ||=
|
|
||||||
if for_merge_request?
|
|
||||||
Digest::SHA1.hexdigest([:discussion, :note, id].join("-"))
|
|
||||||
else
|
|
||||||
Digest::SHA1.hexdigest(self.class.build_discussion_id(noteable_type, noteable_id || commit_id))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def max_attachment_size
|
def max_attachment_size
|
||||||
current_application_settings.max_attachment_size.megabytes.to_i
|
current_application_settings.max_attachment_size.megabytes.to_i
|
||||||
end
|
end
|
||||||
|
@ -256,4 +253,24 @@ class Note < ActiveRecord::Base
|
||||||
def nullify_blank_line_code
|
def nullify_blank_line_code
|
||||||
self.line_code = nil if self.line_code.blank?
|
self.line_code = nil if self.line_code.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ensure_discussion_id
|
||||||
|
return unless self.persisted?
|
||||||
|
return if self.discussion_id
|
||||||
|
|
||||||
|
set_discussion_id
|
||||||
|
update_column(:discussion_id, self.discussion_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_discussion_id
|
||||||
|
self.discussion_id = Digest::SHA1.hexdigest(build_discussion_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_discussion_id
|
||||||
|
if for_merge_request?
|
||||||
|
[:discussion, :note, id].join("-")
|
||||||
|
else
|
||||||
|
self.class.build_discussion_id(noteable_type, noteable_id || commit_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
13
db/migrate/20160817154936_add_discussion_ids_to_notes.rb
Normal file
13
db/migrate/20160817154936_add_discussion_ids_to_notes.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||||
|
# for more information on how to write migrations for GitLab.
|
||||||
|
|
||||||
|
class AddDiscussionIdsToNotes < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_column :notes, :discussion_id, :string
|
||||||
|
add_column :notes, :original_discussion_id, :string
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20160810142633) do
|
ActiveRecord::Schema.define(version: 20160817154936) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -671,6 +671,8 @@ ActiveRecord::Schema.define(version: 20160810142633) do
|
||||||
t.text "original_position"
|
t.text "original_position"
|
||||||
t.datetime "resolved_at"
|
t.datetime "resolved_at"
|
||||||
t.integer "resolved_by_id"
|
t.integer "resolved_by_id"
|
||||||
|
t.string "discussion_id"
|
||||||
|
t.string "original_discussion_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
|
add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
|
||||||
|
|
|
@ -434,4 +434,54 @@ describe DiffNote, models: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#discussion_id" do
|
||||||
|
let(:note) { create(:diff_note_on_merge_request) }
|
||||||
|
|
||||||
|
context "when it is newly created" do
|
||||||
|
it "has a discussion id" do
|
||||||
|
expect(note.discussion_id).not_to be_nil
|
||||||
|
expect(note.discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when it didn't store a discussion id before" do
|
||||||
|
before do
|
||||||
|
note.update_column(:discussion_id, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has a discussion id" do
|
||||||
|
# The discussion_id is set in `after_initialize`, so `reload` won't work
|
||||||
|
reloaded_note = Note.find(note.id)
|
||||||
|
|
||||||
|
expect(reloaded_note.discussion_id).not_to be_nil
|
||||||
|
expect(reloaded_note.discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#original_discussion_id" do
|
||||||
|
let(:note) { create(:diff_note_on_merge_request) }
|
||||||
|
|
||||||
|
context "when it is newly created" do
|
||||||
|
it "has a discussion id" do
|
||||||
|
expect(note.original_discussion_id).not_to be_nil
|
||||||
|
expect(note.original_discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when it didn't store a discussion id before" do
|
||||||
|
before do
|
||||||
|
note.update_column(:original_discussion_id, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has a discussion id" do
|
||||||
|
# The original_discussion_id is set in `after_initialize`, so `reload` won't work
|
||||||
|
reloaded_note = Note.find(note.id)
|
||||||
|
|
||||||
|
expect(reloaded_note.original_discussion_id).not_to be_nil
|
||||||
|
expect(reloaded_note.original_discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -73,4 +73,29 @@ describe LegacyDiffNote, models: true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#discussion_id" do
|
||||||
|
let(:note) { create(:note) }
|
||||||
|
|
||||||
|
context "when it is newly created" do
|
||||||
|
it "has a discussion id" do
|
||||||
|
expect(note.discussion_id).not_to be_nil
|
||||||
|
expect(note.discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when it didn't store a discussion id before" do
|
||||||
|
before do
|
||||||
|
note.update_column(:discussion_id, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has a discussion id" do
|
||||||
|
# The discussion_id is set in `after_initialize`, so `reload` won't work
|
||||||
|
reloaded_note = Note.find(note.id)
|
||||||
|
|
||||||
|
expect(reloaded_note.discussion_id).not_to be_nil
|
||||||
|
expect(reloaded_note.discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -763,7 +763,7 @@ describe MergeRequest, models: true do
|
||||||
let(:third_discussion) { Discussion.new([create(:diff_note_on_merge_request)]) }
|
let(:third_discussion) { Discussion.new([create(:diff_note_on_merge_request)]) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(subject).to receive(:discussions).and_return([first_discussion, second_discussion, third_discussion])
|
allow(subject).to receive(:diff_discussions).and_return([first_discussion, second_discussion, third_discussion])
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#discussions_resolvable?" do
|
describe "#discussions_resolvable?" do
|
||||||
|
|
|
@ -321,4 +321,29 @@ describe Note, models: true do
|
||||||
expect(subject[active_diff_note3.line_code].id).to eq(active_diff_note3.discussion_id)
|
expect(subject[active_diff_note3.line_code].id).to eq(active_diff_note3.discussion_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#discussion_id" do
|
||||||
|
let(:note) { create(:note) }
|
||||||
|
|
||||||
|
context "when it is newly created" do
|
||||||
|
it "has a discussion id" do
|
||||||
|
expect(note.discussion_id).not_to be_nil
|
||||||
|
expect(note.discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when it didn't store a discussion id before" do
|
||||||
|
before do
|
||||||
|
note.update_column(:discussion_id, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has a discussion id" do
|
||||||
|
# The discussion_id is set in `after_initialize`, so `reload` won't work
|
||||||
|
reloaded_note = Note.find(note.id)
|
||||||
|
|
||||||
|
expect(reloaded_note.discussion_id).not_to be_nil
|
||||||
|
expect(reloaded_note.discussion_id).to match(/\A\h{40}\z/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue