diff --git a/Gemfile b/Gemfile index bdf30c699335394100a457b16b1c8d891c91b303..67b716bf6ed753c84c6e00e1e71a237a6ae9fe11 100644 --- a/Gemfile +++ b/Gemfile @@ -256,7 +256,7 @@ gem 'creole', '~> 0.5.0', feature_category: :markdown gem 'wikicloth', '0.8.1', feature_category: :markdown gem 'asciidoctor', '~> 2.0.18', feature_category: :markdown gem 'asciidoctor-include-ext', '~> 0.4.0', require: false, feature_category: :markdown -gem 'asciidoctor-plantuml', '~> 0.0.16', feature_category: :markdown +gem 'asciidoctor-plantuml', '~> 0.1.1', feature_category: :markdown gem 'asciidoctor-kroki', '~> 0.10.0', require: false, feature_category: :markdown gem 'rouge', '~> 4.4.0', feature_category: :shared gem 'truncato', '~> 0.7.12', feature_category: :team_planning diff --git a/Gemfile.checksum b/Gemfile.checksum index 9b6d34d1c5fb48156eda5661d7bbcf59443810d4..f5422b22d2d41e0b33e70b50dfb3cdf9576c7b6f 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -26,7 +26,7 @@ {"name":"asciidoctor","version":"2.0.23","platform":"ruby","checksum":"52208807f237dfa0ca29882f8b13d60b820496116ad191cf197ca56f2b7fddf3"}, {"name":"asciidoctor-include-ext","version":"0.4.0","platform":"ruby","checksum":"406adb9d2fbfc25536609ca13b787ed704dc06a4e49d6709b83f3bad578f7878"}, {"name":"asciidoctor-kroki","version":"0.10.0","platform":"ruby","checksum":"8e4225d88f120e2e7b5d3f5ddb67c5e69496d7344a16c57db5036ac900123062"}, -{"name":"asciidoctor-plantuml","version":"0.0.16","platform":"ruby","checksum":"407e47cd1186ded5ccc75f0c812e5524c26c571d542247c5132abb8f47bd1793"}, +{"name":"asciidoctor-plantuml","version":"0.1.1","platform":"ruby","checksum":"2bfa1a79349aa3fff611cdc54ade674e91423e38c20a21b24d8ca59006a0b0ae"}, {"name":"ast","version":"2.4.2","platform":"ruby","checksum":"1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12"}, {"name":"async","version":"2.12.1","platform":"ruby","checksum":"146fb3acf6d05ad40abb9ae659dd3b574067a3420fe7d6d5d6a3cf5413de3ea5"}, {"name":"atlassian-jwt","version":"0.2.1","platform":"ruby","checksum":"2fd2d87418773f2e140c038cb22e049069708aff2bd0a423a7e1740574e97823"}, diff --git a/Gemfile.lock b/Gemfile.lock index 954dcdc8c00db2a39f1a65ac9332455d93d0a57d..4e4bd4a2d12638e2a0442917c5bf4750356d5111 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -331,7 +331,7 @@ GEM asciidoctor (>= 1.5.6, < 3.0.0) asciidoctor-kroki (0.10.0) asciidoctor (~> 2.0) - asciidoctor-plantuml (0.0.16) + asciidoctor-plantuml (0.1.1) asciidoctor (>= 2.0.17, < 3.0.0) ast (2.4.2) async (2.12.1) @@ -1980,7 +1980,7 @@ DEPENDENCIES asciidoctor (~> 2.0.18) asciidoctor-include-ext (~> 0.4.0) asciidoctor-kroki (~> 0.10.0) - asciidoctor-plantuml (~> 0.0.16) + asciidoctor-plantuml (~> 0.1.1) async (~> 2.12.1) atlassian-jwt (~> 0.2.1) attr_encrypted (~> 3.2.4)! diff --git a/Gemfile.next.checksum b/Gemfile.next.checksum index da5add729d22e002f30ea4556ac11a81a3d2b36f..06c1c4ff8b91734d93347659ace0a9333216a6a8 100644 --- a/Gemfile.next.checksum +++ b/Gemfile.next.checksum @@ -26,7 +26,7 @@ {"name":"asciidoctor","version":"2.0.23","platform":"ruby","checksum":"52208807f237dfa0ca29882f8b13d60b820496116ad191cf197ca56f2b7fddf3"}, {"name":"asciidoctor-include-ext","version":"0.4.0","platform":"ruby","checksum":"406adb9d2fbfc25536609ca13b787ed704dc06a4e49d6709b83f3bad578f7878"}, {"name":"asciidoctor-kroki","version":"0.10.0","platform":"ruby","checksum":"8e4225d88f120e2e7b5d3f5ddb67c5e69496d7344a16c57db5036ac900123062"}, -{"name":"asciidoctor-plantuml","version":"0.0.16","platform":"ruby","checksum":"407e47cd1186ded5ccc75f0c812e5524c26c571d542247c5132abb8f47bd1793"}, +{"name":"asciidoctor-plantuml","version":"0.1.1","platform":"ruby","checksum":"2bfa1a79349aa3fff611cdc54ade674e91423e38c20a21b24d8ca59006a0b0ae"}, {"name":"ast","version":"2.4.2","platform":"ruby","checksum":"1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12"}, {"name":"async","version":"2.12.1","platform":"ruby","checksum":"146fb3acf6d05ad40abb9ae659dd3b574067a3420fe7d6d5d6a3cf5413de3ea5"}, {"name":"atlassian-jwt","version":"0.2.1","platform":"ruby","checksum":"2fd2d87418773f2e140c038cb22e049069708aff2bd0a423a7e1740574e97823"}, diff --git a/Gemfile.next.lock b/Gemfile.next.lock index bd7ec9b03a11f450f9b4ef3a0f8f43da8b77e063..a3e685ad12810362edd248f0337f12b2e0b195b0 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -340,7 +340,7 @@ GEM asciidoctor (>= 1.5.6, < 3.0.0) asciidoctor-kroki (0.10.0) asciidoctor (~> 2.0) - asciidoctor-plantuml (0.0.16) + asciidoctor-plantuml (0.1.1) asciidoctor (>= 2.0.17, < 3.0.0) ast (2.4.2) async (2.12.1) @@ -2007,7 +2007,7 @@ DEPENDENCIES asciidoctor (~> 2.0.18) asciidoctor-include-ext (~> 0.4.0) asciidoctor-kroki (~> 0.10.0) - asciidoctor-plantuml (~> 0.0.16) + asciidoctor-plantuml (~> 0.1.1) async (~> 2.12.1) atlassian-jwt (~> 0.2.1) attr_encrypted (~> 3.2.4)! diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 03d0b7ad1c1afa6a46252d746a3c5e7605ec3255..11f27fd561898e3313af2e95ad8a4e388f9461c5 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -885,10 +885,6 @@ def validate_kroki_url validate_url(parsed_kroki_url, :kroki_url, KROKI_URL_ERROR_MESSAGE) end - def kroki_url_absolute? - parsed_kroki_url&.absolute? - end - def sourcegraph_url_is_com? !!(sourcegraph_url =~ %r{\Ahttps://(www\.)?sourcegraph\.com}) end diff --git a/lib/banzai/filter/plantuml_filter.rb b/lib/banzai/filter/plantuml_filter.rb index 090bf08c6a47a5a2e85e595dce458ed213224519..030443c0a3c99fa36ae8e0855e0ada6b26fd56de 100644 --- a/lib/banzai/filter/plantuml_filter.rb +++ b/lib/banzai/filter/plantuml_filter.rb @@ -9,18 +9,23 @@ module Filter # class PlantumlFilter < HTML::Pipeline::Filter prepend Concerns::PipelineTimingCheck + include ActionView::Helpers::TagHelper + include Gitlab::Utils::StrongMemoize def call return doc unless settings.plantuml_enabled? && doc.at_xpath(lang_tag) + return doc unless plantuml_url_valid? Gitlab::Plantuml.configure doc.xpath(lang_tag).each do |node| - img_tag = Nokogiri::HTML::DocumentFragment.parse( - Asciidoctor::PlantUml::Processor.plantuml_content(node.content, {})).css('img').first + next if node.content.blank? - next if img_tag.nil? + image_src = create_image_src('png', node.content) + img_tag = Nokogiri::HTML::DocumentFragment.parse(content_tag(:img, nil, src: image_src)) + img_tag = img_tag.children.first + img_tag.add_class('plantuml') img_tag.set_attribute('data-diagram', 'plantuml') img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(node.content)}") @@ -40,6 +45,15 @@ def lang_tag def settings Gitlab::CurrentSettings.current_application_settings end + strong_memoize_attr :settings + + def create_image_src(format, text) + Asciidoctor::PlantUml::Processor.gen_url(text, format) + end + + def plantuml_url_valid? + ::Gitlab::UrlSanitizer.valid_web?(settings.plantuml_url) + end end end end diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb index bbbabd7a6bbc1507465fb1f21b7bad0fc059ee16..c1da963e512786d669d4d96df42df438b424cb26 100644 --- a/spec/lib/banzai/filter/plantuml_filter_spec.rb +++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb @@ -9,7 +9,7 @@ stub_application_setting(plantuml_enabled: true, plantuml_url: "http://localhost:8080") input = '<pre data-canonical-lang="plantuml"><code>Bob -> Sara : Hello</code></pre>' - output = '<img class="plantuml" src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IFNhcmEgOiBIZWxsbw==">' + output = '<img src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq" class="plantuml" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IFNhcmEgOiBIZWxsbw==">' doc = filter(input) expect(doc.to_s).to eq output @@ -19,7 +19,7 @@ stub_application_setting(plantuml_enabled: true, plantuml_url: "http://localhost:8080") input = '<pre><code data-canonical-lang="plantuml">Bob -> Sara : Hello</code></pre>' - output = '<img class="plantuml" src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IFNhcmEgOiBIZWxsbw==">' + output = '<img src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq" class="plantuml" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IFNhcmEgOiBIZWxsbw==">' doc = filter(input) expect(doc.to_s).to eq output @@ -35,8 +35,17 @@ expect(doc.to_s).to eq output end - it 'does not replace plantuml pre tag with img tag if url is invalid' do - stub_application_setting(plantuml_enabled: true, plantuml_url: "invalid") + it 'does not replace plantuml pre tag if there is no content' do + stub_application_setting(plantuml_enabled: true, plantuml_url: "http://localhost:8080") + + input = '<pre><code data-canonical-lang="plantuml"></code></pre>' + doc = filter(input) + + expect(doc.to_s).to eq input + end + + it 'does not replace plantuml pre tag if the url is not valid' do + stub_application_setting(plantuml_enabled: true, plantuml_url: "invalid://localhost:8080") input = '<pre data-canonical-lang="plantuml"><code>Bob -> Sara : Hello</code></pre>' output = '<pre data-canonical-lang="plantuml"><code>Bob -> Sara : Hello</code></pre>' diff --git a/spec/lib/gitlab/other_markup_spec.rb b/spec/lib/gitlab/other_markup_spec.rb index cb0d8dd1bf1a13fa1fca0c71c52637a1ce85ec5a..7f50e4f504b413b2d80dd9ae9b9f49b37288893c 100644 --- a/spec/lib/gitlab/other_markup_spec.rb +++ b/spec/lib/gitlab/other_markup_spec.rb @@ -35,7 +35,7 @@ RST output = <<~HTML - <img class="plantuml" src="https://plantuml.com/plantuml/png/U9npoazIqBLJSCp9J4wrKiX8pSd9vm9pGA9E-Kb0iKm0o4SAt000" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IEFsaWNlOiBoZWxsbwpBbGljZSAtPiBCb2I6IGhp"> + <img src="https://plantuml.com/plantuml/png/U9npoazIqBLJSCp9J4wrKiX8pSd9vm9pGA9E-Kb0iKm0o4SAt000" class="plantuml" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IEFsaWNlOiBoZWxsbwpBbGljZSAtPiBCb2I6IGhp"> <p>Caption with <strong>bold</strong> and <em>italic</em></p> HTML diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb index c0ebcc5c4747aab495c00ba30a320e61247559e3..4a205ae6bf617bdbb9e8aeb9d6d3607fc1b03627 100644 --- a/spec/support/matchers/markdown_matchers.rb +++ b/spec/support/matchers/markdown_matchers.rb @@ -299,7 +299,7 @@ def have_image(src) end end - # PLantumlFilter + # PlantumlFilter matcher :parse_plantuml do set_default_markdown_messages