holderdeord/hdo-site

View on GitHub
app/decorators/issue_decorator.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: utf-8

class IssueDecorator < Draper::Decorator
  delegate :title,
           :description,
           :tags,
           :to_param,
           :status_text,
           :editor_name,
           :last_updated_by_name,
           :published?

  def updated_at
    I18n.l model.updated_at, format: :text
  end

  def time_since_updated
    h.distance_of_time_in_words_to_now model.updated_at.localtime
  end

  def periods
    periods = ParliamentPeriod.all
    periods.map { |pp| Period.new(pp, model) }.select { |e| e.years.any? || e.promisors.any? }
  end

  def period_named(name)
    periods.find { |e| e.name == name }
  end

  def short_explanation
    h.t 'app.votes.based_on', count: model.proposition_connections.size
  end

  private

  class Period
    delegate :name, to: :@parliament_period

    def initialize(parliament_period, issue)
      @parliament_period = parliament_period
      @issue             = issue
    end

    def years
      @years ||= proposition_connections.group_by { |e| e.vote.time.to_date }.
             map { |date, connections| Day.new(date, connections) }.
             sort_by(&:raw_date).reverse.group_by { |e| e.year }.
             map { |year, days| OpenStruct.new(:year => year, :days => days) }
    end

    def promisors
      @promises ||= @issue.promise_connections.joins(:promise).
                      where('promises.parliament_period_id' => @parliament_period).
                      group_by { |e| e.promise.promisor }.
                      sort_by { |promisor, _| [promisor.kind_of?(Party) ? 0 : 1, promisor.name] }.
                      map { |promisor, connections| Promisor.new(promisor, connections) }

    end


    def positions
      @positions ||= @issue.positions.where(parliament_period_id: @parliament_period).order(:priority).map { |pos| Position.new(@issue, pos) }
    end

    def explanation
      votes = proposition_connections.map(&:vote).uniq

      if votes.any?
        count      = votes.size
        start_date = votes.first.time
        end_date   = votes.last.time

        "Basert på #{count} avstemning#{count == 1 ? '' : 'er'} på Stortinget mellom #{I18n.l start_date, format: :month_year} og #{I18n.l end_date, format: :month_year}"
      else
        ''
      end
    end

    private

    def proposition_connections
      @proposition_connections ||= @issue.proposition_connections.includes(:proposition => :votes).select { |e| @parliament_period.include?(e.vote.time) }.sort_by { |e| e.vote.time }
    end
  end

  class Position
    delegate :title, :description, :priority, to: :@position

    def initialize(issue, position)
      @issue    = issue
      @position = position
      @period   = position.parliament_period
    end

    def parties
      @position.parties.map { |party| PartyInfo.new(party, comment_for(party), promises_for(party), accountability_for(party)) }
    end

    private

    def promises_for(party)
      promises = @issue.promise_connections.joins(:promise).
                    where('promises.promisor_id' => party).
                    where('promises.promisor_type' => Party.name).
                    where('promises.parliament_period_id' => @period)

      #
      # The following may need change if there are several governments per period.
      #

      gov = Government.for_date(@period.start_date + 2.months).first
      if gov && gov.parties.include?(party)
        promises += @issue.promise_connections.joins(:promise).
                      where('promises.promisor_id' => gov).
                      where('promises.promisor_type' => Government.name).
                      where('promises.parliament_period_id' => @period)
      end

      promises.sort_by(&:status)
    end

    def accountability_for(party)
      @issue.accountability(@period).text_for(party)
    end

    def comment_for(party)
      @issue.party_comments.
             where(:party_id => party).
             where(:parliament_period_id => @period).first
    end
  end

  class PartyInfo < Struct.new(:party, :comment, :promises, :accountability)
    delegate :logo, :slug, :name, to: :party
  end

  class Promisor < Struct.new(:promisor, :connections)
    TEASER_LENGTH = 90

    def slug
      parties.map { |e| e.slug }.join('-')
    end

    def parties
      promisor.kind_of?(Government) ? promisor.parties : [promisor]
    end

    def teaser_promise
      @teaser_promise ||= teaser_connection.promise.body
    end

    def teaser
      teaser_promise.truncate(TEASER_LENGTH)
    end

    def teaser_connection
      connections.find { |e| !e.related? } || connections.first
    end

    def promises
      connections.map { |c| [c.promise, c] }
    end

    def expandable?
      connections.size > 1 || teaser_promise.length >= TEASER_LENGTH
    end
  end

  class Day
    def initialize(date, connections)
      @date = date
      @connections = connections
    end

    def day
      @date.day
    end

    def year
      @date.year
    end

    def month
      I18n.l @date, format: '%b'
    end

    def raw_date
      @date
    end

    def votes
      @connections.sort_by { |e| e.vote.time }.reverse
    end
  end
end