Newer
Older
dmpopidor / app / models / concerns / exportable_plan.rb
# frozen_string_literal: true

module ExportablePlan

  def as_pdf(coversheet = false)
    prepare(coversheet)
  end

  def as_csv(headings = true,
             unanswered = true,
             selected_phase = nil,
             show_custom_sections = true,
             show_coversheet = false)
    hash = prepare(show_coversheet)

    CSV.generate do |csv|
      if show_coversheet
        prepare_coversheet_for_csv(csv, headings, hash)
      end

      hdrs = (hash[:phases].many? ? [_("Phase")] : [])
      if headings
        hdrs << [_("Section"), _("Question"), _("Answer")]
      else
        hdrs << [_("Answer")]
      end

      customization = hash[:customization]

      csv << hdrs.flatten
      hash[:phases].each do |phase|
        if  selected_phase.nil? || phase[:title] == selected_phase.title
          phase[:sections].each do |section|
            show_section = !customization
            show_section ||= customization && !section[:modifiable]
            show_section ||= customization && section[:modifiable] && show_custom_sections

            if show_section
              show_section_for_csv(csv, phase, section, headings, unanswered, hash)
            end
          end
        end
      end
    end
  end

  private

  def prepare(coversheet = false)
    hash = coversheet ? prepare_coversheet : {}
    template = Template.includes(phases: { sections: { questions: :question_format } })
                       .joins(phases: { sections: { questions: :question_format } })
                       .where(id: self.template_id)
                       .order("sections.number", "questions.number").first
    hash[:customization] = template.customization_of.present?
    hash[:title] = self.title
    hash[:answers] = self.answers
    hash[:research_outputs] = self.research_outputs

    # add the relevant questions/answers
    phases = []
    template.phases.order(:number).each do |phase|
      phs = { id: phase.id, title: phase.title, number: phase.number, sections: [] }
      phase.sections.order(:number).each do |section|
        sctn = { id: section.id,
                 title: section.title,
                 number: section.number,
                 questions: [],
                 modifiable: section.modifiable }
        section.questions.each do |question|
          txt = question.text
          sctn[:questions] << {
            id: question.id,
            text: txt,
            format: question.question_format
          }
        end
        phs[:sections] << sctn
      end
      phases << phs
    end
    hash[:phases] = phases

    record_plan_export(:pdf)

    hash
  end

  def prepare_coversheet
    hash = {}
    # name of owner and any co-owners
    attribution = self.owner.present? ? [self.owner.name(false)] : []
    self.roles.administrator.not_creator.each do |role|
      attribution << role.user.name(false)
    end
    hash[:attribution] = attribution

    # Org name of plan owner's org
    hash[:affiliation] = self.owner.present? ? self.owner.org.name : ""

    # set the funder name
    hash[:funder] = self.funder_name.present? ?
                    self.funder_name : (self.template.org.present? ?
                    self.template.org.name : "")

    # set the template name and customizer name if applicable
    hash[:template] = self.template.title
    customizer = ""
    cust_questions = self.questions.where(modifiable: true).pluck(:id)
    # if the template is customized, and has custom answered questions
    if self.template.customization_of.present? &&
       Answer.where(plan_id: self.id, question_id: cust_questions).present?
      customizer = _(" Customised By: ") + self.template.org.name
    end
    hash[:customizer] = customizer
    hash
  end

  def prepare_coversheet_for_csv(csv, headings, hash)
    csv << [ hash[:attribution].many? ?
             _("Creators: ") :
             _("Creator:"), _("%{authors}") % { authors: hash[:attribution].join(", ") } ]
    csv << [ "Affiliation: ", _("%{affiliation}") % { affiliation: hash[:affiliation] } ]
    if hash[:funder].present?
      csv << [ _("Template: "), _("%{funder}") % { funder: hash[:funder] } ]
    else
      csv << [ _("Template: "), _("%{template}") % { template: hash[:template] + hash[:customizer] } ]
    end
    if self.grant_number.present?
      csv << [ _("Grant number: "), _("%{grant_number}") % { grant_number: self.grant_number } ]
    end
    if self.description.present?
      csv << [ _("Project abstract: "), _("%{description}") %
               { description: Nokogiri::HTML(self.description).text } ]
    end
    csv << [ _("Last modified: "), _("%{date}") % { date: self.updated_at.to_date.strftime("%d-%m-%Y") } ]
    csv << [ _("Copyright information:"),
             _("The above plan creator(s) have agreed that others may use as
             much of the text of this plan as they would like in their own plans,
             and customise it as necessary. You do not need to credit the creator(s)
             as the source of the language used, but using any of the plan's text
             does not imply that the creator(s) endorse, or have any relationship to,
             your project or proposal") ]
    csv << []
    csv << []
  end

  def show_section_for_csv(csv, phase, section, headings, unanswered, hash)
    section[:questions].each do |question|
      answer = self.answer(question[:id], false)
      if answer.present? || (answer.blank? && unanswered)
        answer_text = answer.present? ? answer.text :
                      (unanswered ? _("Not Answered") : "")
        if answer.present? && answer.question_options.any?
          answer_text = answer.question_options.pluck(:text).join(", ")
        end
      end
      flds = (hash[:phases].many? ? [phase[:title]] : [])
      if headings
        if question[:text].is_a? String
          question_text = question[:text]
        else
          question_text = (question[:text].many? ?
                           question[:text].join(", ") :
                           question[:text][0])
        end
        flds << [ section[:title], sanitize_text(question_text),
                  sanitize_text(answer_text)
                ]
      else
        flds << [ sanitize_text(answer_text) ]
      end
      csv << flds.flatten
    end
  end

  def record_plan_export(format)
    exported_plan = ExportedPlan.new.tap do |ep|
      ep.plan = self
      ep.phase_id = self.phases.first.id
      ep.format = format
      plan_settings = self.settings(:export)

      Settings::Template::DEFAULT_SETTINGS.each do |key, value|
        ep.settings(:export).send("#{key}=", plan_settings.send(key))
      end
    end
    exported_plan.save
  end

  def sanitize_text(text)
    ActionView::Base.full_sanitizer.sanitize(text.to_s.gsub(/&nbsp;/i, ""))
  end

end