module OrgAdmin class TemplatesController < ApplicationController include Paginable include Versionable after_action :verify_authorized # The root version of index which returns all templates # GET /org_admin/templates # ----------------------------------------------------- def index authorize Template templates = Template.latest_version.where(customization_of: nil) published = templates.select{|t| t.published? || t.draft? }.length render 'index', locals: { orgs: Org.all, title: _('All Templates'), templates: templates.includes(:org), action: 'index', query_params: { sort_field: :title, sort_direction: :asc }, all_count: templates.length, published_count: published.present? ? published : 0, unpublished_count: published.present? ? (templates.length - published): templates.length } end # A version of index that displays only templates that belong to the user's org # GET /org_admin/templates/organisational # ----------------------------------------------------- def organisational authorize Template templates = Template.latest_version_per_org(current_user.org.id).where(customization_of: nil, org_id: current_user.org.id) published = templates.select{|t| t.published? || t.draft? }.length title = current_user.can_super_admin? ? _('%{org_name} Templates') % { org_name: current_user.org.name } : _('Own Templates') render 'index', locals: { orgs: current_user.can_super_admin? ? Org.all : nil, title: title, templates: templates, action: 'organisational', query_params: { sort_field: :title, sort_direction: :asc }, all_count: templates.length, published_count: published.present? ? published : 0, unpublished_count: published.present? ? (templates.length - published): templates.length } end # A version of index that displays only templates that are customizable # GET /org_admin/templates/customisable # ----------------------------------------------------- def customisable authorize Template customizations = Template.latest_customized_version_per_org(current_user.org.id).where(org_id: current_user.org.id) funder_templates = Template.latest_customizable.includes(:org) # We use this to validate the counts below in the event that a template was customized but the base template # org is no longer a funder funder_template_families = funder_templates.collect(&:family_id) published = customizations.select{|t| t.published? || t.draft? }.length render 'index', locals: { orgs: (current_user.can_super_admin? ? Org.all : []), title: _('Customizable Templates'), templates: funder_templates, customizations: customizations, action: 'customisable', query_params: { sort_field: :title, sort_direction: :asc }, all_count: funder_templates.length, published_count: published.present? ? published : 0, unpublished_count: published.present? ? (customizations.length - published): customizations.length, not_customized_count: funder_templates.length - customizations.length } end # GET /org_admin/templates/[:id] def show template = Template.find(params[:id]) authorize template # Load the info needed for the overview section if the authorization check passes! phases = template.phases.includes(sections: { questions: :question_options }). order('phases.number', 'sections.number', 'questions.number', 'question_options.number'). select('phases.title', 'phases.description', 'sections.title', 'questions.text', 'question_options.text') if !template.latest? flash[:notice] = _('You are viewing a historical version of this template. You will not be able to make changes.') end render 'container', locals: { partial_path: 'show', template: template, phases: phases, referrer: get_referrer(template, request.referrer) } end # GET /org_admin/templates/:id/edit # ----------------------------------------------------- def edit template = Template.includes(:org, :phases).find(params[:id]) authorize template # Load the info needed for the overview section if the authorization check passes! phases = template.phases.includes(sections: { questions: :question_options }). order('phases.number', 'sections.number', 'questions.number', 'question_options.number'). select('phases.title', 'phases.description', 'sections.title', 'questions.text', 'question_options.text') if !template.latest? flash[:notice] = _("You are viewing a historical version of this #{template_type(template)}. You will not be able to make changes.") end render 'container', locals: { partial_path: 'edit', template: template, phases: phases, referrer: get_referrer(template, request.referrer) } end # GET /org_admin/templates/new # ----------------------------------------------------- def new authorize Template render 'container', locals: { partial_path: 'new', template: Template.new(org: current_user.org), referrer: request.referrer.present? ? request.referrer : org_admin_templates_path } end # POST /org_admin/templates # ----------------------------------------------------- def create authorize Template # creates a new template with version 0 and new family_id template = Template.new(template_params) template.org_id = current_user.org.id template.links = (params["template-links"].present? ? ActiveSupport::JSON.decode(params["template-links"]) : {"funder": [], "sample_plan": []}) if template.save! redirect_to edit_org_admin_template_path(template), notice: success_message(template_type(template), _('created')) else flash[:alert] = failed_create_error(template, template_type(template)) render partial: "org_admin/templates/new", locals: { template: template, hash: hash } end end # PUT /org_admin/templates/:id (AJAXable) # ----------------------------------------------------- def update template = Template.find(params[:id]) authorize template begin template.assign_attributes(template_params) template.links = ActiveSupport::JSON.decode(params["template-links"]) if params["template-links"].present? if template.save! render(status: :ok, json: { msg: success_message(template_type(template), _('saved'))}) else # Note failed_update_error may return HTML tags (e.g. <br/>) and therefore the client should parse them accordingly render(status: :bad_request, json: { msg: failed_update_error(template, template_type(template))}) end rescue ActiveSupport::JSON.parse_error render(status: :bad_request, json: { msg: _("Error parsing links for a #{template_type(template)}") }) and return rescue => e render(status: :forbidden, json: { msg: e.message }) and return end end # DELETE /org_admin/templates/:id # ----------------------------------------------------- def destroy template = Template.find(params[:id]) authorize template versions = Template.includes(:plans).where(family_id: template.family_id) if versions.select{|t| t.plans.length > 0 }.empty? versions.each do |version| if version.destroy! flash[:notice] = success_message(template_type(template), _('removed')) else flash[:alert] = failed_destroy_error(template, template_type(template)) end end else flash[:alert] = _("You cannot delete a #{template_type(template)} that has been used to create plans.") end redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end # GET /org_admin/templates/:id/history # ----------------------------------------------------- def history template = Template.find(params[:id]) authorize template templates = Template.where(family_id: template.family_id) render 'history', locals: { templates: templates, referrer: template.customization_of.present? ? customisable_org_admin_templates_path : organisational_org_admin_templates_path, current: templates.maximum(:version) } end # POST /org_admin/templates/:id/customize # ----------------------------------------------------- def customize template = Template.find(params[:id]) authorize template if template.customize?(current_user.org) begin customisation = template.customize!(current_user.org) redirect_to org_admin_template_path(customisation) rescue StandardError => e flash[:alert] = _('Unable to customize that template.') redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end else flash[:notice] = _('That template is not customizable.') redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end end # POST /org_admin/templates/:id/transfer_customization # the funder template's id is passed through here # ----------------------------------------------------- def transfer_customization template = Template.includes(:org).find(params[:id]) authorize template if template.upgrade_customization? begin new_customization = template.upgrade_customization! redirect_to org_admin_template_path(new_customization) rescue StandardError => e flash[:alert] = _('Unable to transfer your customizations.') redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end else flash[:notice] = _('That template is no longer customizable.') redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end end # POST /org_admin/templates/:id/copy (AJAX) # ----------------------------------------------------- def copy template = Template.find(params[:id]) authorize template begin new_copy = template.generate_copy!(current_user.org) flash[:notice] = "#{template_type(template).capitalize} was successfully copied." redirect_to edit_org_admin_template_path(new_copy) rescue StandardError => e flash[:alert] = failed_create_error(template, template_type(template)) redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end end # PATCH /org_admin/templates/:id/publish (AJAX) # ----------------------------------------------------- def publish template = Template.find(params[:id]) authorize template if template.latest? # Now make the current version published if template.update_attributes!({ published: true }) flash[:notice] = _("Your #{template_type(template)} has been published and is now available to users.") else flash[:alert] = _("Unable to publish your #{template_type(template)}.") end else flash[:alert] = _("You can not publish a historical version of this #{template_type(template)}.") end redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end # PATCH /org_admin/templates/:id/unpublish (AJAX) # ----------------------------------------------------- def unpublish template = Template.find(params[:id]) authorize template versions = Template.where(family_id: template.family_id) versions.each do |version| unless version.update_attributes!({ published: false }) flash[:alert] = _("Unable to unpublish your #{template_type(template)}.") end end flash[:notice] = _("Successfully unpublished your #{template_type(template)}") unless flash[:alert].present? redirect_to request.referrer.present? ? request.referrer : org_admin_templates_path end # GET /org_admin/template_options (AJAX) # Collect all of the templates available for the org+funder combination # -------------------------------------------------------------------------- def template_options() org_id = (plan_params[:org_id] == '-1' ? '' : plan_params[:org_id]) funder_id = (plan_params[:funder_id] == '-1' ? '' : plan_params[:funder_id]) authorize Template.new templates = [] if org_id.present? || funder_id.present? unless funder_id.blank? # Load the funder's template(s) minus the default template (that gets swapped in below if NO other templates are available) templates = Template.latest_customizable.where(org_id: funder_id).select{ |t| !t.is_default? } unless org_id.blank? # Swap out any organisational cusotmizations of a funder template templates = templates.map do |tmplt| customization = Template.published.latest_customized_version(tmplt.family_id, org_id).first # Only provide the customized version if its still up to date with the funder template! if customization.present? && !customization.upgrade_customization? customization else tmplt end end end end # If the no funder was specified OR the funder matches the org if funder_id.blank? || funder_id == org_id # Retrieve the Org's templates templates << Template.published.organisationally_visible.where(org_id: org_id, customization_of: nil).to_a end templates = templates.flatten.uniq end # If no templates were available use the default template if templates.empty? default = Template.default if default.present? customization = Template.published.latest_customized_version(default.family_id, org_id).first templates << (customization.present? ? customization : default) end end templates = (templates.count > 0 ? templates.sort{|x,y| x.title <=> y.title} : []) render json: {"templates": templates.collect{|t| {id: t.id, title: t.title} }}.to_json end # ====================================================== private def plan_params params.require(:plan).permit(:org_id, :funder_id) end def template_params params.require(:template).permit(:title, :description, :visibility, :links) end def template_type(template) template.customization_of.present? ? _('customisation') : _('template') end def get_referrer(template, referrer) if referrer.present? if referrer.end_with?(new_org_admin_template_path) || referrer.end_with?(edit_org_admin_template_path) || referrer.end_with?(org_admin_template_path) template.customization_of.present? ? customisable_org_admin_templates_path : organisational_org_admin_templates_path else request.referrer end else org_admin_templates_path end end end end