summaryrefslogtreecommitdiff
path: root/lib/banzai
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 11:18:50 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 11:18:50 +0000
commit8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch)
treea77e7fe7a93de11213032ed4ab1f33a3db51b738 /lib/banzai
parent00b35af3db1abfe813a778f643dad221aad51fca (diff)
downloadgitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'lib/banzai')
-rw-r--r--lib/banzai/filter/ascii_doc_sanitization_filter.rb3
-rw-r--r--lib/banzai/filter/design_reference_filter.rb121
-rw-r--r--lib/banzai/filter/external_issue_reference_filter.rb36
-rw-r--r--lib/banzai/filter/gollum_tags_filter.rb20
-rw-r--r--lib/banzai/filter/issue_reference_filter.rb14
-rw-r--r--lib/banzai/filter/iteration_reference_filter.rb16
-rw-r--r--lib/banzai/filter/label_reference_filter.rb15
-rw-r--r--lib/banzai/filter/reference_filter.rb6
-rw-r--r--lib/banzai/filter/repository_link_filter.rb4
-rw-r--r--lib/banzai/filter/wiki_link_filter.rb10
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb1
-rw-r--r--lib/banzai/reference_parser/iteration_parser.rb22
12 files changed, 230 insertions, 38 deletions
diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
index e41f7d8488a..a1a204ec652 100644
--- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb
+++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
@@ -18,6 +18,7 @@ module Banzai
# Classes used by Asciidoctor to style components
ADMONITION_CLASSES = %w(fa icon-note icon-tip icon-warning icon-caution icon-important).freeze
+ ALIGNMENT_BUILTINS_CLASSES = %w(text-center text-left text-right text-justify).freeze
CALLOUT_CLASSES = ['conum'].freeze
CHECKLIST_CLASSES = %w(fa fa-check-square-o fa-square-o).freeze
LIST_CLASSES = %w(checklist none no-bullet unnumbered unstyled).freeze
@@ -28,7 +29,7 @@ module Banzai
ELEMENT_CLASSES_WHITELIST = {
span: %w(big small underline overline line-through).freeze,
- div: ['admonitionblock'].freeze,
+ div: ALIGNMENT_BUILTINS_CLASSES + ['admonitionblock'].freeze,
td: ['icon'].freeze,
i: ADMONITION_CLASSES + CALLOUT_CLASSES + CHECKLIST_CLASSES,
ul: LIST_CLASSES,
diff --git a/lib/banzai/filter/design_reference_filter.rb b/lib/banzai/filter/design_reference_filter.rb
new file mode 100644
index 00000000000..7455dfe00ef
--- /dev/null
+++ b/lib/banzai/filter/design_reference_filter.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+module Banzai
+ module Filter
+ class DesignReferenceFilter < AbstractReferenceFilter
+ FEATURE_FLAG = :design_management_reference_filter_gfm_pipeline
+
+ class Identifier
+ include Comparable
+ attr_reader :issue_iid, :filename
+
+ def initialize(issue_iid:, filename:)
+ @issue_iid = issue_iid
+ @filename = filename
+ end
+
+ def as_composite_id(id_for_iid)
+ id = id_for_iid[issue_iid]
+ return unless id
+
+ { issue_id: id, filename: filename }
+ end
+
+ def <=>(other)
+ return unless other.is_a?(Identifier)
+
+ [issue_iid, filename] <=> [other.issue_iid, other.filename]
+ end
+ alias_method :eql?, :==
+
+ def hash
+ [issue_iid, filename].hash
+ end
+ end
+
+ self.reference_type = :design
+
+ # This filter must be enabled by setting the
+ # design_management_reference_filter_gfm_pipeline flag
+ def call
+ return doc unless enabled?
+
+ super
+ end
+
+ def find_object(project, identifier)
+ records_per_parent[project][identifier]
+ end
+
+ def parent_records(project, identifiers)
+ return [] unless project.design_management_enabled?
+
+ iids = identifiers.map(&:issue_iid).to_set
+ issues = project.issues.where(iid: iids)
+ id_for_iid = issues.index_by(&:iid).transform_values(&:id)
+ issue_by_id = issues.index_by(&:id)
+
+ designs(identifiers, id_for_iid).each do |d|
+ issue = issue_by_id[d.issue_id]
+ # optimisation: assign values we have already fetched
+ d.project = project
+ d.issue = issue
+ end
+ end
+
+ def relation_for_paths(paths)
+ super.includes(:route, :namespace, :group)
+ end
+
+ def parent_type
+ :project
+ end
+
+ # optimisation to reuse the parent_per_reference query information
+ def parent_from_ref(ref)
+ parent_per_reference[ref || current_parent_path]
+ end
+
+ def url_for_object(design, project)
+ path_options = { vueroute: design.filename }
+ Gitlab::Routing.url_helpers.designs_project_issue_path(project, design.issue, path_options)
+ end
+
+ def data_attributes_for(_text, _project, design, **_kwargs)
+ super.merge(issue: design.issue_id)
+ end
+
+ def self.object_class
+ ::DesignManagement::Design
+ end
+
+ def self.object_sym
+ :design
+ end
+
+ def self.parse_symbol(raw, match_data)
+ filename = match_data[:url_filename]
+ iid = match_data[:issue].to_i
+ Identifier.new(filename: CGI.unescape(filename), issue_iid: iid)
+ end
+
+ def record_identifier(design)
+ Identifier.new(filename: design.filename, issue_iid: design.issue.iid)
+ end
+
+ private
+
+ def designs(identifiers, id_for_iid)
+ identifiers
+ .map { |identifier| identifier.as_composite_id(id_for_iid) }
+ .compact
+ .in_groups_of(100, false) # limitation of by_issue_id_and_filename, so we batch
+ .flat_map { |ids| DesignManagement::Design.by_issue_id_and_filename(ids) }
+ end
+
+ def enabled?
+ Feature.enabled?(FEATURE_FLAG, parent)
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/external_issue_reference_filter.rb b/lib/banzai/filter/external_issue_reference_filter.rb
index 8159dcfed72..74bc102320c 100644
--- a/lib/banzai/filter/external_issue_reference_filter.rb
+++ b/lib/banzai/filter/external_issue_reference_filter.rb
@@ -54,6 +54,8 @@ module Banzai
doc
end
+ private
+
# Replace `JIRA-123` issue references in text with links to the referenced
# issue's details page.
#
@@ -63,27 +65,31 @@ module Banzai
# Returns a String with `JIRA-123` references replaced with links. All
# links have `gfm` and `gfm-issue` class names attached for styling.
def issue_link_filter(text, link_content: nil)
- project = context[:project]
-
self.class.references_in(text, issue_reference_pattern) do |match, id|
- ExternalIssue.new(id, project)
-
- url = url_for_issue(id, project, only_path: context[:only_path])
-
- title = "Issue in #{project.external_issue_tracker.title}"
+ url = url_for_issue(id)
klass = reference_class(:issue)
data = data_attribute(project: project.id, external_issue: id)
-
content = link_content || match
%(<a href="#{url}" #{data}
- title="#{escape_once(title)}"
+ title="#{escape_once(issue_title)}"
class="#{klass}">#{content}</a>)
end
end
- def url_for_issue(*args)
- IssuesHelper.url_for_issue(*args)
+ def url_for_issue(issue_id)
+ return '' if project.nil?
+
+ url = if only_path?
+ project.external_issue_tracker.issue_path(issue_id)
+ else
+ project.external_issue_tracker.issue_url(issue_id)
+ end
+
+ # Ensure we return a valid URL to prevent possible XSS.
+ URI.parse(url).to_s
+ rescue URI::InvalidURIError
+ ''
end
def default_issues_tracker?
@@ -94,7 +100,13 @@ module Banzai
external_issues_cached(:external_issue_reference_pattern)
end
- private
+ def project
+ context[:project]
+ end
+
+ def issue_title
+ "Issue in #{project.external_issue_tracker.title}"
+ end
def external_issues_cached(attribute)
cached_attributes = Gitlab::SafeRequestStore[:banzai_external_issues_tracker_attributes] ||= Hash.new { |h, k| h[k] = {} }
diff --git a/lib/banzai/filter/gollum_tags_filter.rb b/lib/banzai/filter/gollum_tags_filter.rb
index dec4ec871f1..033e3d2c33e 100644
--- a/lib/banzai/filter/gollum_tags_filter.rb
+++ b/lib/banzai/filter/gollum_tags_filter.rb
@@ -30,7 +30,7 @@ module Banzai
# Note: the table of contents tag is now handled by TableOfContentsTagFilter
#
# Context options:
- # :project_wiki (required) - Current project wiki.
+ # :wiki [Wiki] (required) - Current wiki instance.
#
class GollumTagsFilter < HTML::Pipeline::Filter
include ActionView::Helpers::TagHelper
@@ -100,8 +100,8 @@ module Banzai
if url?(content)
path = content
- elsif file = project_wiki.find_file(content)
- path = ::File.join project_wiki_base_path, file.path
+ elsif file = wiki.find_file(content)
+ path = ::File.join(wiki_base_path, file.path)
end
if path
@@ -134,25 +134,25 @@ module Banzai
if url?(reference)
reference
else
- ::File.join(project_wiki_base_path, reference)
+ ::File.join(wiki_base_path, reference)
end
content_tag(:a, name || reference, href: href, class: 'gfm')
end
- def project_wiki
- context[:project_wiki]
+ def wiki
+ context[:wiki]
end
- def project_wiki_base_path
- project_wiki && project_wiki.wiki_base_path
+ def wiki_base_path
+ wiki&.wiki_base_path
end
- # Ensure that a :project_wiki key exists in context
+ # Ensure that a :wiki key exists in context
#
# Note that while the key might exist, its value could be nil!
def validate
- needs :project_wiki
+ needs :wiki
end
end
end
diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb
index 37e66387f2e..dc4b865bfb6 100644
--- a/lib/banzai/filter/issue_reference_filter.rb
+++ b/lib/banzai/filter/issue_reference_filter.rb
@@ -18,7 +18,9 @@ module Banzai
end
def url_for_object(issue, project)
- IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path], internal: true)
+ return issue_path(issue, project) if only_path?
+
+ issue_url(issue, project)
end
def projects_relation_for_paths(paths)
@@ -35,6 +37,14 @@ module Banzai
private
+ def issue_path(issue, project)
+ Gitlab::Routing.url_helpers.namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: issue.iid)
+ end
+
+ def issue_url(issue, project)
+ Gitlab::Routing.url_helpers.namespace_project_issue_url(namespace_id: project.namespace, project_id: project, id: issue.iid)
+ end
+
def design_link_extras(issue, path)
if path == '/designs' && read_designs?(issue)
['designs']
@@ -44,7 +54,7 @@ module Banzai
end
def read_designs?(issue)
- Ability.allowed?(current_user, :read_design, issue)
+ issue.project.design_management_enabled?
end
end
end
diff --git a/lib/banzai/filter/iteration_reference_filter.rb b/lib/banzai/filter/iteration_reference_filter.rb
new file mode 100644
index 00000000000..9d2b533e6da
--- /dev/null
+++ b/lib/banzai/filter/iteration_reference_filter.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Banzai
+ module Filter
+ # The actual filter is implemented in the EE mixin
+ class IterationReferenceFilter < AbstractReferenceFilter
+ self.reference_type = :iteration
+
+ def self.object_class
+ Iteration
+ end
+ end
+ end
+end
+
+Banzai::Filter::IterationReferenceFilter.prepend_if_ee('EE::Banzai::Filter::IterationReferenceFilter')
diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index 60ffb178393..7cda4699ae6 100644
--- a/lib/banzai/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -71,13 +71,16 @@ module Banzai
end
def url_for_object(label, parent)
- h = Gitlab::Routing.url_helpers
+ label_url_method =
+ if context[:label_url_method]
+ context[:label_url_method]
+ elsif parent.is_a?(Project)
+ :project_issues_url
+ end
- if parent.is_a?(Project)
- h.project_issues_url(parent, label_name: label.name, only_path: context[:only_path])
- elsif context[:label_url_method]
- h.public_send(context[:label_url_method], parent, label_name: label.name, only_path: context[:only_path]) # rubocop:disable GitlabSecurity/PublicSend
- end
+ return unless label_url_method
+
+ Gitlab::Routing.url_helpers.public_send(label_url_method, parent, label_name: label.name, only_path: context[:only_path]) # rubocop:disable GitlabSecurity/PublicSend
end
def object_link_text(object, matches)
diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb
index 38bbed3cf72..9e932ccf9f8 100644
--- a/lib/banzai/filter/reference_filter.rb
+++ b/lib/banzai/filter/reference_filter.rb
@@ -142,6 +142,12 @@ module Banzai
def element_node?(node)
node.is_a?(Nokogiri::XML::Element)
end
+
+ private
+
+ def only_path?
+ context[:only_path]
+ end
end
end
end
diff --git a/lib/banzai/filter/repository_link_filter.rb b/lib/banzai/filter/repository_link_filter.rb
index 24900217560..66b9aac3e7e 100644
--- a/lib/banzai/filter/repository_link_filter.rb
+++ b/lib/banzai/filter/repository_link_filter.rb
@@ -10,7 +10,7 @@ module Banzai
# :commit
# :current_user
# :project
- # :project_wiki
+ # :wiki
# :ref
# :requested_path
# :system_note
@@ -53,7 +53,7 @@ module Banzai
def linkable_files?
strong_memoize(:linkable_files) do
- context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty?
+ context[:wiki].nil? && repository.try(:exists?) && !repository.empty?
end
end
diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb
index 205f777bc90..44f13612fde 100644
--- a/lib/banzai/filter/wiki_link_filter.rb
+++ b/lib/banzai/filter/wiki_link_filter.rb
@@ -6,12 +6,12 @@ module Banzai
# Rewrite rules are documented in the `WikiPipeline` spec.
#
# Context options:
- # :project_wiki
+ # :wiki
class WikiLinkFilter < HTML::Pipeline::Filter
include Gitlab::Utils::SanitizeNodeLink
def call
- return doc unless project_wiki?
+ return doc unless wiki?
doc.search('a:not(.gfm)').each { |el| process_link(el.attribute('href'), el) }
@@ -33,8 +33,8 @@ module Banzai
remove_unsafe_links({ node: node }, remove_invalid_links: false)
end
- def project_wiki?
- !context[:project_wiki].nil?
+ def wiki?
+ !context[:wiki].nil?
end
def process_link_attr(html_attr)
@@ -46,7 +46,7 @@ module Banzai
end
def apply_rewrite_rules(link_string)
- Rewriter.new(link_string, wiki: context[:project_wiki], slug: context[:page_slug]).apply_rules
+ Rewriter.new(link_string, wiki: context[:wiki], slug: context[:page_slug]).apply_rules
end
end
end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index 329bbb270bd..2ea5fd3388a 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -56,6 +56,7 @@ module Banzai
[
Filter::UserReferenceFilter,
Filter::ProjectReferenceFilter,
+ Filter::DesignReferenceFilter,
Filter::IssueReferenceFilter,
Filter::ExternalIssueReferenceFilter,
Filter::MergeRequestReferenceFilter,
diff --git a/lib/banzai/reference_parser/iteration_parser.rb b/lib/banzai/reference_parser/iteration_parser.rb
new file mode 100644
index 00000000000..45253fa1977
--- /dev/null
+++ b/lib/banzai/reference_parser/iteration_parser.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Banzai
+ module ReferenceParser
+ # The actual parser is implemented in the EE mixin
+ class IterationParser < BaseParser
+ self.reference_type = :iteration
+
+ def references_relation
+ Iteration
+ end
+
+ private
+
+ def can_read_reference?(_user, _ref_project, _node)
+ false
+ end
+ end
+ end
+end
+
+Banzai::ReferenceParser::IterationParser.prepend_if_ee('::EE::Banzai::ReferenceParser::IterationParser')