From 96c2b940480eb1bafd47e1f6d203ad11f8f646df Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 2 Apr 2015 20:46:43 -0400 Subject: [PATCH 01/36] Reference filters :sparkles: Commit ranges, commits, external issues, issues, labels, merge requests, snippets, users. --- app/helpers/issues_helper.rb | 2 + app/helpers/labels_helper.rb | 16 +- lib/gitlab/markdown.rb | 328 +++--------------- .../markdown/commit_range_reference_filter.rb | 127 +++++++ .../markdown/commit_reference_filter.rb | 108 ++++++ .../markdown/cross_project_reference.rb | 26 ++ .../external_issue_reference_filter.rb | 94 +++++ lib/gitlab/markdown/issue_reference_filter.rb | 110 ++++++ lib/gitlab/markdown/label_reference_filter.rb | 100 ++++++ .../merge_request_reference_filter.rb | 107 ++++++ .../markdown/snippet_reference_filter.rb | 98 ++++++ lib/gitlab/markdown/user_reference_filter.rb | 117 +++++++ spec/helpers/gitlab_markdown_helper_spec.rb | 52 +-- spec/helpers/labels_helper_spec.rb | 4 +- .../commit_range_reference_filter_spec.rb | 105 ++++++ .../markdown/commit_reference_filter_spec.rb | 98 ++++++ .../markdown/cross_project_reference_spec.rb | 23 ++ .../external_issue_reference_filter_spec.rb | 101 ++++++ .../markdown/issue_reference_filter_spec.rb | 104 ++++++ .../markdown/label_reference_filter_spec.rb | 72 ++++ .../merge_request_reference_filter_spec.rb | 93 +++++ .../markdown/snippet_reference_filter_spec.rb | 64 ++++ .../markdown/user_reference_filter_spec.rb | 87 +++++ spec/support/reference_filter_spec_helper.rb | 37 ++ 24 files changed, 1730 insertions(+), 343 deletions(-) create mode 100644 lib/gitlab/markdown/commit_range_reference_filter.rb create mode 100644 lib/gitlab/markdown/commit_reference_filter.rb create mode 100644 lib/gitlab/markdown/cross_project_reference.rb create mode 100644 lib/gitlab/markdown/external_issue_reference_filter.rb create mode 100644 lib/gitlab/markdown/issue_reference_filter.rb create mode 100644 lib/gitlab/markdown/label_reference_filter.rb create mode 100644 lib/gitlab/markdown/merge_request_reference_filter.rb create mode 100644 lib/gitlab/markdown/snippet_reference_filter.rb create mode 100644 lib/gitlab/markdown/user_reference_filter.rb create mode 100644 spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/commit_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/cross_project_reference_spec.rb create mode 100644 spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/issue_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/label_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb create mode 100644 spec/lib/gitlab/markdown/user_reference_filter_spec.rb create mode 100644 spec/support/reference_filter_spec_helper.rb diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index ad4a7612724..7b034f22248 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -108,4 +108,6 @@ module IssuesHelper xml.summary issue.title end end + + module_function :url_for_issue, :title_for_issue end diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 32ef2e7ca84..0259829a059 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -7,9 +7,13 @@ module LabelsHelper label_color = label.color || Label::DEFAULT_COLOR text_color = text_color_for_bg(label_color) - content_tag :span, class: 'label color-label', style: "background-color:#{label_color};color:#{text_color}" do - label.name - end + # Intentionally not using content_tag here so that this method can be called + # by LabelReferenceFilter + span = %() + + label.name + '' + + span.html_safe end def suggested_colors @@ -42,13 +46,15 @@ module LabelsHelper r, g, b = bg_color.slice(1,7).scan(/.{2}/).map(&:hex) if (r + g + b) > 500 - "#333" + '#333333' else - "#FFF" + '#FFFFFF' end end def project_labels_options(project) options_from_collection_for_select(project.labels, 'name', 'name', params[:label_name]) end + + module_function :render_colored_label, :text_color_for_bg end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 47c456d8dc7..93c279edc32 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -10,11 +10,11 @@ module Gitlab # Supported reference formats are: # * @foo for team members # * #123 for issues - # * #JIRA-123 for Jira issues + # * JIRA-123 for Jira issues # * !123 for merge requests # * $123 for snippets - # * 123456 for commits - # * 123456...7890123 for commit ranges (comparisons) + # * 1c002d for specific commit + # * 1c002d...35cfb2 for commit ranges (comparisons) # # It also parses Emoji codes to insert images. See # http://www.emoji-cheat-sheet.com/ for a list of the supported icons. @@ -30,10 +30,6 @@ module Gitlab # >> gfm(":trollface:") # => "\":trollface:\" module Markdown - include IssuesHelper - - attr_reader :options, :html_options - # Public: Parse the provided text with GitLab-Flavored Markdown # # text - the source text @@ -65,42 +61,13 @@ module Gitlab reference_only_path: true ) - @options = options - @html_options = html_options - - # TODO: add popups with additional information - - # Used markdown pipelines in GitLab: - # GitlabEmojiFilter - performs emoji replacement. - # SanitizationFilter - remove unsafe HTML tags and attributes - # - # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters - filters = [ - HTML::Pipeline::Gitlab::GitlabEmojiFilter, - HTML::Pipeline::SanitizationFilter - ] - - whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST - whitelist[:attributes][:all].push('class', 'id') - whitelist[:elements].push('span') - - # Remove the rel attribute that the sanitize gem adds, and remove the - # href attribute if it contains inline javascript - fix_anchors = lambda do |env| - name, node = env[:node_name], env[:node] - if name == 'a' - node.remove_attribute('rel') - if node['href'] && node['href'].match('javascript:') - node.remove_attribute('href') - end - end - end - whitelist[:transformers].push(fix_anchors) - markdown_context = { - asset_root: Gitlab.config.gitlab.url, - asset_host: Gitlab::Application.config.asset_host, - whitelist: whitelist + asset_root: Gitlab.config.gitlab.url, + asset_host: Gitlab::Application.config.asset_host, + whitelist: sanitization_whitelist, + reference_class: html_options[:class], + only_path: options[:reference_only_path], + project: project } markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline @@ -114,21 +81,6 @@ module Gitlab text = result[:output].to_html(save_with: save_options) - # Extract pre blocks so they are not altered - # from http://github.github.com/github-flavored-markdown/ - text.gsub!(%r{
.*?
|.*?}m) { |match| extract_piece(match) } - # Extract links with probably parsable hrefs - text.gsub!(%r{.*?}m) { |match| extract_piece(match) } - # Extract images with probably parsable src - text.gsub!(%r{}m) { |match| extract_piece(match) } - - text = parse(text, project) - - # Insert pre block extractions - text.gsub!(/\{gfm-extraction-(\h{32})\}/) do - insert_piece($1) - end - if options[:parse_tasks] text = parse_tasks(text) end @@ -138,242 +90,48 @@ module Gitlab private - def extract_piece(text) - @extractions ||= {} - - md5 = Digest::MD5.hexdigest(text) - @extractions[md5] = text - "{gfm-extraction-#{md5}}" - end - - def insert_piece(id) - @extractions[id] - end - - # Private: Parses text for references + # Custom filters for html-pipeline: # - # text - Text to parse + # See https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters + def filters + [ + Gitlab::Markdown::UserReferenceFilter, + Gitlab::Markdown::IssueReferenceFilter, + Gitlab::Markdown::ExternalIssueReferenceFilter, + Gitlab::Markdown::MergeRequestReferenceFilter, + Gitlab::Markdown::SnippetReferenceFilter, + Gitlab::Markdown::CommitRangeReferenceFilter, + Gitlab::Markdown::CommitReferenceFilter, + Gitlab::Markdown::LabelReferenceFilter, + HTML::Pipeline::Gitlab::GitlabEmojiFilter, + HTML::Pipeline::SanitizationFilter + ] + end + + # Customize the SanitizationFilter whitelist # - # Returns parsed text - def parse(text, project = @project) - parse_references(text, project) if project + # - Allow `class` and `id` attributes on all elements + # - Allow `span` elements + # - Remove `rel` attributes from `a` elements + # - Remove `a` nodes with `javascript:` in the `href` attribute + def sanitization_whitelist + whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST + whitelist[:attributes][:all].push('class', 'id') + whitelist[:elements].push('span') - text - end - - NAME_STR = Gitlab::Regex::NAMESPACE_REGEX_STR - PROJ_STR = "(?#{NAME_STR}/#{NAME_STR})" - - REFERENCE_PATTERN = %r{ - (?\W)? # Prefix - ( # Reference - @(?#{NAME_STR}) # User name - |~(?