Commit 79aac2c1 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ignore-references' into 'master'

Don't notify users mentioned in code blocks or blockquotes.

cc @rspeicher

See merge request !753
parents 34d176ad a916936f
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 7.12.0 (unreleased) v 7.12.0 (unreleased)
- Don't notify users mentioned in code blocks or blockquotes.
- Disable changing of the source branch in merge request update API (Stan Hu) - Disable changing of the source branch in merge request update API (Stan Hu)
- Shorten merge request WIP text. - Shorten merge request WIP text.
- Add option to disallow users from registering any application to use GitLab as an OAuth provider - Add option to disallow users from registering any application to use GitLab as an OAuth provider
......
...@@ -41,29 +41,26 @@ module GitlabMarkdownHelper ...@@ -41,29 +41,26 @@ module GitlabMarkdownHelper
fragment.to_html.html_safe fragment.to_html.html_safe
end end
MARKDOWN_OPTIONS = {
no_intra_emphasis: true,
tables: true,
fenced_code_blocks: true,
strikethrough: true,
lax_spacing: true,
space_after_headers: true,
superscript: true,
footnotes: true
}.freeze
def markdown(text, options={}) def markdown(text, options={})
unless @markdown && options == @options unless @markdown && options == @options
@options = options @options = options
options.merge!(
# Handled further down the line by Gitlab::Markdown::SanitizationFilter
escape_html: false
)
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options) rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options)
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
@markdown = Redcarpet::Markdown.new(rend, @markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS)
no_intra_emphasis: true,
tables: true,
fenced_code_blocks: true,
strikethrough: true,
lax_spacing: true,
space_after_headers: true,
superscript: true,
footnotes: true
)
end end
@markdown.render(text).html_safe @markdown.render(text).html_safe
......
...@@ -25,12 +25,18 @@ module Gitlab ...@@ -25,12 +25,18 @@ module Gitlab
ERB::Util.html_escape_once(html) ERB::Util.html_escape_once(html)
end end
# Don't look for references in text nodes that are children of these def ignore_parents
# elements. @ignore_parents ||= begin
IGNORE_PARENTS = %w(pre code a style).to_set # Don't look for references in text nodes that are children of these
# elements.
parents = %w(pre code a style)
parents << 'blockquote' if context[:ignore_blockquotes]
parents.to_set
end
end
def ignored_ancestry?(node) def ignored_ancestry?(node)
has_ancestor?(node, IGNORE_PARENTS) has_ancestor?(node, ignore_parents)
end end
def project def project
......
module Gitlab module Gitlab
# Extract possible GFM references from an arbitrary String for further processing. # Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor class ReferenceExtractor
attr_accessor :project, :current_user, :references attr_accessor :project, :current_user
def initialize(project, current_user = nil) def initialize(project, current_user = nil)
@project = project @project = project
...@@ -9,48 +9,31 @@ module Gitlab ...@@ -9,48 +9,31 @@ module Gitlab
end end
def analyze(text) def analyze(text)
@_text = text.dup references.clear
@text = markdown.render(text.dup)
end end
def users %i(user label issue merge_request snippet commit commit_range).each do |type|
result = pipeline_result(:user) define_method("#{type}s") do
result.uniq references[type]
end
end end
def labels private
result = pipeline_result(:label)
result.uniq
end
def issues
# TODO (rspeicher): What about external issues?
result = pipeline_result(:issue)
result.uniq
end
def merge_requests
result = pipeline_result(:merge_request)
result.uniq
end
def snippets def markdown
result = pipeline_result(:snippet) @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, GitlabMarkdownHelper::MARKDOWN_OPTIONS)
result.uniq
end end
def commits def references
result = pipeline_result(:commit) @references ||= Hash.new do |references, type|
result.uniq type = type.to_sym
end return references[type] if references.has_key?(type)
def commit_ranges references[type] = pipeline_result(type).uniq
result = pipeline_result(:commit_range) end
result.uniq
end end
private
# Instantiate and call HTML::Pipeline with a single reference filter type, # Instantiate and call HTML::Pipeline with a single reference filter type,
# returning the result # returning the result
# #
...@@ -65,11 +48,12 @@ module Gitlab ...@@ -65,11 +48,12 @@ module Gitlab
project: project, project: project,
current_user: current_user, current_user: current_user,
# We don't actually care about the links generated # We don't actually care about the links generated
only_path: true only_path: true,
ignore_blockquotes: true
} }
pipeline = HTML::Pipeline.new([filter], context) pipeline = HTML::Pipeline.new([filter], context)
result = pipeline.call(@_text) result = pipeline.call(@text)
result[:references][filter_type] result[:references][filter_type]
end end
......
...@@ -10,6 +10,8 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML ...@@ -10,6 +10,8 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
@options = options.dup @options = options.dup
@options.reverse_merge!( @options.reverse_merge!(
# Handled further down the line by Gitlab::Markdown::SanitizationFilter
escape_html: false,
project: @template.instance_variable_get("@project") project: @template.instance_variable_get("@project")
) )
......
...@@ -16,6 +16,30 @@ describe Gitlab::ReferenceExtractor do ...@@ -16,6 +16,30 @@ describe Gitlab::ReferenceExtractor do
expect(subject.users).to eq([@u_foo, @u_bar, @u_offteam]) expect(subject.users).to eq([@u_foo, @u_bar, @u_offteam])
end end
it 'ignores user mentions inside specific elements' do
@u_foo = create(:user, username: 'foo')
@u_bar = create(:user, username: 'bar')
@u_offteam = create(:user, username: 'offteam')
project.team << [@u_foo, :reporter]
project.team << [@u_bar, :guest]
subject.analyze(%Q{
Inline code: `@foo`
Code block:
```
@bar
```
Quote:
> @offteam
})
expect(subject.users).to eq([])
end
it 'accesses valid issue objects' do it 'accesses valid issue objects' do
@i0 = create(:issue, project: project) @i0 = create(:issue, project: project)
@i1 = create(:issue, project: project) @i1 = create(:issue, project: project)
......
...@@ -107,17 +107,26 @@ shared_examples 'an editable mentionable' do ...@@ -107,17 +107,26 @@ shared_examples 'an editable mentionable' do
it 'creates new cross-reference notes when the mentionable text is edited' do it 'creates new cross-reference notes when the mentionable text is edited' do
subject.save subject.save
new_text = <<-MSG new_text = <<-MSG.strip_heredoc
These references already existed: These references already existed:
Issue: #{mentioned_issue.to_reference}
Commit: #{mentioned_commit.to_reference} Issue: #{mentioned_issue.to_reference}
Commit: #{mentioned_commit.to_reference}
---
This cross-project reference already existed: This cross-project reference already existed:
Issue: #{ext_issue.to_reference(project)}
Issue: #{ext_issue.to_reference(project)}
---
These two references are introduced in an edit: These two references are introduced in an edit:
Issue: #{new_issues[0].to_reference}
Cross: #{new_issues[1].to_reference(project)} Issue: #{new_issues[0].to_reference}
Cross: #{new_issues[1].to_reference(project)}
MSG MSG
# These three objects were already referenced, and should not receive new # These three objects were already referenced, and should not receive new
......
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