Class: Banzai::Filter::PlaceholdersPostFilter
- Inherits:
-
HTML::Pipeline::Filter
- Object
- HTML::Pipeline::Filter
- Banzai::Filter::PlaceholdersPostFilter
- Defined in:
- lib/banzai/filter/placeholders_post_filter.rb
Overview
Replaces previously identified dynamic placeholders with current values. By performing this as a post-processing filter, we can show current information.
Defined Under Namespace
Classes: PlaceholderReplacer
Constant Summary collapse
- CSS =
gitlab-glfm-markdown will detect possible placeholder values, and mark them with a ‘<span data-placeholder>` for text, or add
data-placeholderto links or images. This allows us to specifically search for those nodes.The syntax used is ‘%PLACEHOLDER`. Markdown processing ignores this syntax, so even links with embedded placeholders will get preserved.
'[data-placeholder]'- XPATH =
Gitlab::Utils::Nokogiri.css_to_xpath(CSS).freeze
- FILTER_ITEM_LIMIT =
100- ALLOWED_URI_CONTEXT_ALL =
:all- ALLOWED_URI_CONTEXT_ALL_BUT_HOST =
:all_but_host- PLACEHOLDER_REPLACERS =
Variables that can be replaced. We handle them all dynamically in post-process as the values can change over time.
All placeholder replacements yield text, not HTML, and must be escaped or set as a text node’s content.
See PlaceholderReplacer for documentation on the metadata of each.
{ 'gitlab_server' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL) do Gitlab.config.gitlab.host end, 'gitlab_pages_domain' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL) do Gitlab.config.pages.host end, 'project_path' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST, uri_encode: false) do |context| # Rationale for `uri_encode: false`: the path is to be explicitly expandable, as many services # will generate URLs including a namespaced path for end-users. context[:project]&.full_path if Ability.allowed?(context[:current_user], :read_project, context[:project]) end, 'project_name' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| context[:project]&.path if Ability.allowed?(context[:current_user], :read_project, context[:project]) end, 'project_id' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| context[:project]&.id.to_s if Ability.allowed?(context[:current_user], :read_project, context[:project]) end, 'project_namespace' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| if Ability.allowed?(context[:current_user], :read_project, context[:project]) context[:project]&.project_namespace&.to_param end end, 'project_title' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| context[:project]&.title if Ability.allowed?(context[:current_user], :read_project, context[:project]) end, 'group_name' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| group = context[:project]&.group || context[:group] group.name if Ability.allowed?(context[:current_user], :read_group, group) end, 'default_branch' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST, uri_encode: false) do |context| # Rationale for `uri_encode: false`: GitLab displays URLs like # http://gdk.test:3000/root/comrak/-/tree/kiv/dev # where "kiv/dev" is a branch name. (In practice, as of writing, they generate a 404 when used!) # To support this kind of expansion, we must not percent-encode the branch name. if context[:project]&.repository_exists? && Ability.allowed?(context[:current_user], :read_code, context[:project]) context[:project]&.default_branch end end, 'current_ref' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| if context[:project]&.repository_exists? && Ability.allowed?(context[:current_user], :read_code, context[:project]) context[:ref] end end, 'commit_sha' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST) do |context| if context[:project]&.repository_exists? && Ability.allowed?(context[:current_user], :read_code, context[:project]) context[:project]&.commit&.sha end end, 'latest_tag' => PlaceholderReplacer.new(ALLOWED_URI_CONTEXT_ALL_BUT_HOST, uri_encode: false) do |context| if context[:project]&.repository_exists? && Ability.allowed?(context[:current_user], :read_code, context[:project]) # Rationale for `uri_encode: false`: GitLab uses URLs like # http://gdk.test:3000/root/comrak/-/tree/a/b/c # where "a/b/c" is a tag name. (These actually work, unlike branches.) # To support this kind of expansion, we must not percent-encode the tag name. TagsFinder.new(context[:project].repository, per_page: 1, sort: 'updated_desc') &.execute&.first&.name end end }.freeze
- PLACEHOLDERS_REGEX =
/(#{PLACEHOLDER_REPLACERS.keys.map { |p| Regexp.escape(p) }.join('|')})/- PLACEHOLDERS_FULL_ANCHORED_REGEX =
/\A%\{#{PLACEHOLDERS_REGEX}}\z/
Constants included from Concerns::TimeoutFilterHandler
Concerns::TimeoutFilterHandler::COMPLEX_MARKDOWN_MESSAGE, Concerns::TimeoutFilterHandler::RENDER_TIMEOUT, Concerns::TimeoutFilterHandler::SANITIZATION_RENDER_TIMEOUT
Constants included from Concerns::PipelineTimingCheck
Concerns::PipelineTimingCheck::MAX_PIPELINE_SECONDS
Instance Method Summary collapse
Methods included from Concerns::PipelineTimingCheck
Instance Method Details
#call ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/banzai/filter/placeholders_post_filter.rb', line 177 def call return doc unless context[:project]&.markdown_placeholders_feature_flag_enabled? || context[:group]&.markdown_placeholders_feature_flag_enabled? return doc if context[:disable_placeholders] || context[:broadcast_message_placeholders] doc.xpath(XPATH).each_with_index do |node, index| break if Banzai::Filter.filter_item_limit_exceeded?(index, limit: FILTER_ITEM_LIMIT) case node.name when 'span' replace_span_placeholder(node) when 'a' replace_link_placeholders(node) when 'img' replace_image_placeholders(node) else next end end doc end |