1# frozen_string_literal: true 2 3class Badge < ApplicationRecord 4 include FromUnion 5 6 # This structure sets the placeholders that the urls 7 # can have. This hash also sets which action to ask when 8 # the placeholder is found. 9 PLACEHOLDERS = { 10 'project_path' => :full_path, 11 'project_id' => :id, 12 'default_branch' => :default_branch, 13 'commit_sha' => ->(project) { project.commit&.sha } 14 }.freeze 15 16 # This regex is built dynamically using the keys from the PLACEHOLDER struct. 17 # So, we can easily add new placeholder just by modifying the PLACEHOLDER hash. 18 # This regex will build the new PLACEHOLDER_REGEX with the new information 19 PLACEHOLDERS_REGEX = /(#{PLACEHOLDERS.keys.join('|')})/.freeze 20 21 default_scope { order_created_at_asc } # rubocop:disable Cop/DefaultScope 22 23 scope :order_created_at_asc, -> { reorder(created_at: :asc) } 24 25 scope :with_name, ->(name) { where(name: name) } 26 27 validates :link_url, :image_url, addressable_url: true 28 validates :type, presence: true 29 30 def rendered_link_url(project = nil) 31 build_rendered_url(link_url, project) 32 end 33 34 def rendered_image_url(project = nil) 35 Gitlab::AssetProxy.proxy_url( 36 build_rendered_url(image_url, project) 37 ) 38 end 39 40 private 41 42 def build_rendered_url(url, project = nil) 43 return url unless valid? && project 44 45 Gitlab::StringPlaceholderReplacer.replace_string_placeholders(url, PLACEHOLDERS_REGEX) do |arg| 46 replace_placeholder_action(PLACEHOLDERS[arg], project) 47 end 48 end 49 50 # The action param represents the :symbol or Proc to call in order 51 # to retrieve the return value from the project. 52 # This method checks if it is a Proc and use the call method, and if it is 53 # a symbol just send the action 54 def replace_placeholder_action(action, project) 55 return unless project 56 57 action.is_a?(Proc) ? action.call(project) : project.public_send(action) # rubocop:disable GitlabSecurity/PublicSend 58 end 59end 60