class Decidim::ContentParsers::ProposalParser

A parser that searches mentions of Proposals in content.

This parser accepts two ways for linking Proposals.

For example `~1234`, but no `~ 1234`.

Also fills a `Metadata#linked_proposals` attribute.

@see BaseParser Examples of how to use a content parser

Constants

ID_REGEX

Matches a mentioned Proposal ID (~(d)+ expression)

Metadata

Class used as a container for metadata

@!attribute linked_proposals

@return [Array] an array of Decidim::Proposals::Proposal mentioned in content
URL_REGEX
URL_REGEX_CONTENT
URL_REGEX_END_CHAR
URL_REGEX_SCHEME

Matches a URL

Attributes

metadata[R]

(see BaseParser#metadata)

Public Class Methods

new(content, context) click to toggle source
Calls superclass method
# File lib/decidim/content_parsers/proposal_parser.rb, line 30
def initialize(content, context)
  super
  @metadata = Metadata.new([])
end

Public Instance Methods

rewrite() click to toggle source

Replaces found mentions matching an existing Proposal with a global id for that Proposal. Other mentions found that doesn't match an existing Proposal are returned as they are.

@return [String] the content with the valid mentions replaced by a global id.

# File lib/decidim/content_parsers/proposal_parser.rb, line 40
def rewrite
  rewrited_content = parse_for_urls(content)
  parse_for_ids(rewrited_content)
end

Private Instance Methods

find_proposal_by_id(id) click to toggle source
# File lib/decidim/content_parsers/proposal_parser.rb, line 90
def find_proposal_by_id(id)
  if id.present?
    spaces = Decidim.participatory_space_manifests.flat_map do |manifest|
      manifest.participatory_spaces.call(context[:current_organization]).public_spaces
    end
    components = Component.where(participatory_space: spaces).published
    Decidim::Proposals::Proposal.where(component: components).find_by(id: id)
  end
end
parse_for_ids(content) click to toggle source
# File lib/decidim/content_parsers/proposal_parser.rb, line 62
def parse_for_ids(content)
  content.gsub(ID_REGEX) do |match|
    proposal = proposal_from_id_match(Regexp.last_match(1))
    if proposal
      @metadata.linked_proposals << proposal.id
      proposal.to_global_id
    else
      match
    end
  end
end
parse_for_urls(content) click to toggle source
# File lib/decidim/content_parsers/proposal_parser.rb, line 50
def parse_for_urls(content)
  content.gsub(URL_REGEX) do |match|
    proposal = proposal_from_url_match(match)
    if proposal
      @metadata.linked_proposals << proposal.id
      proposal.to_global_id
    else
      match
    end
  end
end
proposal_from_id_match(match) click to toggle source
# File lib/decidim/content_parsers/proposal_parser.rb, line 85
def proposal_from_id_match(match)
  proposal_id = match
  find_proposal_by_id(proposal_id)
end
proposal_from_url_match(match) click to toggle source
# File lib/decidim/content_parsers/proposal_parser.rb, line 74
def proposal_from_url_match(match)
  uri = URI.parse(match)
  return if uri.path.blank?

  proposal_id = uri.path.split("/").last
  find_proposal_by_id(proposal_id)
rescue URI::InvalidURIError
  Rails.logger.error("#{e.message}=>#{e.backtrace}")
  nil
end