# frozen_string_literal: true module Integrations module ChatMessage class BaseMessage RELATIVE_LINK_REGEX = %r{!\[[^\]]*\]\((/uploads/[^\)]*)\)}.freeze # Markup characters which are used for links in HTML, Markdown, # and Slack "mrkdwn" syntax (``). UNSAFE_MARKUP_CHARACTERS = '<>[]|' attr_reader :markdown attr_reader :user_full_name attr_reader :user_name attr_reader :user_avatar attr_reader :project_name attr_reader :project_url def initialize(params) @markdown = params[:markdown] || false @project_name = params[:project_name] || params.dig(:project, :path_with_namespace) @project_url = params.dig(:project, :web_url) || params[:project_url] @user_full_name = params.dig(:user, :name) || params[:user_full_name] @user_name = params.dig(:user, :username) || params[:user_name] @user_avatar = params.dig(:user, :avatar_url) || params[:user_avatar] end def user_combined_name if user_full_name.present? "#{user_full_name} (#{user_name})" else user_name end end def summary return message if markdown format(message) end def pretext summary end def fallback format(message) end def attachments raise NotImplementedError end def activity raise NotImplementedError end private def message raise NotImplementedError end def format(string) ::Slack::Messenger::Util::LinkFormatter.format(format_relative_links(string)) end def format_relative_links(string) string.gsub(RELATIVE_LINK_REGEX, "#{project_url}\\1") end # Remove unsafe markup from user input, which can be used to hijack links in our own markup, # or insert new ones. # # This currently removes Markdown and Slack "mrkdwn" links (keeping the link label), # and all HTML markup (keeping the text nodes). # We can't just escape the markup characters, because each chat app handles this differently. # # See: # - https://api.slack.com/reference/surfaces/formatting#escaping # - https://gitlab.com/gitlab-org/slack-notifier#escaping def strip_markup(string) string&.delete(UNSAFE_MARKUP_CHARACTERS) end def attachment_color '#345' end def link(text, url) "[#{strip_markup(text)}](#{url})" end def pretty_duration(seconds) parse_string = if duration < 1.hour '%M:%S' else '%H:%M:%S' end Time.at(seconds).utc.strftime(parse_string) end end end end