Newer
Older
dmpopidor / app / controllers / templates_controller.rb
# [+Project:+] DMPRoadmap
# [+Description:+] This controller is responsible for all the actions in the admin interface under templates (e.g. phases, versions, sections, questions, suggested answer) (index; show; create; edit; delete)
# [+Copyright:+] Digital Curation Centre and University of California Curation Center

class TemplatesController < ApplicationController
  respond_to :html
  after_action :verify_authorized

  # GET /dmptemplates
  def admin_index
    authorize Template
    # institutional templates
    all_versions_own_templates = Template.where(org_id: current_user.org_id, customization_of: nil).order(version: :desc)
    current_templates = {}
    # take most recent version of each template
    all_versions_own_templates.each do |temp|
      if current_templates[temp.dmptemplate_id].nil?
        current_templates[temp.dmptemplate_id] = temp
      end
    end
    @templates_own = current_templates.values

    # funders templates
    funders_templates = {}
    Org.includes(:templates).funder.each do |org|
      org.templates.where(customization_of: nil, published: true).order(version: :desc).each do |temp|
        if funders_templates[temp.dmptemplate_id].nil?
          funders_templates[temp.dmptemplate_id] = temp
        end
      end
    end

    @templates_funders = funders_templates.values
    # are any funder templates customized
    @templates_customizations = {}
    Template.where(org_id: current_user.org_id, customization_of: funders_templates.keys).order(version: :desc).each do |temp|
      if @templates_customizations[temp.customization_of].nil?
        @templates_customizations[temp.customization_of] = {}
        @templates_customizations[temp.customization_of][:temp] = temp
        @templates_customizations[temp.customization_of][:published] = temp.published
      else
        @templates_customizations[temp.customization_of][:published] = @templates_customizations[temp.customization_of][:published] || temp.published
      end
    end
  end


  # GET /dmptemplates/1
  def admin_template
    @template = Template.find(params[:id])
    # check to see if this is a funder template needing customized
    if @template.org_id != current_user.org_id
      # definitely need to deep_copy the given template
      new_customization = Template.deep_copy(@template)
      new_customization.org_id = current_user.org_id
      new_customization.published = false
      new_customization.customization_of = @template.dmptemplate_id
      # need to mark all Phases, questions, sections as not-modifiable
      new_customization.phases.includes(sections: :questions).each do |phase|
        phase.modifiable = false
        phase.save!
        phase.sections.each do |section|
          section.modifiable = false
          section.save!
          section.questions.each do |question|
            question.modifiable = false
            question.save!
          end
        end
      end
      customizations = Template.includes(phases: [sections: [questions: :suggested_answers ]]).where(org_id: current_user.org_id, customization_of: @template.dmptemplate_id).order(version: :desc)
      if customizations.present?
        # existing customization to port over
        max_version = customizations.first
        new_customization.dmptemplate_id = max_version.dmptemplate_id
        new_customization.version = max_version.version + 1
        # here we rip the customizations out of the old template
        # First, we find any customized phases or sections
        max_version.phases.each do |phase|
          # check if the phase was added as a customization
          if phase.modifiable
            # deep copy the phase and add it to the template
            phase_copy = Phase.deep_copy(phase)
            phase_copy.number = new_customization.phases.length + 1
            phase_copy.template_id = new_customization.id
            phase_copy.save!
          else
            # iterate over the sections to see if any of them are customizations
            phase.sections.each do |section|
              if section.modifiable
                # this is a custom section
                section_copy = Section.deep_copy(section)
                customization_phase = new_customization.includes(:sections).phase.where(number: phase.number)
                section_copy.phase_id = customization_phase.id
                # custom sections get added to the end
                section_copy.number = customization_phase.sections.length + 1
                # section from phase with corresponding number in the main_template
                section_copy.save!
              else
                # not a customized section, iterate over questions
                customization_phase = new_customization.includes(sections: [questions: :suggested_answers])
                customization_section = customization_phase.section.where(number: section.number)
                section.questions.each do |question|
                  # find corresponding question in new template
                  customization_question = customization_section.question.where(number: question.number)
                  # apply suggested_answers
                  question.suggested_answers.each do |suggested_answer|
                    suggested_answer_copy = SuggestedAnswer.deep_copy(suggested_answer)
                    suggested_answer_copy.org_id = current_user.org_id
                    suggested_answer_copy.question_id = customization_question.id
                    suggested_answer_copy.save!
                  end
                  # guidance attached to a question is also a form of customization
                  # It will soon become an annotation of the question, and be combined with
                  # suggested answers
                  customization_question.guidance = customization_question.guidance + question.guidance
                  customization_question.save!
                end
              end
            end
          end
        end
      else
        # first time customization
        new_customization.version = 0
        new_customization.dmptemplate_id = loop do
          random = rand 2147483647  # max int field in psql
          break random unless Template.exists?(dmptemplate_id: random)
        end
      end
      new_customization.save!
      @template = new_customization
    end
    # needed for some post-migration edge cases
    # some customized templates which were edited
    if @template.customization_of.present? && @template.published
      new_version = Template.deep_copy(@template)
      new_version.version = @template.version + 1
      new_version.published = false
      new_version.save!
      @template = new_version
    end
    authorize @template
  end


  # PUT /dmptemplates/1
  def admin_update
    @template = Template.find(params[:id])
    authorize @template
    if @template.published?
      # published templates cannot be edited
      redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.read_only') and return
    end
    @template.description = params["template-desc"]
    if @template.update_attributes(params[:template])
      if @template.published
        # create a new template version if this template became published
        new_version = Template.deep_copy(@template)
        new_version.version = @template.version + 1
        new_version.published = false
        new_version.save!
      end
      redirect_to admin_index_template_path(), notice: I18n.t('org_admin.templates.updated_message')
    else
      render action: "edit"
    end
  end


  # GET /dmptemplates/new
  def admin_new
    authorize Template
  end


  # POST /dmptemplates
  # creates a new template with version 0 and new dmptemplate_id
  def admin_create
    @template = Template.new(params[:template])
    @template.org_id = current_user.org_id
    @template.description = params['template-desc']
    @template.published = false
    @template.version = 0
    # Generate a unique identifier for the dmptemplate_id
    @template.dmptemplate_id = loop do
      random = rand 2147483647
      break random unless Template.exists?(dmptemplate_id: random)
    end
    authorize @template
    if @template.save
      redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.created_message')
    else
      render action: "admin_new"
    end
  end


  # DELETE /dmptemplates/1
  def admin_destroy
    @template = Template.find(params[:id])
    authorize @template
    @template.destroy
    redirect_to admin_index_template_path
  end

  # GET /templates/1
  def admin_template_history
    @template = Template.find(params[:id])
    authorize @template
    @templates = Template.where(dmptemplate_id: @template.dmptemplate_id).order(:version)
  end



  # PHASES

  #show and edit a phase of the template
  def admin_phase
    @phase = Phase.find(params[:id])
    authorize @phase.template
    @edit = params[:edit] == "true" ? true : false
        #verify if there are any sections if not create one
    @sections = @phase.sections
    if !@sections.any?() || @sections.count == 0
      @section = @phase.sections.build
      @section.phase = @phase
      @section.title = ''
      @section.number = 1
      @section.published = true
      @section.modifiable = true
      @section.save
      @new_sec = true
    end
    #verify if section_id has been passed, if so then open that section
    if params.has_key?(:section_id)
      @open = true
      @section_id = params[:section_id].to_i
    end
    if params.has_key?(:question_id)
      @question_id = params[:question_id].to_i
    end
  end


  #preview a phase
  def admin_previewphase
    @phase = Phase.find(params[:id])
    authorize @phase.template
    @template = @phase.template
  end


  #add a new phase to a template
  def admin_addphase
    @template = Template.find(params[:id])
    @phase = Phase.new
    authorize @template
    @phase.number = @template.phases.count + 1
  end


  #create a phase
  def admin_createphase
    @phase = Phase.new(params[:phase])
    authorize @phase.template
    @phase.description = params["phase-desc"]
    @phase.modifiable = true
    if @phase.save
      redirect_to admin_phase_template_path(id: @phase.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message')
    else
      render action: "admin_phase"
    end
  end


  #update a phase of a template
  def admin_updatephase
    @phase = Phase.find(params[:id])
    authorize @phase.template
    @phase.description = params["phase-desc"]
    if @phase.update_attributes(params[:phase])
      redirect_to admin_phase_template_path(@phase), notice: I18n.t('org_admin.templates.updated_message')
    else
      render action: "admin_phase"
    end
  end

  #delete a phase
  def admin_destroyphase
    @phase = Phase.find(params[:phase_id])
    authorize @phase.template
    @template = @phase.template
    @phase.destroy
    redirect_to admin_template_template_path(@template), notice: I18n.t('org_admin.templates.destroyed_message')
  end

# SECTIONS
  #create a section
  def admin_createsection
    @section = Section.new(params[:section])
    authorize @section.phase.template
    @section.description = params["section-desc"]
    @section.modifiable = true
    if @section.save
      redirect_to admin_phase_template_path(id: @section.phase_id,
        :section_id => @section.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message')
    else
      render action: "admin_phase"
    end
  end


  #update a section of a template
  def admin_updatesection
    @section = Section.find(params[:id])
    authorize @section.phase.template
    @section.description = params["section-desc-#{params[:id]}"]
    @phase = @section.phase
    if @section.update_attributes(params[:section])
      redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id , edit: 'true'), notice: I18n.t('org_admin.templates.updated_message')
    else
      render action: "admin_phase"
    end
  end


  #delete a section and questions
  def admin_destroysection
    @section = Section.find(params[:section_id])
    authorize @section.phase.template
    @phase = @section.phase
    @section.destroy
    redirect_to admin_phase_template_path(id: @phase.id, edit: 'true' ), notice: I18n.t('org_admin.templates.destroyed_message')
  end


#  QUESTIONS

  #create a question
  def admin_createquestion
    @question = Question.new(params[:question])
    authorize @question.section.phase.template
    @question.guidance = params["new-question-guidance"]
    @question.default_value = params["new-question-default-value"]
    if @question.save!
      redirect_to admin_phase_template_path(id: @question.section.phase_id, section_id: @question.section_id, question_id: @question.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message')
    else
      render action: "admin_phase"
    end
  end

  #update a question of a template
  def admin_updatequestion
    @question = Question.find(params[:id])
    authorize @question.section.phase.template
    @question.guidance = params["question-guidance-#{params[:id]}"]
    @question.default_value = params["question-default-value-#{params[:id]}"]
    @section = @question.section
    @phase = @section.phase
    if @question.update_attributes(params[:question])
      redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: I18n.t('org_admin.templates.updated_message')
    else
      render action: "admin_phase"
    end
  end

  #delete question
  def admin_destroyquestion
    @question = Question.find(params[:question_id])
    authorize @question.section.phase.template
    @section = @question.section
    @phase = @section.phase
    @question.destroy
    redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: I18n.t('org_admin.templates.destroyed_message')
  end


  #SUGGESTED ANSWERS
  #create suggested answers
  def admin_createsuggestedanswer
    @suggested_answer = SuggestedAnswer.new(params[:suggested_answer])
    authorize @suggested_answer.question.section.phase.template
    if @suggested_answer.save
      redirect_to admin_phase_template_path(id: @suggested_answer.question.section.phase_id, section_id: @suggested_answer.question.section_id, question_id: @suggested_answer.question.id, edit: 'true'), notice: I18n.t('org_admin.templates.created_message')
    else
      render action: "admin_phase"
    end
  end


  #update a suggested answer of a template
  def admin_updatesuggestedanswer
    @suggested_answer = SuggestedAnswer.find(params[:id])
    authorize @suggested_answer.question.section.phase.template
    @question = @suggested_answer.question
    @section = @question.section
    @phase = @section.phase
    if @suggested_answer.update_attributes(params[:suggested_answer])
      redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: I18n.t('org_admin.templates.updated_message')
    else
      render action: "admin_phase"
    end
  end

  #delete a suggested answer
  def admin_destroysuggestedanswer
    @suggested_answer = SuggestedAnswer.find(params[:suggested_answer])
    authorize @suggested_answer.question.section.phase.template
    @question = @suggested_answer.question
    @section = @question.section
    @phase = @section.phase
    @suggested_answer.destroy
    redirect_to admin_phase_template_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: I18n.t('org_admin.templates.destroyed_message')
  end

end