diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /lib/banzai | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-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.rb | 3 | ||||
-rw-r--r-- | lib/banzai/filter/design_reference_filter.rb | 121 | ||||
-rw-r--r-- | lib/banzai/filter/external_issue_reference_filter.rb | 36 | ||||
-rw-r--r-- | lib/banzai/filter/gollum_tags_filter.rb | 20 | ||||
-rw-r--r-- | lib/banzai/filter/issue_reference_filter.rb | 14 | ||||
-rw-r--r-- | lib/banzai/filter/iteration_reference_filter.rb | 16 | ||||
-rw-r--r-- | lib/banzai/filter/label_reference_filter.rb | 15 | ||||
-rw-r--r-- | lib/banzai/filter/reference_filter.rb | 6 | ||||
-rw-r--r-- | lib/banzai/filter/repository_link_filter.rb | 4 | ||||
-rw-r--r-- | lib/banzai/filter/wiki_link_filter.rb | 10 | ||||
-rw-r--r-- | lib/banzai/pipeline/gfm_pipeline.rb | 1 | ||||
-rw-r--r-- | lib/banzai/reference_parser/iteration_parser.rb | 22 |
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') |