GitLab wurde erfolgreich aktualisiert. Durch regelmäßige Updates bleibt das THM GitLab sicher. Danke für Ihre Geduld.

Unverified Commit 21e10888 authored by Douwe Maan's avatar Douwe Maan Committed by Luke "Jared" Bennett

Address review comments

parent fe26b8af
module RendersNotes
def prepare_notes_for_rendering(notes)
preload_noteable_for_regular_notes(notes)
preload_max_access_for_authors(notes, @project)
Banzai::NoteRenderer.render(notes, @project, current_user)
notes
end
private
def preload_max_access_for_authors(notes, project)
user_ids = notes.map(&:author_id)
project.team.max_member_access_for_user_ids(user_ids)
end
def preload_noteable_for_regular_notes(notes)
ActiveRecord::Associations::Preloader.new.preload(notes.reject(&:for_commit?), :noteable)
end
end
......@@ -2,7 +2,7 @@
#
# Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController
include NotesHelper
include RendersNotes
include CreatesCommit
include DiffForPath
include DiffHelper
......
class Projects::IssuesController < Projects::ApplicationController
include NotesHelper
include RendersNotes
include ToggleSubscriptionAction
include IssuableActions
include ToggleAwardEmoji
......
......@@ -3,7 +3,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include DiffForPath
include DiffHelper
include IssuableActions
include NotesHelper
include RendersNotes
include ToggleAwardEmoji
include IssuableCollections
......
class Projects::NotesController < Projects::ApplicationController
include NotesHelper
include RendersNotes
include ToggleAwardEmoji
# Authorize
......
class Projects::SnippetsController < Projects::ApplicationController
include NotesHelper
include RendersNotes
include ToggleAwardEmoji
include SpammableActions
include SnippetsActions
......
......@@ -20,9 +20,9 @@ def initialize(project, current_user, params = {})
end
def execute
@notes = init_collection
@notes = since_fetch_at(@params[:last_fetched_at], @notes) if @params[:last_fetched_at]
@notes
notes = init_collection
notes = since_fetch_at(notes)
notes.fresh
end
def target
......@@ -56,7 +56,7 @@ def init_collection
def notes_of_any_type
types = %w(commit issue merge_request snippet)
note_relations = types.map { |t| notes_for_type(t) }
note_relations.map! { |notes| search(@params[:search], notes) } if @params[:search]
note_relations.map! { |notes| search(notes) }
UnionFinder.new.find_union(note_relations, Note)
end
......@@ -98,16 +98,21 @@ def notes_on_target
#
# This method uses ILIKE on PostgreSQL and LIKE on MySQL.
#
def search(query, notes_relation = @notes)
def search(query, notes)
query = @params[:search]
return unless query
pattern = "%#{query}%"
notes_relation.where(Note.arel_table[:note].matches(pattern))
notes.where(Note.arel_table[:note].matches(pattern))
end
# Notes changed since last fetch
# Uses overlapping intervals to avoid worrying about race conditions
def since_fetch_at(fetch_time, notes_relation = @notes)
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_relation.where('updated_at > ?', last_fetched_at - FETCH_OVERLAP).fresh
notes.updated_after(last_fetched_at - FETCH_OVERLAP)
end
end
......@@ -57,23 +57,6 @@ def link_to_reply_discussion(discussion, line_type = nil)
data: data, title: 'Add a reply'
end
def preload_max_access_for_authors(notes, project)
user_ids = notes.map(&:author_id)
project.team.max_member_access_for_user_ids(user_ids)
end
def preload_noteable_for_regular_notes(notes)
ActiveRecord::Associations::Preloader.new.preload(notes.reject(&:for_commit?), :noteable)
end
def prepare_notes_for_rendering(notes)
preload_noteable_for_regular_notes(notes)
preload_max_access_for_authors(notes, @project)
Banzai::NoteRenderer.render(notes, @project, current_user)
notes
end
def note_max_access_for_user(note)
note.project.team.human_max_access(note.author_id)
end
......
......@@ -4,7 +4,6 @@ def note_commit_email(recipient_id, note_id)
setup_note_mail(note_id, recipient_id)
@commit = @note.noteable
@discussion = @note.discussion if @note.part_of_discussion?
@target_url = namespace_project_commit_url(*note_target_url_options)
mail_answer_thread(@commit,
......@@ -17,7 +16,6 @@ def note_issue_email(recipient_id, note_id)
setup_note_mail(note_id, recipient_id)
@issue = @note.noteable
@discussion = @note.discussion if @note.part_of_discussion?
@target_url = namespace_project_issue_url(*note_target_url_options)
mail_answer_thread(@issue, note_thread_options(recipient_id))
end
......@@ -26,7 +24,6 @@ def note_merge_request_email(recipient_id, note_id)
setup_note_mail(note_id, recipient_id)
@merge_request = @note.noteable
@discussion = @note.discussion if @note.part_of_discussion?
@target_url = namespace_project_merge_request_url(*note_target_url_options)
mail_answer_thread(@merge_request, note_thread_options(recipient_id))
end
......@@ -35,7 +32,6 @@ def note_snippet_email(recipient_id, note_id)
setup_note_mail(note_id, recipient_id)
@snippet = @note.noteable
@discussion = @note.discussion if @note.part_of_discussion?
@target_url = namespace_project_snippet_url(*note_target_url_options)
mail_answer_thread(@snippet, note_thread_options(recipient_id))
end
......@@ -44,7 +40,6 @@ def note_personal_snippet_email(recipient_id, note_id)
setup_note_mail(note_id, recipient_id)
@snippet = @note.noteable
@discussion = @note.discussion if @note.part_of_discussion?
@target_url = snippet_url(@note.noteable)
mail_answer_thread(@snippet, note_thread_options(recipient_id))
end
......
......@@ -2,12 +2,14 @@ module ResolvableDiscussion
extend ActiveSupport::Concern
included do
memoized_values << :resolvable
memoized_values << :resolved
memoized_values << :first_note
memoized_values << :first_note_to_resolve
memoized_values << :last_resolved_note
memoized_values << :last_note
memoized_values.push(
:resolvable,
:resolved,
:first_note,
:first_note_to_resolve,
:last_resolved_note,
:last_note
)
delegate :resolved_at,
:resolved_by,
......
......@@ -8,7 +8,9 @@ module ResolvableNote
validates :resolved_by, presence: true, if: :resolved?
# Keep this scope in sync with the logic in `#potentially_resolvable?` in `Discussion` subclasses that are resolvable
# Keep this scope in sync with the logic in `#potentially_resolvable?` in `Discussion` subclasses that are resolvable.
# `RESOLVABLE_TYPES` should include names of all subclasses that are resolvable (where the method can return true), and
# the scope should also match the criteria `ResolvableDiscussion#potentially_resolvable?` puts on resolvability.
scope :potentially_resolvable, -> { where(type: RESOLVABLE_TYPES).where(noteable_type: 'MergeRequest') }
# Keep this scope in sync with `#resolvable?`
scope :resolvable, -> { potentially_resolvable.user }
......
# A discussion on merge request or commit diffs consisting of `DiffNote` notes
class DiffDiscussion < Discussion
include DiscussionOnDiff
......
# A note on merge request or commit diffs
class DiffNote < Note
include NoteOnDiff
......
......@@ -39,6 +39,7 @@ def self.build_discussion_id_base(note)
[:discussion, note.noteable_type.try(:underscore), noteable_id]
end
# Returns an array of discussion ID components
def self.build_discussion_id(note)
[*build_discussion_id_base(note), SecureRandom.hex]
end
......
# A note in a non-diff discussion on an issue, merge request, commit, or snippet
class DiscussionNote < Note
NOTEABLE_TYPES = %w(MergeRequest Issue Commit Snippet).freeze
......
# A discussion to wrap a single `Note` note on the root of an issue, merge request,
# commit, or snippet, that is not displayed as a discussion
class IndividualNoteDiscussion < Discussion
# Keep this method in sync with the `potentially_resolvable` scope on `ResolvableNote`
def potentially_resolvable?
......
# A discussion on merge request or commit diffs consisting of `LegacyDiffNote` notes
class LegacyDiffDiscussion < Discussion
include DiscussionOnDiff
......
# A note on merge request or commit diffs, using the legacy implementation
class LegacyDiffNote < Note
include NoteOnDiff
......
......@@ -68,6 +68,7 @@ class Note < ActiveRecord::Base
scope :user, ->{ where(system: false) }
scope :common, ->{ where(noteable_type: ["", nil]) }
scope :fresh, ->{ order(created_at: :asc, id: :asc) }
scope :updated_after, ->(time){ where('updated_at > ?', time) }
scope :inc_author_project, ->{ includes(:project, :author) }
scope :inc_author, ->{ includes(:author) }
scope :inc_relations_for_view, -> do
......@@ -238,18 +239,20 @@ def discussion_id(noteable = nil)
discussion_class(noteable).override_discussion_id(self) || super()
end
# Returns a discussion containing just this note
# Returns a discussion containing just this note.
# This method exists as an alternative to `#discussion` to use when the methods
# we intend to call on the Discussion object don't require it to have all of its notes,
# and just depend on the first note or the type of discussion. This saves us a DB query.
def to_discussion(noteable = nil)
Discussion.build([self], noteable)
end
# Returns the entire discussion this note is part of
# Returns the entire discussion this note is part of.
# Consider using `#to_discussion` if we do not need to render the discussion
# and all its notes and if we don't care about the discussion's resolvability status.
def discussion
if part_of_discussion?
self.noteable.notes.find_discussion(self.discussion_id) || to_discussion
else
to_discussion
end
full_discussion = self.noteable.notes.find_discussion(self.discussion_id) if part_of_discussion?
full_discussion || to_discussion
end
def part_of_discussion?
......
# A discussion to wrap a number of `Note` notes on the root of a commit when they
# are displayed in context of a merge request as if they were part of a discussion.
class OutOfContextDiscussion < Discussion
# To make sure all out-of-context notes are displayed in one discussion,
# we override the discussion ID to be a newly generated but consistent ID.
......
# A non-diff discussion on an issue, merge request, commit, or snippet, consisting of `DiscussionNote` notes
class SimpleDiscussion < Discussion
end
- if @discussion
- discussion = @note.discussion unless @discussion.individual_note?
- if discussion
%p.details
= succeed ':' do
= link_to @note.author_name, user_url(@note.author)
- if @discussion.diff_discussion?
- if @discussion.new_discussion?
- if discussion.diff_discussion?
- if discussion.new_discussion?
started a new discussion
- else
commented on a discussion
on #{link_to @discussion.file_path, @target_url}
on #{link_to discussion.file_path, @target_url}
- else
- if @discussion.new_discussion?
- if discussion.new_discussion?
started a new discussion
- else
commented on a #{link_to 'discussion', @target_url}
......@@ -20,15 +21,15 @@
%p.details
#{link_to @note.author_name, user_url(@note.author)} commented:
- if @discussion&.diff_discussion?
- if discussion&.diff_discussion?
= content_for :head do
= stylesheet_link_tag 'mailers/highlighted_diff_email'
%table
= render partial: "projects/diffs/line",
collection: @discussion.truncated_diff_lines,
collection: discussion.truncated_diff_lines,
as: :line,
locals: { diff_file: @discussion.diff_file,
locals: { diff_file: discussion.diff_file,
plain: true,
email: true }
......
<% if @discussion -%>
<% discussion = @note.discussion unless @discussion.individual_note? -%>
<% if discussion && !discussion.individual_note? -%>
<%= @note.author_name -%>
<% if @discussion.new_discussion? -%>
<% if discussion.new_discussion? -%>
<%= " started a new discussion" -%>
<% else -%>
<%= " commented on a discussion" -%>
<% end -%>
<% if @discussion.diff_discussion? -%>
<%= " on #{@discussion.file_path}" -%>
<% if discussion.diff_discussion? -%>
<%= " on #{discussion.file_path}" -%>
<% end -%>
<%= ":" -%>
......@@ -16,8 +17,8 @@
<% end -%>
<% if @discussion&.diff_discussion? -%>
<% @discussion.truncated_diff_lines(highlight: false).each do |line| -%>
<% if discussion&.diff_discussion? -%>
<% discussion.truncated_diff_lines(highlight: false).each do |line| -%>
<%= "> #{line.text}\n" -%>
<% end -%>
......
<%= render partial: 'note_email' %>
<%= render 'note_email' %>
<%= render partial: 'note_email' %>
<%= render 'note_email' %>
<%= render partial: 'note_email' %>
<%= render 'note_email' %>
<%= render partial: 'note_email' %>
<%= render 'note_email' %>
......@@ -15,7 +15,6 @@
end
describe 'GET index' do
let(:last_fetched_at) { '1487756246' }
let(:request_params) do
{
namespace_id: project.namespace,
......@@ -35,6 +34,8 @@
end
it 'passes last_fetched_at from headers to NotesFinder' do
last_fetched_at = 3.hours.ago.to_i
request.headers['X-Last-Fetched-At'] = last_fetched_at
expect(NotesFinder).to receive(:new)
......@@ -47,21 +48,11 @@
context 'for a discussion note' do
let!(:note) { create(:discussion_note_on_issue, noteable: issue, project: project) }
it 'includes the ID' do
it 'responds with the expected attributes' do
get :index, request_params
expect(note_json[:id]).to eq(note.id)
end
it 'includes discussion_html' do
get :index, request_params
expect(note_json[:discussion_html]).not_to be_nil
end
it "doesn't include diff_discussion_html" do
get :index, request_params
expect(note_json[:diff_discussion_html]).to be_nil
end
end
......@@ -72,21 +63,11 @@
let(:params) { request_params.merge(target_type: 'merge_request', target_id: note.noteable_id) }
it 'includes the ID' do
it 'responds with the expected attributes' do
get :index, params
expect(note_json[:id]).to eq(note.id)
end
it 'includes discussion_html' do
get :index, params
expect(note_json[:discussion_html]).not_to be_nil
end
it 'includes diff_discussion_html' do
get :index, params
expect(note_json[:diff_discussion_html]).not_to be_nil
end
end
......@@ -100,21 +81,11 @@
let(:params) { request_params.merge(target_type: 'merge_request', target_id: merge_request.id) }
it 'includes the ID' do
it 'responds with the expected attributes' do
get :index, params
expect(note_json[:id]).to eq(note.id)
end
it 'includes discussion_html' do
get :index, params
expect(note_json[:discussion_html]).not_to be_nil
end
it "doesn't include diff_discussion_html" do
get :index, params
expect(note_json[:diff_discussion_html]).to be_nil
end
end
......@@ -122,21 +93,11 @@
context 'when displayed on the commit' do
let(:params) { request_params.merge(target_type: 'commit', target_id: note.commit_id) }
it 'includes the ID' do
it 'responds with the expected attributes' do
get :index, params
expect(note_json[:id]).to eq(note.id)
end
it "doesn't include discussion_html" do
get :index, params
expect(note_json[:discussion_html]).to be_nil
end
it "doesn't include diff_discussion_html" do
get :index, params
expect(note_json[:diff_discussion_html]).to be_nil
end
end
......@@ -145,27 +106,12 @@
context 'for a regular note' do
let!(:note) { create(:note, noteable: issue, project: project) }
it 'includes the ID' do
it 'responds with the expected attributes' do
get :index, request_params
expect(note_json[:id]).to eq(note.id)
end
it 'includes html' do
get :index, request_params
expect(note_json[:html]).not_to be_nil
end
it "doesn't include discussion_html" do
get :index, request_params
expect(note_json[:discussion_html]).to be_nil
end
it "doesn't include diff_discussion_html" do
get :index, request_params
expect(note_json[:diff_discussion_html]).to be_nil
end
end
......
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