diff --git a/app/controllers/phases_controller.rb b/app/controllers/phases_controller.rb index de50db4..e800139 100644 --- a/app/controllers/phases_controller.rb +++ b/app/controllers/phases_controller.rb @@ -162,6 +162,10 @@ @phase.description = params["phase-desc"] @phase.modifiable = true if @phase.save + # Set the template's dirty flag to true + @template.dirty = true + @template.save + redirect_to admin_show_phase_path(id: @phase.id, edit: 'true'), notice: _('Information was successfully created.') else flash[:notice] = failed_create_error(@phase, _('phase')) @@ -177,6 +181,10 @@ authorize @phase @phase.description = params["phase-desc"] if @phase.update_attributes(params[:phase]) + # Set the template's dirty flag to true + @template.dirty = true + @template.save + redirect_to admin_show_phase_path(@phase), notice: _('Information was successfully updated.') else @sections = @phase.sections @@ -198,6 +206,10 @@ authorize @phase @template = @phase.template if @phase.destroy + # Set the template's dirty flag to true + @template.dirty = true + @template.save + redirect_to admin_template_template_path(@template), notice: _('Information was successfully deleted.') else @sections = @phase.sections diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index 47f9a11..3b55aa0 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -9,6 +9,10 @@ @question.guidance = params["new-question-guidance"] @question.default_value = params["new-question-default-value"] if @question.save + # Set the template's dirty flag to true + @question.section.phase.template.dirty = true + @question.section.phase.template.save + redirect_to admin_show_phase_path(id: @question.section.phase_id, section_id: @question.section_id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully created.') else @edit = (@question.section.phase.template.org == current_user.org) @@ -33,6 +37,10 @@ @section = @question.section @phase = @section.phase if @question.update_attributes(params[:question]) + # Set the template's dirty flag to true + @question.section.phase.template.dirty = true + @question.section.phase.template.save + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully updated.') else @edit = (@phase.template.org == current_user.org) @@ -53,6 +61,10 @@ @section = @question.section @phase = @section.phase if @question.destroy + # Set the template's dirty flag to true + @question.section.phase.template.dirty = true + @question.section.phase.template.save + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: _('Information was successfully deleted.') else redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: failed_destroy_error(@question, 'question') diff --git a/app/controllers/sections_controller.rb b/app/controllers/sections_controller.rb index e05418c..65d5f9f 100644 --- a/app/controllers/sections_controller.rb +++ b/app/controllers/sections_controller.rb @@ -10,6 +10,10 @@ @section.modifiable = true @phase = @section.phase if @section.save + # Set the template's dirty flag to true + @section.phase.template.dirty = true + @section.phase.template.save + redirect_to admin_show_phase_path(id: @section.phase_id, :section_id => @section.id, edit: 'true'), notice: _('Information was successfully created.') else @@ -31,6 +35,10 @@ @section.description = params["section-desc-#{params[:id]}"] @phase = @section.phase if @section.update_attributes(params[:section]) + # Set the template's dirty flag to true + @section.phase.template.dirty = true + @section.phase.template.save + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id , edit: 'true'), notice: _('Information was successfully updated.') else @edit = (@phase.template.org == current_user.org) @@ -50,6 +58,10 @@ authorize @section @phase = @section.phase if @section.destroy + # Set the template's dirty flag to true + @section.phase.template.dirty = true + @section.phase.template.save + redirect_to admin_show_phase_path(id: @phase.id, edit: 'true' ), notice: _('Information was successfully deleted.') else @edit = (@phase.template.org == current_user.org) diff --git a/app/controllers/suggested_answers_controller.rb b/app/controllers/suggested_answers_controller.rb index cfe3da0..e15d0c0 100644 --- a/app/controllers/suggested_answers_controller.rb +++ b/app/controllers/suggested_answers_controller.rb @@ -7,6 +7,10 @@ @suggested_answer = SuggestedAnswer.new(params[:suggested_answer]) authorize @suggested_answer if @suggested_answer.save + # Set the template's dirty flag to true + @suggested_answer.question.section.phase.template.dirty = true + @suggested_answer.question.section.phase.template.save + redirect_to admin_show_phase_path(id: @suggested_answer.question.section.phase_id, section_id: @suggested_answer.question.section_id, question_id: @suggested_answer.question.id, edit: 'true'), notice: _('Information was successfully created.') else @phase = @suggested_answer.question.section.phase @@ -29,6 +33,10 @@ @section = @question.section @phase = @section.phase if @suggested_answer.update_attributes(params[:suggested_answer]) + # Set the template's dirty flag to true + @phase.template.dirty = true + @phase.template.save + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, question_id: @question.id, edit: 'true'), notice: _('Information was successfully updated.') else flash[:notice] = failed_update_error(@suggested_answer, _('suggested answer')) @@ -44,6 +52,10 @@ @section = @question.section @phase = @section.phase if @suggested_answer.destroy + # Set the template's dirty flag to true + @phase.template.dirty = true + @phase.template.save + redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: _('Information was successfully deleted.') else redirect_to admin_show_phase_path(id: @phase.id, section_id: @section.id, edit: 'true'), notice: flash[:notice] = failed_destroy_error(@suggested_answer, _('suggested answer')) diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index 965aaeb..7a877bd 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -6,195 +6,210 @@ respond_to :html after_action :verify_authorized - # GET /dmptemplates + # GET /org/admin/templates/:id/admin_index + # ----------------------------------------------------- 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 - @other_published_version = {} - current_templates.keys.each do |dmptemplate_id| - @other_published_version[dmptemplate_id] = Template.where(org_id: current_user.org_id, dmptemplate_id: dmptemplate_id, published: true).present? - end - - # 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 + + # Collect all of the published funder templates + @funder_templates = [] + Org.funders.each do |org| + Template.dmptemplate_ids(org).each do |id| + template = Template.live(org, id) + # Its possible for the template to NOT have a published version + # so only add it if its not nil + unless template.nil? + @funder_templates << {current: template, live: template} 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 + + # Collect all of the organisations templates + @org_templates = [] + Template.dmptemplate_ids(current_user.org).each do |id| + template = Template.current(current_user.org, id) + live = Template.live(current_user.org, id) + + # Its possible for the template to NOT have a published version + # so only add it if its not nil + unless template.nil? + if template.customization_of.nil? + @org_templates << {current: template, live: live} + + # Check to see if this is a customization of a funder template + # If so replace the funder's copy + else + @funder_templates.delete_if{|t| + t[:current].dmptemplate_id == template.customization_of + } + @funder_templates << {current: template, live: live} + end end end + + @funder_templates = @funder_templates.sort{|x,y| + x[:current].title <=> y[:current].title + } + @org_templates = @org_templates.sort{|x,y| + x[:current].title <=> y[:current].title + } end + # PUT /org/admin/templates/:id/admin_customize + # ----------------------------------------------------- + def admin_customize + @template = Template.find(params[:id]) + authorize @template + + customisation = Template.deep_copy(@template) + customisation.org = current_user.org + customisation.version = 0 + customisation.published = false + customisation.dirty = false + customisation.customization_of = @template.dmptemplate_id + customisation.visibility = :private + + customisation.dmptemplate_id = loop do + random = rand 2147483647 # max int field in psql + break random unless Template.exists?(dmptemplate_id: random) + end + + customisation.save! + + # need to mark all of the original funder's phases, questions, + # sections as not-modifiable + customisation.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 + + redirect_to admin_template_template_path(customisation) + end + + # PUT /org/admin/templates/:id/admin_publish + # ----------------------------------------------------- + def admin_publish + @template = Template.find(params[:id]) + authorize @template - # GET /dmptemplates/1 + # Unpublish the older published version if there is one + live = Template.live(current_user.org, @template.dmptemplate_id) + unless live.nil? + live.published = false + live.save + end + + # Publish the template + @template.published = true + @template.dirty = false + @template.save + + # Create a new version + new_version = Template.deep_copy(@template) + new_version.version = (@template.version + 1) + new_version.published = false + new_version.save + + # Make all of the templates phase/section/questions as unmodifiable + @template.phases.each do |p| + p.sections.each do |s| + s.questions.each do |q| + q.modifiable = false + q.save + end + s.modifiable = false + s.save + end + p.modifiable = false + p.save + end + + redirect_to admin_index_template_path(current_user.org) + end + + # PUT /org/admin/templates/:id/admin_unpublish + # ----------------------------------------------------- + def admin_unpublish + template = Template.find(params[:id]) + authorize template + + # Unpublish the live version + @template = Template.live(current_user.org, template.dmptemplate_id) + @template.published = false + @template.save + + redirect_to admin_index_template_path(current_user.org) + end + + # GET /org/admin/templates/:id/admin_template + # ----------------------------------------------------- def admin_template @template = Template.includes(:org, phases: [sections: [questions: [:question_options, :question_format, :suggested_answers]]]).find(params[:id]) - # check to see if this is a funder template needing customized - authorize @template - 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(:org, 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.phases.includes(:sections).where(number: phase.number).first - 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.phases.includes(sections: [questions: :suggested_answers]).where(number: phase.number).first - customization_section = customization_phase.sections.where(number: section.number).first - section.questions.each do |question| - # find corresponding question in new template - customization_question = customization_section.questions.where(number: question.number).first - # 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 + + @current = Template.current(current_user.org, @template.dmptemplate_id) + + unless @template == @current + flash[:notice] = _('You are viewing a historical version of this template. You will not be able to make changes.') end - # needed for some post-migration edge cases - # some customized templates which were edited - if @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 - + # once the correct template has been generated, we convert it to hash @hash = @template.to_hash end - # PUT /dmptemplates/1 + # PUT /org/admin/templates/:id/admin_update + # ----------------------------------------------------- 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: _('Published templates cannot be edited.') and return - end - @template.description = params["template-desc"] - if @template.update_attributes(params[:template]) - if @template.published? - # unpublish older versions - Template.where("dmptemplate_id = ? AND published = ? AND version < ?", - @template.dmptemplate_id, true, @template.version).each do |t| - t.published = false - t.save - end - - # 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_template_template_path(), notice: _('Information was successfully updated.') + + current = Template.current(current_user.org, @template.dmptemplate_id) + + # Only allow the current version to be updated + if current != @template + redirect_to admin_template_template_path(@template), notice: "#{_('This is not the current version of ')} '#{@template.title}'" + else + if @template.description == params["template-desc"] || + @template.title == params[:template][:title] + @template.dirty = true + end + + @template.description = params["template-desc"] + if @template.update_attributes(params[:template]) + flash[:notice] = _('Information was successfully updated.') + + else + flash[:notice] = failed_update_error(@template, _('template')) + end + @hash = @template.to_hash - flash[:notice] = failed_update_error(@template, _('template')) render 'admin_template' - end + end end - # GET /dmptemplates/new + # GET /org/admin/templates/:id/admin_new + # ----------------------------------------------------- def admin_new authorize Template end - # POST /dmptemplates - # creates a new template with version 0 and new dmptemplate_id + # POST /org/admin/templates/:id/admin_create + # ----------------------------------------------------- def admin_create + # creates a new template with version 0 and new dmptemplate_id @template = Template.new(params[:template]) authorize @template @template.org_id = current_user.org.id @@ -219,7 +234,8 @@ end - # DELETE /dmptemplates/1 + # DELETE /org/admin/templates/:id/admin_destroy + # ----------------------------------------------------- def admin_destroy @template = Template.find(params[:id]) authorize @template @@ -232,11 +248,13 @@ end end - # GET /templates/1 + # GET /org/admin/templates/:id/admin_template_history + # ----------------------------------------------------- def admin_template_history @template = Template.find(params[:id]) authorize @template @templates = Template.where(dmptemplate_id: @template.dmptemplate_id).order(:version) + @current = Template.current(current_user.org, @template.dmptemplate_id) end end \ No newline at end of file diff --git a/app/policies/template_policy.rb b/app/policies/template_policy.rb index 3c9fb80..eeda053 100644 --- a/app/policies/template_policy.rb +++ b/app/policies/template_policy.rb @@ -20,6 +20,18 @@ def admin_template? user.can_modify_templates? && (template.org_id == user.org_id) end + + def admin_customize? + user.can_modify_templates? + end + + def admin_publish? + user.can_modify_templates? && (template.org_id == user.org_id) + end + + def admin_unpublish? + user.can_modify_templates? && (template.org_id == user.org_id) + end def admin_update? user.can_modify_templates? && (template.org_id == user.org_id) diff --git a/config/routes.rb b/config/routes.rb index 2f0a5ff..abf0ee0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -130,6 +130,9 @@ delete 'admin_destroy' post 'admin_create' put 'admin_update' + put 'admin_customize' + put 'admin_publish' + put 'admin_unpublish' end end