diff --git a/app/controllers/org_admin/templates_controller.rb b/app/controllers/org_admin/templates_controller.rb new file mode 100644 index 0000000..bed28f0 --- /dev/null +++ b/app/controllers/org_admin/templates_controller.rb @@ -0,0 +1,475 @@ +module OrgAdmin + class TemplatesController < ApplicationController + include Paginable + after_action :verify_authorized + + # GET /org_admin/templates + # ----------------------------------------------------- + def index + authorize Template + valid_orgs = current_user.can_super_admin? ? Org.not_funder : Org.find(current_user.org) + org_templates = Template.get_latest_template_versions(valid_orgs).page(1) + funder_templates = Template.get_latest_template_versions(Org.funder).page(1) + + # If the user is an Org Admin look for customizations to funder templates + customizations = {} + unless current_user.can_super_admin? + funder_templates.each do |funder_template| + customization = Template.org_customizations(funder_template.dmptemplate_id, current_user.org_id) + customizations[customization.dmptemplate_id] = customization if customization.present? + end + end + + # Gather up all of the publication dates for the live versions of each template. + published = {} + [funder_templates, org_templates].each do |collection| + collection.each do |template| + live = Template.live(template.dmptemplate_id) + published[template.dmptemplate_id] = live.updated_at if live.present? + end + end + + render 'index', locals: { + funder_templates: funder_templates, + org_templates: org_templates, + customized_templates: customizations, + published: published, + current_org: current_user.org, + orgs: Org.all + } + end + + # GET /org_admin/templates/new + # ----------------------------------------------------- + def new + authorize Template + end + + # POST /org_admin/templates + # ----------------------------------------------------- + def create + authorize Template + # creates a new template with version 0 and new dmptemplate_id + @template = Template.new(params[:template]) + @template.org_id = current_user.org.id + @template.description = params['template-desc'] + + if @template.save + redirect_to edit_org_admin_template_path(@template), notice: success_message(_('template'), _('created')) + else + @hash = @template.to_hash + flash[:alert] = failed_create_error(@template, _('template')) + render action: "new" + end + end + + # GET /org_admin/templates/:id/edit + # ----------------------------------------------------- + def edit + @template = Template.includes(:org, phases: [sections: [questions: [:question_options, :question_format, :annotations]]]).find(params[:id]) + authorize @template + + @current = Template.current(@template.dmptemplate_id) + + if @template == @current + # If the template is published + if @template.published? + # We need to create a new, editable version + new_version = Template.deep_copy(@template) + new_version.version = (@template.version + 1) + new_version.published = false + new_version.save + @template = new_version + # @current = Template.current(@template.dmptemplate_id) + end + else + flash[:notice] = _('You are viewing a historical version of this template. You will not be able to make changes.') + end + + # If the template is published + if @template.published? + # We need to create a new, editable version + 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 + @template_hash = @template.to_hash + render('container', + locals: { + partial_path: 'edit', + template: @template, + current: @current, + template_hash: @template_hash + }) + end + + # PUT /org_admin/templates/:id + # ----------------------------------------------------- + def update + @template = Template.find(params[:id]) + authorize @template + + current = Template.current(@template.dmptemplate_id) + + # Only allow the current version to be updated + if current != @template + redirect_to edit_org_admin_template_path(@template), notice: _('You can not edit a historical version of this template.') + + else + if @template.description != params["template-desc"] || + @template.title != params[:template][:title] + @template.dirty = true + end + + @template.description = params["template-desc"] + @template.links = JSON.parse(params["template-links"]) if params["template-links"].present? + + # If the visibility checkbox is not checked and the user's org is a funder set the visibility to public + # otherwise default it to organisationally_visible + if current_user.org.funder? && params[:template_visibility].nil? + @template.visibility = Template.visibilities[:publicly_visible] + else + @template.visibility = Template.visibilities[:organisationally_visible] + end + + if @template.update_attributes(params[:template]) + flash[:notice] = success_message(_('template'), _('saved')) + + else + flash[:alert] = failed_update_error(@template, _('template')) + end + + redirect_to action: 'edit', id: params[:id] + end + end + + # DELETE /org_admin/templates/:id + # ----------------------------------------------------- + def destroy + @template = Template.find(params[:id]) + authorize @template + + if @template.plans.length <= 0 + current = Template.current(@template.dmptemplate_id) + + # Only allow the current version to be destroyed + if current == @template + if @template.destroy + flash[:notice] = success_message(_('template'), _('removed')) + redirect_to org_admin_templates_path + else + @hash = @template.to_hash + flash[:alert] = failed_destroy_error(@template, _('template')) + render org_admin_templates_path + end + else + flash[:alert] = _('You cannot delete historical versions of this template.') + redirect_to org_admin_templates_path + end + else + flash[:alert] = _('You cannot delete a template that has been used to create plans.') + redirect_to org_admin_templates_path + end + end + + # GET /org_admin/templates/:id/history + # ----------------------------------------------------- + def history + @template = Template.find(params[:id]) + authorize @template + @templates = Template.where(dmptemplate_id: @template.dmptemplate_id).order(:version) + @current = Template.current(@template.dmptemplate_id) + end + + # GET /org_admin/templates/:id/customize + # ----------------------------------------------------- + def customize + @template = Template.find(params[:id]) + authorize @template + + customisation = Template.deep_copy(@template) + customisation.org = current_user.org + customisation.version = 0 + customisation.customization_of = @template.dmptemplate_id + customisation.dmptemplate_id = loop do + random = rand 2147483647 + break random unless Template.exists?(dmptemplate_id: random) + end + customisation.dirty = true + customisation.save + + 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 edit_org_admin_template_path(customisation) + end + + # GET /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 + 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 + new_customization.dirty = true + 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: :annotations]]).where(org_id: current_user.org_id, customization_of: @template.dmptemplate_id).order(version: :desc) + # existing version 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 customzed 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: :annotations]).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 annotations + question.annotations.where(org_id: current_user.org_id).each do |annotation| + annotation_copy = Annotation.deep_copy(annotation) + annotation_copy.question_id = customization_question.id + annotation_copy.save! + end + end + end + end + end + end + new_customization.save + redirect_to edit_org_admin_template_path(new_customization) + end + + + # GET /org_admin/templates/funders/:page (AJAX) + # ----------------------------------------------------- + def funders + authorize Template + if params[:page] == 'ALL' + templates = Template.get_latest_template_versions(Org.funder) + else + templates = Template.get_latest_template_versions(Org.funder).page(params[:page]) + end + # Include the default template in the list of funder templates + templates << Template.default + + # If the user is an Org Admin look for customizations to funder templates + customizations = [] + unless current_user.can_super_admin? + templates.each do |funder_template| + customization = Template.org_customizations(funder_template.id, current_user.org_id) + customizations << customization if customization.present? + end + end + + # Gather up all of the publication dates for the live versions of each template. + published = {} + templates.each do |template| + live = Template.live(template.dmptemplate_id) + published[template.dmptemplate_id] = live.updated_at if live.present? + end + + paginable_renderise(partial: 'funder_templates_list', scope: templates, + locals: {current_org: current_user.org.id, customizations: customizations, published: published}) + end + + # GET /org_admin/templates/orgs/:page (AJAX) + # ----------------------------------------------------- + def orgs + authorize Template + valid_orgs = current_user.can_super_admin? ? Org.not_funder : Org.find(current_user.org) + if params[:page] == 'ALL' + templates = Template.get_latest_template_versions(valid_orgs) + else + templates = Template.get_latest_template_versions(valid_orgs).page(params[:page]) + end + + # Gather up all of the publication dates for the live versions of each template. + published = {} + templates.each do |template| + live = Template.live(template.dmptemplate_id) + published[template.dmptemplate_id] = live.updated_at if live.present? + end + + paginable_renderise(partial: 'templates_list', scope: templates, locals: {current_org: current_user.org.id, published: published}) + end + + # PUT /org_admin/templates/:id/copy (AJAX) + # ----------------------------------------------------- + def copy + @template = Template.find(params[:id]) + authorize @template + + new_copy = Template.deep_copy(@template) + new_copy.title = "Copy of " + @template.title + new_copy.version = 0 + new_copy.published = false + new_copy.dmptemplate_id = loop do + random = rand 2147483647 + break random unless Template.exists?(dmptemplate_id: random) + end + + if new_copy.save + flash[:notice] = 'Template was successfully copied.' + redirect_to edit_org_admin_template_path(id: new_copy.id, edit: true), notice: _('Information was successfully created.') + else + flash[:alert] = failed_create_error(new_copy, _('template')) + end + + end + + # PUT /org_admin/templates/:id/publish (AJAX) + # ----------------------------------------------------- + def publish + @template = Template.find(params[:id]) + authorize @template + + current = Template.current(@template.dmptemplate_id) + + # Only allow the current version to be updated + if current != @template + redirect_to org_admin_templates_path, alert: _('You can not publish a historical version of this template.') + + else + # Unpublish the older published version if there is one + live = Template.live(@template.dmptemplate_id) + if !live.nil? and self != live + live.published = false + live.save! + end + # Set the dirty flag to false + @template.dirty = false + @template.published = true + @template.save + + flash[:notice] = _('Your template has been published and is now available to users.') + + redirect_to org_admin_templates_path + end + end + + # PUT /org_admin/templates/:id/unpublish (AJAX) + # ----------------------------------------------------- + def unpublish + template = Template.find(params[:id]) + authorize template + + # Unpublish the live version + @template = Template.live(template.dmptemplate_id) + + if @template.nil? + flash[:alert] = _('That template is not currently published.') + else + @template.published = false + @template.save + flash[:notice] = _('Your template is no longer published. Users will not be able to create new DMPs for this template until you re-publish it') + end + + redirect_to org_admin_templates_path + end + + # PUT /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? + if funder_id.blank? + # Load the org's template(s) + if org_id.present? + org = Org.find(org_id) + templates = Template.valid.where(published: true, org: org, customization_of: nil).to_a + end + + else + funder = Org.find(funder_id) + # Load the funder's template(s) + templates = Template.valid.where(published: true, org: funder).to_a + + if org_id.present? + org = Org.find(org_id) + + # Swap out any organisational cusotmizations of a funder template + templates.each do |tmplt| + customization = Template.valid.find_by(published: true, org: org, customization_of: tmplt.dmptemplate_id) + if customization.present? && tmplt.updated_at < customization.created_at + templates.delete(tmplt) + templates << customization + end + end + end + end + end + + # If no templates were available use the generic templates + if templates.empty? + templates << Template.where(is_default: true, published: true).first + 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 + end +end \ No newline at end of file diff --git a/app/controllers/phases_controller.rb b/app/controllers/phases_controller.rb index 18e58f6..b93ac76 100644 --- a/app/controllers/phases_controller.rb +++ b/app/controllers/phases_controller.rb @@ -106,7 +106,7 @@ else @original_org = @phase.template.org end - render('/templates/container', + render('/org_admin/templates/container', locals: { partial_path: 'admin_show', phase: @phase, @@ -132,7 +132,7 @@ @phase.template = @template authorize @phase @phase.number = @template.phases.count + 1 - render('/templates/container', + render('/org_admin/templates/container', locals: { partial_path: 'admin_add', template: @template @@ -155,7 +155,7 @@ else flash[:alert] = failed_create_error(@phase, _('phase')) @template = @phase.template - redirect_to admin_template_template_path(id: @phase.template_id) + redirect_to edit_org_admin_template_path(id: @phase.template_id) end end @@ -198,7 +198,7 @@ @template.dirty = true @template.save! - redirect_to admin_template_template_path(@template), notice: success_message(_('phase'), _('deleted')) + redirect_to edit_org_admin_template_path(@template), notice: success_message(_('phase'), _('deleted')) else @sections = @phase.sections diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 89c03ae..3bae0a0 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -18,8 +18,8 @@ authorize @plan # Get all of the available funders and non-funder orgs - @funders = Org.funders.joins(:templates).where(templates: {published: true}).uniq.sort{|x,y| x.name <=> y.name } - @orgs = (Org.institutions + Org.managing_orgs).flatten.uniq.sort{|x,y| x.name <=> y.name } + @funders = Org.funder.joins(:templates).where(templates: {published: true}).uniq.sort{|x,y| x.name <=> y.name } + @orgs = (Org.institution + Org.managing_orgs).flatten.uniq.sort{|x,y| x.name <=> y.name } # Get the current user's org @default_org = current_user.org if @orgs.include?(current_user.org) diff --git a/app/controllers/public_pages_controller.rb b/app/controllers/public_pages_controller.rb index cdf5041..fe8c78a 100644 --- a/app/controllers/public_pages_controller.rb +++ b/app/controllers/public_pages_controller.rb @@ -4,7 +4,7 @@ # GET template_index # ----------------------------------------------------- def template_index - template_ids = Template.where(org_id: Org.funders.pluck(:id), visibility: Template.visibilities[:publicly_visible]).valid.pluck(:dmptemplate_id).uniq << Template.where(is_default: true, published: true).pluck(:dmptemplate_id) + template_ids = Template.where(org_id: Org.funder.pluck(:id), visibility: Template.visibilities[:publicly_visible]).valid.pluck(:dmptemplate_id).uniq << Template.where(is_default: true, published: true).pluck(:dmptemplate_id) @templates = [] template_ids.flatten.each do |tid| t = Template.live(tid) diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb deleted file mode 100644 index 0fdb404..0000000 --- a/app/controllers/templates_controller.rb +++ /dev/null @@ -1,431 +0,0 @@ -# [+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 - helper TemplateHelper - # GET /org/admin/templates/:id/admin_index - # ----------------------------------------------------- - def admin_index - authorize Template - - funder_templates, org_templates, organisation_templates = [], [], [] - - # Get all of the unique template family ids (dmptemplate_id) for each funder and the current org - funder_ids = Template.valid_published().joins(:org).where(Org.funder_condition).pluck(:dmptemplate_id) - org_ids = current_user.org.templates.where(customization_of: nil).valid.collect{|t| t.dmptemplate_id }.flatten.uniq - organisation_ids = Template.valid_published(is_default: true).joins(:org) - .where(Org.organisation_condition).where(["org_id <> ?", current_user.org_id]).pluck(:dmptemplate_id) - - org_ids.each do |id| - current = Template.current(id) - live = Template.live(id) - org_templates << {current: current, live: live} - end - funder_ids.each do |id| - funder_live = Template.live(id) - current = Template.org_customizations(id, current_user.org_id) - # if we have a current template, check to see if there is a live version - live = current.nil? ? nil : Template.live(current.dmptemplate_id) - # need a current version, default to funder live if no custs exist - current = funder_live unless current.present? - - funder_templates << {current: current, live: live, funder_live: funder_live, stale: funder_live.updated_at > current.created_at} - end - - organisation_ids.each do |id| - organisation_live = Template.live(id) - current = Template.org_customizations(id, current_user.org_id) - live = current.present? ? Template.live(current.dmptemplate_id) : nil - current = organisation_live unless current.present? - organisation_templates << { current: current, live: live, organisation_live: organisation_live, stale: organisation_live.updated_at > current.created_at } - 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 - } - @organisation_templates = organisation_templates.sort{|x,y| - x[:current].title <=> y[:current].title - } - end - - # GET /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.customization_of = @template.dmptemplate_id - customisation.dmptemplate_id = loop do - random = rand 2147483647 - break random unless Template.exists?(dmptemplate_id: random) - end - customisation.dirty = true - customisation.save - - 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 - - # GET /org/admin/templates/:id/admin_transfer_customization - # the funder template's id is passed through here - # ----------------------------------------------------- - def admin_transfer_customization - @template = Template.includes(:org).find(params[:id]) - authorize @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 - new_customization.dirty = true - 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: :annotations]]).where(org_id: current_user.org_id, customization_of: @template.dmptemplate_id).order(version: :desc) - # existing version 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 customzed 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: :annotations]).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 annotations - question.annotations.where(org_id: current_user.org_id).each do |annotation| - annotation_copy = Annotation.deep_copy(annotation) - annotation_copy.question_id = customization_question.id - annotation_copy.save! - end - end - end - end - end - end - new_customization.save - redirect_to admin_template_template_path(new_customization) - end - - # PUT /org/admin/templates/:id/admin_publish - # ----------------------------------------------------- - def admin_publish - @template = Template.find(params[:id]) - authorize @template - - current = Template.current(@template.dmptemplate_id) - - # Only allow the current version to be updated - if current != @template - redirect_to admin_template_template_path(@template), alert: _('You can not publish a historical version of this template.') - - else - # Unpublish the older published version if there is one - live = Template.live(@template.dmptemplate_id) - if !live.nil? and self != live - live.published = false - live.save! - end - # Set the dirty flag to false - @template.dirty = false - @template.published = true - @template.save - - flash[:notice] = _('Your template has been published and is now available to users.') - - redirect_to admin_index_template_path(current_user.org) - end - 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(template.dmptemplate_id) - - if @template.nil? - flash[:alert] = _('That template is not currently published.') - else - @template.published = false - @template.save - flash[:notice] = _('Your template is no longer published. Users will not be able to create new DMPs for this template until you re-publish it') - end - - 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, :annotations]]]).find(params[:id]) - authorize @template - - @current = Template.current(@template.dmptemplate_id) - - if @template == @current - # If the template is published - if @template.published? - # We need to create a new, editable version - new_version = Template.deep_copy(@template) - new_version.version = (@template.version + 1) - new_version.published = false - new_version.save - @template = new_version -# @current = Template.current(@template.dmptemplate_id) - end - else - flash[:notice] = _('You are viewing a historical version of this template. You will not be able to make changes.') - end - - # If the template is published - if @template.published? - # We need to create a new, editable version - 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 - @template_hash = @template.to_hash - render('container', - locals: { - partial_path: 'admin_template', - template: @template, - current: @current, - template_hash: @template_hash - }) - end - - - # PUT /org/admin/templates/:id/admin_update - # ----------------------------------------------------- - def admin_update - @template = Template.find(params[:id]) - authorize @template - - current = Template.current(@template.dmptemplate_id) - - # Only allow the current version to be updated - if current != @template - redirect_to admin_template_template_path(@template), notice: _('You can not edit a historical version of this template.') - - else - if @template.description != params["template-desc"] || - @template.title != params[:template][:title] - @template.dirty = true - end - - @template.description = params["template-desc"] - @template.links = JSON.parse(params["template-links"]) if params["template-links"].present? - - # If the visibility checkbox is not checked and the user's org is a funder set the visibility to public - # otherwise default it to organisationally_visible - if current_user.org.funder? && params[:template_visibility].nil? - @template.visibility = Template.visibilities[:publicly_visible] - else - @template.visibility = Template.visibilities[:organisationally_visible] - end - - if @template.update_attributes(params[:template]) - flash[:notice] = success_message(_('template'), _('saved')) - - else - flash[:alert] = failed_update_error(@template, _('template')) - end - - redirect_to action: 'admin_template', id: params[:id] - end - end - - - # GET /org/admin/templates/:id/admin_new - # ----------------------------------------------------- - def admin_new - authorize Template - end - - - # 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 - @template.description = params['template-desc'] - - if @template.save - redirect_to admin_template_template_path(@template), notice: success_message(_('template'), _('created')) - else - @hash = @template.to_hash - flash[:alert] = failed_create_error(@template, _('template')) - render action: "admin_new" - end - end - - - # DELETE /org/admin/templates/:id/admin_destroy - # ----------------------------------------------------- - def admin_destroy - @template = Template.find(params[:id]) - authorize @template - - current = Template.current(@template.dmptemplate_id) - - # Only allow the current version to be destroyed - if current == @template - if @template.destroy - redirect_to admin_index_template_path - else - @hash = @template.to_hash - flash[:notice] = failed_destroy_error(@template, _('template')) - render admin_template_template_path(@template) - end - else - flash[:alert] = _('You cannot delete historical versions of this template.') - redirect_to admin_index_template_path - end - end - - # 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(@template.dmptemplate_id) - end - - # PUT /org/admin/templates/:id/admin_copy - # ----------------------------------------------------- - def admin_copy - @template = Template.find(params[:id]) - authorize @template - - new_copy = Template.deep_copy(@template) - new_copy.title = "Copy of " + @template.title - new_copy.version = 0 - new_copy.published = false - new_copy.dmptemplate_id = loop do - random = rand 2147483647 - break random unless Template.exists?(dmptemplate_id: random) - end - - if new_copy.save - flash[:notice] = 'Template was successfully copied.' - redirect_to admin_template_template_path(id: new_copy.id, edit: true), notice: _('Information was successfully created.') - else - flash[:alert] = failed_create_error(new_copy, _('template')) - end - - end - - # 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? - if funder_id.blank? - # Load the org's template(s) - if org_id.present? - org = Org.find(org_id) - templates = Template.valid.where(published: true, org: org, customization_of: nil).to_a - end - - else - funder = Org.find(funder_id) - # Load the funder's template(s) - templates = Template.valid.where(published: true, org: funder).to_a - - if org_id.present? - org = Org.find(org_id) - - # Swap out any organisational cusotmizations of a funder template - templates.each do |tmplt| - customization = Template.valid.find_by(published: true, org: org, customization_of: tmplt.dmptemplate_id) - if customization.present? && tmplt.updated_at < customization.created_at - templates.delete(tmplt) - templates << customization - end - end - end - end - end - - # If no templates were available use the generic templates - if templates.empty? - templates << Template.where(is_default: true, published: true).first - 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 - -end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 51d9e30..996a33d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -78,8 +78,33 @@ redirect_to "#{edit_user_registration_path}\#notification-preferences", notice: success_message(_('preferences'), _('saved')) end + # PUT /users/:id/org_swap (AJAX) + # ----------------------------------------------------- + def org_swap + # Allows the user to swap their org affiliation on the fly + authorize current_user + org = Org.find(org_swap_params[:org_id]) + if org.present? + current_user.org = org + if current_user.save! + render json: { + msg: _('Your organisation affiliation has been changed. You may now edit templates for %{org_name}.') % {org_name: current_user.org.name} + }.to_json + else + render json: { + err: _('Unable to change your organisation affiliation at this time.') + }.to_json + end + else + render json: {}.to_json + end + end + private - + def org_swap_params + params.require(:user).permit(:org_id, :org_name) + end + ## # html forms return our boolean values as strings, this converts them to true/false def booleanize_hash(node) diff --git a/app/models/guidance.rb b/app/models/guidance.rb index ca9ab48..24c1cc0 100644 --- a/app/models/guidance.rb +++ b/app/models/guidance.rb @@ -98,7 +98,7 @@ end # guidance groups are viewable if they are owned by a funder - if Org.funders.include?(guidance.guidance_group.org) + if Org.funder.include?(guidance.guidance_group.org) viewable = true end end @@ -119,7 +119,7 @@ def self.all_viewable(user) managing_groups = Org.includes(guidance_groups: :guidances).managing_orgs.collect{|o| o.guidance_groups} # find all groups owned by a Funder organisation - funder_groups = Org.includes(guidance_groups: :guidances).funders.collect{|org| org.guidance_groups} + funder_groups = Org.includes(guidance_groups: :guidances).funder.collect{|org| org.guidance_groups} # find all groups owned by any of the user's organisations organisation_groups = user.org.guidance_groups diff --git a/app/models/guidance_group.rb b/app/models/guidance_group.rb index c4bc700..8974a37 100644 --- a/app/models/guidance_group.rb +++ b/app/models/guidance_group.rb @@ -106,7 +106,7 @@ managing_org_groups = Org.includes(guidance_groups: [guidances: :themes]).managing_orgs.collect{|org| org.guidance_groups} # find all groups owned by a Funder organisation - funder_groups = Org.includes(:guidance_groups).funders.collect{|org| org.guidance_groups} + funder_groups = Org.includes(:guidance_groups).funder.collect{|org| org.guidance_groups} organisation_groups = [user.org.guidance_groups] diff --git a/app/models/org.rb b/app/models/org.rb index df88458..a9f0e3c 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -60,9 +60,6 @@ # Predefined queries for retrieving the managain organisation and funders scope :managing_orgs, -> { where(abbreviation: Rails.configuration.branding[:organisation][:abbreviation]) } - scope :funders, -> { where(org_type: 2) } - scope :institutions, -> { where(org_type: 1) } - # EVALUATE CLASS AND INSTANCE METHODS BELOW # diff --git a/app/models/template.rb b/app/models/template.rb index 65a10ea..d0d076b 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -80,6 +80,22 @@ Template.where(customization_of: dmptemplate_id, org_id: org_id).order(version: :desc).valid.first end + def self.get_latest_template_versions(orgs) + # get the unique dmptemplate_ids (template version families) + families = Template.valid.where(org: orgs, customization_of: nil).pluck(:dmptemplate_id) + + # return the most current versions of each template version family + id_query = "SELECT templates.dmptemplate_id, templates.id, current.version "\ + "FROM "\ + "(SELECT MAX(version) AS version, dmptemplate_id "\ + "FROM templates WHERE dmptemplate_id in (#{families.join(', ')}) "\ + "GROUP BY dmptemplate_id) as current "\ + "INNER JOIN templates ON current.version = templates.version AND current.dmptemplate_id = templates.dmptemplate_id;" + + ids = Template.find_by_sql(id_query).collect{|t| t.id } + Template.includes(:org).where(id: ids).order('orgs.name, templates.title') + end + ## # deep copy the given template and all of it's associations # diff --git a/app/policies/template_policy.rb b/app/policies/template_policy.rb index 157e9c3..64cf610 100644 --- a/app/policies/template_policy.rb +++ b/app/policies/template_policy.rb @@ -1,11 +1,67 @@ class TemplatePolicy < ApplicationPolicy attr_reader :user, :template - - def initialize(user, template) - raise Pundit::NotAuthorizedError, "must be logged in" unless user + + def initialize(user, template = Template.new) + raise Pundit::NotAuthorizedError, _("must be logged in") unless user.is_a?(User) @user = user @template = template end + + def index? + user.can_super_admin? || user.can_modify_templates? + end + + def new? + user.can_super_admin? || user.can_modify_templates? + end + + def create? + user.can_super_admin? || user.can_modify_templates? + end + + def edit? + user.can_super_admin? || (user.can_modify_templates? && template.org_id == user.org_id) + end + + def update? + user.can_super_admin? || (user.can_modify_templates? && template.org_id == user.org_id) + end + + def destroy? + user.can_super_admin? || (user.can_modify_templates? && (template.org_id == user.org_id)) + end + + def history? + user.can_super_admin? || (user.can_modify_templates? && template.org_id == user.org_id) + end + + def customize? + user.can_super_admin? || user.can_modify_templates? + end + + def transfer_customization? + user.can_super_admin? || user.can_modify_templates? + end + + # Pagination + def funders? + user.can_super_admin? || user.can_modify_templates? + end + def orgs? + user.can_super_admin? || user.can_modify_templates? + end + + # AJAX Calls + def copy? + user.can_super_admin? || (user.can_modify_templates? && (template.org_id == user.org_id)) + end + def publish? + user.can_super_admin? || (user.can_modify_templates? && (template.org_id == user.org_id)) + end + def unpublish? + user.can_super_admin? || (user.can_modify_templates? && (template.org_id == user.org_id)) + end + ## # Users can modify templates if: @@ -13,64 +69,13 @@ # - The template which they are modifying belongs to their org ## - def admin_index? - user.can_modify_templates? - end - 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) - end - - def admin_new? - user.can_modify_templates? - end - - def admin_create? - user.can_modify_templates? && (template.org_id.nil? || (template.org_id == user.org_id)) - end - - def admin_destroy? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_template_history? - user.can_modify_templates? && (template.org_id == user.org_id) - end - - def admin_transfer_customization? - user.can_modify_templates? - end - - def admin_copy? - user.can_modify_templates? && (template.org_id == user.org_id) - end - # Anyone with an account should be able to get templates for the sepecified research_org + funder # This policy is applicable to the Create Plan page def template_options? user.present? end - class Scope < Scope - def resolve - scope.where(org_id: user.org_id) - end - end -end +end \ No newline at end of file diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index a97a91b..abe3184 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -19,6 +19,11 @@ @user.can_grant_permissions? && (@users.org_id == @user.org_id) end + # Allows the user to swap their org affiliation on the fly + def org_swap? + user.can_super_admin? + end + class Scope < Scope def resolve scope.where(org_id: user.org_id) diff --git a/app/views/layouts/_branding.html.erb b/app/views/layouts/_branding.html.erb index 6705e94..9e5ddd3 100644 --- a/app/views/layouts/_branding.html.erb +++ b/app/views/layouts/_branding.html.erb @@ -35,68 +35,52 @@ <% end %> <% end %> - -
diff --git a/app/views/org_admin/templates/_admin_nav_tabs.html.erb b/app/views/org_admin/templates/_admin_nav_tabs.html.erb new file mode 100644 index 0000000..70dd9d1 --- /dev/null +++ b/app/views/org_admin/templates/_admin_nav_tabs.html.erb @@ -0,0 +1,17 @@ + diff --git a/app/views/org_admin/templates/_edit.html.erb b/app/views/org_admin/templates/_edit.html.erb new file mode 100644 index 0000000..bb4b6a7 --- /dev/null +++ b/app/views/org_admin/templates/_edit.html.erb @@ -0,0 +1,44 @@ ++ <% if template_hash[:live].nil? %> + <%= _('Unpublished') %> + <% elsif template_hash[:current].dirty? %> + <%= _('You have un-published changes') %> + <% else %> + <%= _('Published') %> + <% end %> +
++ <%= l template.created_at.to_date, formats: :short %> +
++ <%= l template.updated_at.to_date, formats: :short %> +
+| + <%= render(partial: "shared/table_filter", locals: { placeholder: _('Search')}) %> + | +||||
|---|---|---|---|---|
| <%= _('Template Name') %> | +<%= _('Funder') %> | +<%= _('Status') %> | +<%= _('Edited Date') %> | ++ |
| + <%= template.title %> + | ++ <%= raw template.org.name %> + | ++ <% if current_user.can_super_admin? %> + <% if !published[template.dmptemplate_id].present? %> + <%= _('Unpublished') %> + <% elsif template.dirty? %> + <%= _('Unpublished changes') %> + <% else %> + <%= _('Published') %> + <% end %> + <% else %> + <% if customization.present? %> + + <% if customization.updated_at < template.updated_at %> + <%= _('Original funder template has changed!')%> + <% elsif !template.published? %> + + <%= b_label = _('Funder version is un-published') %> + <% elsif customization.dirty? %> + <%= _('You have un-published changes') %> + <% else %> + <%= _('Published') %> + <% end %> + <% else %> + <%= _('Not Customised') %> + <% end %> + <% end %> + | ++ <% last_temp_updated = template.updated_at %> + <%= l last_temp_updated.to_date, formats: :short %> + | ++ + | +
+ <%= raw phase.description %> +
+| <%= _('Sections')%> | +<%= _('Questions')%> | +
|---|---|
|
+ <%= section[:data].title %> + |
+
+ <% if section[:questions].present? %>
+
|
+
| + <%= render(partial: "shared/table_filter", locals: { placeholder: _('Search')}) %> + | +||||
|---|---|---|---|---|
| <%= _('Template Name') %> | +<%= current_user.can_super_admin? ? _('Organisation') : _('Description') %> | +<%= _('Status') %> | +<%= _('Edited Date') %> | ++ |
| + <%= template.title %> + | ++ <%= current_user.can_super_admin? ? template.org.name : raw(template.description) %> + | ++ <% if !published[template.dmptemplate_id].present? %> + <%= _('Unpublished') %> + <% elsif template.dirty? %> + <%= _('Unpublished changes') %> + <% else %> + <%= _('Published') %> + <% end %> + | ++ <% last_temp_updated = template.updated_at %> + <%= l last_temp_updated.to_date, formats: :short %> + | ++ + | +
<%= _('Here you can view previously published versions of your template. These can no longer be modified.')%>
+| <%= _('Title') %> | +<%= _('Version') %> | +<%= _('Published') %> | +<%= _('Last updated') %> | +<%= _('Actions') %> | +
|---|---|---|---|---|
| + <%= org_template.title%> + <% if org_template == @current && !org_template.published%> + <%=_('Draft')%> + <% end %> + | ++ <%= org_template.version %> + | ++ <%= (org_template.published? ? _('Yes') : _('No')) %> + | ++ <% last_temp_updated = org_template.updated_at %> + <% org_template.phases.each do |phase|%> + <% if org_template.updated_at.to_date < phase.updated_at.to_date %> + <% last_temp_updated = phase.updated_at %> + <% end %> + <% end %> + <%= l last_temp_updated.to_date, formats: :short %> + | ++ <%= link_to (org_template == @current ? _('Edit') : _('View')), edit_org_admin_template_path(id: org_template), class: "dmp_table_link"%> + | +
<%= _('This template is new and does not yet have any publication history.') %>
+ <% end %> +<%= _('If you would like to modify one of the templates below, you must first change your organisation affiliation.') %>
++ <%= _('If you wish to add an institutional template for a Data Management Plan, use the \'create template\' button. You can create more than one template if desired e.g. one for researchers and one for PhD students. Your template will be presented to users within your institution when no funder templates apply. If you want to add questions to funder templates use the \'customise template\' options below.') %> +
+<%= _('There are currently no templates defined for your organisation.') %> + <% end %> +
<%= _('There are currently no funder templates.') %> + <% end %> +
To create a new template, first enter a title and description. Once you have saved this you will be presented with options to add one or more phases.
')%> + <%= form_for :template, url: {action: "create"} do |f| %> +- <% if template_hash[:live].nil? %> - <%= _('Unpublished') %> - <% elsif template_hash[:current].dirty? %> - <%= _('You have un-published changes') %> - <% else %> - <%= _('Published') %> - <% end %> -
-- <%= l template.created_at.to_date, formats: :short %> -
-- <%= l template.updated_at.to_date, formats: :short %> -
-| <%= _('Title') %> | -<%= _('Description') %> | -<%= _('Status') %> | -<%= _('Last updated') %> | -- |
|---|---|---|---|---|
| <%= hash[:current].title%> | -<%= raw hash[:current].description.truncate(90, omission: _('... (continued)')) %> | -- - <% if hash[:current].customization_of.nil? %> - - <%= _('N/A') %> - <% else %> - - <% if hash[:stale] %> - <%= _('Original funder template has changed!')%> - <% elsif hash[:live].nil? %> - - <%= b_label = _('Un-published') %> - <% elsif hash[:current].dirty? %> - <%= _('You have un-published changes') %> - <% else %> - <%= _('Published') %> - <% end %> - <% end %> - | -- <% last_updated = hash[:current].updated_at %> - <%= l last_updated.to_date, formats: :short %> - | -
-
-
-
-
- |
-
- <%= raw phase.description %> -
-| <%= _('Sections')%> | -<%= _('Questions')%> | -
|---|---|
|
- <%= section[:data].title %> - |
-
- <% if section[:questions].present? %>
-
|
-
- <%= _("If you wish to add an institutional template for a Data Management Plan, use the 'create template' button. You can create more than one template if desired e.g. one for researchers and one for PhD students.") %> -
-- <%= _("Your template will be presented to users within your institution when no funder templates apply. If you want to add questions to funder templates use the 'customise template' options below.") %> -
-| <%= _('Title') %> | -<%= _('Description') %> | -<%= _('Status') %> | -<%= _('Last updated') %> | -- |
|---|---|---|---|---|
| - <%= hash[:current].title %> - | -- <%= raw hash[:current].description.truncate(90, omission: _('... (continued)')) unless hash[:current].description.nil? %> - | -- <% if hash[:live].nil? %> - <%= _('Unpublished') %> - - <% elsif hash[:current].dirty? %> - <%= _('Unpublished changes') %> - - <% else %> - <%= _('Published') %> - <% end %> - | -- <% last_temp_updated = hash[:current].updated_at %> - <%= l last_temp_updated.to_date, formats: :short %> - | -
-
-
-
- |
-
To create a new template, first enter a title and description. Once you have saved this you will be presented with options to add one or more phases.
')%> - <%= form_for :template, url: {action: "admin_create"} do |f| %> -<%= _('Here you can view previously published versions of your template. These can no longer be modified.')%>
-| <%= _('Title') %> | -<%= _('Version') %> | -<%= _('Published') %> | -<%= _('Last updated') %> | -<%= _('Actions') %> | -
|---|---|---|---|---|
| - <%= org_template.title%> - <% if org_template == @current && !org_template.published%> - <%=_('Draft')%> - <% end %> - | -- <%= org_template.version %> - | -- <%= (org_template.published? ? _('Yes') : _('No')) %> - | -- <% last_temp_updated = org_template.updated_at %> - <% org_template.phases.each do |phase|%> - <% if org_template.updated_at.to_date < phase.updated_at.to_date %> - <% last_temp_updated = phase.updated_at %> - <% end %> - <% end %> - <%= l last_temp_updated.to_date, formats: :short %> - | -- <%= link_to (org_template == @current ? _('Edit') : _('View')), admin_template_template_path(id: org_template), class: "dmp_table_link"%> - | -
<%= _('This template is new and does not yet have any publication history.') %>
- <% end %> -