-
<%= _('All Templates') %>
- <%= paginable_renderise(
- partial: 'paginable/templates/all',
- controller: 'paginable/templates',
- action: 'all',
- scope: all_templates,
- query_params: { sort_field: 'templates.title', sort_direction: :asc },
- locals: {current_org: current_org.id, published: published, scopes: scopes[:all], hide_actions: true}) %>
+
+
+
+
<%= title %>
+
+ <% filter_path = "/paginable/templates/#{action}/#{1}" %>
+ <% qry = query_params.collect{ |k,v| "#{k}=#{v}" }.join('&') %>
+
+ <% if isActivePage(customisable_org_admin_templates_path) %>
+ <%= link_to _('All (%{count})') % { count: all_count}, "#{filter_path}?#{qry}", 'data-remote': "true" %>
+ <%= link_to _('Published (%{count})') % { count: published_count}, "#{filter_path}?f=published{qry}", 'data-remote': "true" %>
+ <%= link_to _('Unpublished (%{count})') % { count: unpublished_count}, "#{filter_path}?f=unpublished{qry}", 'data-remote': "true" %>
+ <%= link_to _('Not customised (%{count})') % { count: not_customized_count}, "#{filter_path}?f=not-customised{qry}", 'data-remote': "true" %>
+ <% else %>
+ <%= link_to _('All (%{count})') % { count: all_count}, "#{filter_path}?#{qry}", 'data-remote': "true" %>
+ <%= link_to _('Published (%{count})') % { count: published_count}, "#{filter_path}?f=published{qry}", 'data-remote': "true" %>
+ <%= link_to _('Unpublished (%{count})') % { count: unpublished_count}, "#{filter_path}?f=unpublished{qry}", 'data-remote': "true" %>
+ <% end %>
+
+
+ <%= paginable_renderise(
+ partial: "paginable/templates/#{action}",
+ controller: 'paginable/templates',
+ action: action,
+ scope: templates,
+ query_params: { sort_field: 'templates.title', sort_direction: :asc },
+ locals: local_assigns) %>
+
- <% end %>
-
-
<%= current_user.can_super_admin? ? _('%{org_name} Templates') % { org_name: current_user.org.name } : _('Own Templates') %>
- <%= paginable_renderise(
- partial: 'paginable/templates/orgs',
- controller: 'paginable/templates',
- action: 'orgs',
- scope: own_templates,
- query_params: { sort_field: 'templates.title', sort_direction: :asc },
- locals: {current_org: current_org.id, published: published, scopes: scopes[:orgs], hide_actions: false}) %>
-
- <% if !current_org.funder_only? %>
-
-
<%= _('Customizable Templates') %>
- <%= paginable_renderise(
- partial: 'paginable/templates/funders',
- controller: 'paginable/templates',
- action: 'funders',
- scope: customizable_templates,
- query_params: { sort_field: 'templates.title', sort_direction: :asc },
- locals: {current_org: current_org.id, customizations: customized_templates, published: published, scopes: scopes[:funders]}) %>
-
- <% end %>
diff --git a/app/views/org_admin/templates/new.html.erb b/app/views/org_admin/templates/new.html.erb
deleted file mode 100644
index facbe19..0000000
--- a/app/views/org_admin/templates/new.html.erb
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
- <%= _('New template') %>
-
-
- <%= link_to _('View all templates'), "#{org_admin_templates_path}#organisation-templates", class: "btn btn-primary" %>
-
-
-
-
-
- <%= raw _('
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| %>
-
- <%= f.label(:title, _('Title') ,class: 'control-label') %>
- <%= f.text_field :title, as: :string,
- class: "form-control", "data-toggle": "tooltip", title: _('Please enter a title for your template.') %>
-
-
-
- <% end %>
-
-
\ No newline at end of file
diff --git a/app/views/paginable/orgs/_index.html.erb b/app/views/paginable/orgs/_index.html.erb
index 7dd18b6..21a92f8 100644
--- a/app/views/paginable/orgs/_index.html.erb
+++ b/app/views/paginable/orgs/_index.html.erb
@@ -15,7 +15,7 @@
<%= org.name %>
<%= org.contact_email %>
<%= org.org_type_to_s %>
-
<%= org.templates.collect(&:dmptemplate_id).uniq.length %>
+
<%= org.templates.collect(&:family_id).uniq.length %>
-
-
-
-
- <% if scopes.present? %>
-
- <% scopes.keys.each do |k| %>
- <% unless k == :dmptemplate_ids %>
- <%= link_to "#{k.capitalize} (#{scopes[k]})",
- "#{all_paginable_templates_path(1)}?scope=#{k}",
- class: 'template-scope', 'data-remote': true %>
- <% end %>
- <% end %>
-
- <% end %>
-
- <%= _('Template Name') %> <%= paginable_sort_link('templates.title') %>
- <%= _('Organisation') %> <%= paginable_sort_link('orgs.name') %>
- <%= _('Status') %> <%= paginable_sort_link('templates.published') %>
- <%= _('Edited Date') %> <%= paginable_sort_link('templates.updated_at') %>
-
-
-
- <% scope.each do |template| %>
-
-
- <%= template.title %>
-
-
- <%= template.org.name %>
-
-
- <% if template.dirty? %>
- <%= _('Unpublished changes') %>
- <% elsif template.published? %>
- <%= _('Published') %>
- <% else %>
- <%= _('Unpublished') %>
- <% end %>
-
-
- <% last_temp_updated = template.updated_at %>
- <%= l last_temp_updated.to_date, formats: :short %>
-
-
- <% end %>
-
-
-
\ No newline at end of file
diff --git a/app/views/paginable/templates/_customisable.html.erb b/app/views/paginable/templates/_customisable.html.erb
new file mode 100644
index 0000000..20cb3b1
--- /dev/null
+++ b/app/views/paginable/templates/_customisable.html.erb
@@ -0,0 +1,86 @@
+<% # locals: templates %>
+
+
+
+
+ <%= _('Template Name') %> <%= paginable_sort_link('templates.title') %>
+ <%= _('Funder') %> <%= paginable_sort_link('orgs.name') %>
+ <%= _('Status') %>
+ <%= _('Edited Date') %> <%= paginable_sort_link('templates.updated_at') %>
+
+
+
+
+ <% scope.each do |template| %>
+ <% customization = customizations.find{ |customization| customization.customization_of == template.family_id } %>
+
+
+ <%= "#{template.is_default ? '* ' : ''}#{template.title}" %>
+
+
+ <%= template.org.name %>
+
+
+ <% if customization.present? %>
+ <% if customization.upgrade_customization? %>
+ <% tooltip = _("Select 'Transfer customisation' in the Actions menu to review your customisation(s) and make any necessary changes. When you are done, you must return to the Actions menu and publish your customisation(s).") %>
+ <%= _('Original funder template has changed!') %><%= tooltip %>
+
+ <% else %>
+ <% if customization.published? %>
+ <%= _('Published') %>
+ <% elsif customization.draft? %>
+ <% tooltip = _('You have unpublished changes! Select "Publish changes" in the Actions menu when you are ready to make them available to users.') %>
+ <%= _('Published') %> <%= tooltip %>
+
+ <% else %>
+ <%= _('Unpublished') %>
+ <% end %>
+ <% end %>
+ <% else %>
+ <%= _('Not customized') %>
+ <% end %>
+
+
+ <% last_temp_updated = template.updated_at %>
+ <%= l last_temp_updated.to_date, formats: :short %>
+
+
+
+
+ <%= _('Actions') %>
+
+
+
+
+
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/paginable/templates/_funders.html.erb b/app/views/paginable/templates/_funders.html.erb
deleted file mode 100644
index d0beef2..0000000
--- a/app/views/paginable/templates/_funders.html.erb
+++ /dev/null
@@ -1,93 +0,0 @@
-<% # locals: templates, current_org %>
-
-
-
-
- <% if scopes.present? %>
-
- <% scopes.keys.each do |k| %>
- <% unless k == :dmptemplate_ids %>
- <% label = (['published', 'unpublished'].include?(k.to_s) ? _('Customization %{publication_status}') % { publication_status: k } : k.capitalize) %>
- <%= link_to "#{label} (#{scopes[k]})", "#{funders_paginable_templates_path(1)}?scope=#{k}", class: 'template-scope', 'data-remote': true %>
- <% end %>
- <% end %>
-
- <% end %>
-
- <%= _('Template Name') %> <%= paginable_sort_link('templates.title') %>
- <%= _('Funder') %> <%= paginable_sort_link('orgs.name') %>
- <%= _('Status') %>
- <%= _('Edited Date') %> <%= paginable_sort_link('templates.updated_at') %>
-
-
-
-
- <% scope.each do |template| %>
- <% customization = customizations[template.dmptemplate_id] %>
-
-
- <%= "#{template.is_default? ? '* ' : ''}#{template.title}" %>
-
-
- <%= raw template.org.name %>
-
-
- <% if customization.present? %>
-
- <% if customization.updated_at < template.updated_at %>
- <%= _('Original funder template has changed!')%>
- <% elsif !template.published? %>
-
- <%= b_label = _('Funder version is unpublished') %>
- <% elsif customization.dirty? %>
- <%= _('You have unpublished changes') %>
- <% elsif customization.published? %>
- <%= _('Published') %>
- <% else %>
- <%= _('Unpublished') %>
- <% end %>
- <% else %>
- <%= _('Not Customised') %>
- <% end %>
-
-
- <% last_temp_updated = template.updated_at %>
- <%= l last_temp_updated.to_date, formats: :short %>
-
-
-
-
- <%= _('Actions') %>
-
-
-
-
-
- <% end %>
-
-
-
\ No newline at end of file
diff --git a/app/views/paginable/templates/_history.html.erb b/app/views/paginable/templates/_history.html.erb
index bf54288..3a081ce 100644
--- a/app/views/paginable/templates/_history.html.erb
+++ b/app/views/paginable/templates/_history.html.erb
@@ -1,35 +1,46 @@
-<%# locals: { controller, action, paginable, scope, current } %>
- <%= _('Title') %> <%= paginable_sort_link('title') %>
- <%= _('Version') %> <%= paginable_sort_link('version') %>
- <%= _('Published') %> <%= paginable_sort_link('published') %>
- <%= _('Last updated') %> <%= paginable_sort_link('updated_at') %>
+ <%= _('Title') %> <%= paginable_sort_link('templates.title') %>
+ <%= _('Version') %> <%= paginable_sort_link('templates.version') %>
+ <%= _('Published') %> <%= paginable_sort_link('templates.published') %>
+ <%= _('Last updated') %> <%= paginable_sort_link('templates.updated_at') %>
<%= _('Actions') %>
- <% scope.each do |org_template| %>
+ <% scope.each do |template| %>
- <%= org_template.title%>
- <% if org_template == current && !org_template.published%>
+ <%= template.title%>
+ <% if template.draft? && template.latest? %>
<%=_('Draft')%>
<% end %>
- <%= org_template.version %>
+ <%= template.version %>
- <%= (org_template.published? ? _('Yes') : _('No')) %>
+ <%= (template.published? ? _('Yes') : _('No')) %>
- <%= l org_template.updated_at.to_date, formats: :short %>
+ <%= l template.updated_at.to_date, formats: :short %>
- <%= link_to (org_template == current ? _('Edit') : _('View')), edit_org_admin_template_path(id: org_template), class: "dmp_table_link"%>
+ <% if template.customization_of.present? %>
+ <% if template.latest? %>
+ <%= link_to _('Edit customizations'), org_admin_template_path(id: template.id), class: "dmp_table_link" %>
+ <% else %>
+ <%= link_to _('View customizations'), org_admin_template_path(id: template.id), class: "dmp_table_link" %>
+ <% end %>
+ <% else %>
+ <% if template.latest? %>
+ <%= link_to _('Edit'), edit_org_admin_template_path(id: template.id), class: "dmp_table_link" %>
+ <% else %>
+ <%= link_to _('View'), org_admin_template_path(id: template.id), class: "dmp_table_link" %>
+ <% end %>
+ <% end %>
<% end %>
diff --git a/app/views/paginable/templates/_index.html.erb b/app/views/paginable/templates/_index.html.erb
new file mode 100644
index 0000000..12a98f2
--- /dev/null
+++ b/app/views/paginable/templates/_index.html.erb
@@ -0,0 +1,40 @@
+<% # locals: templates %>
+
+
+
+
+ <%= _('Template Name') %> <%= paginable_sort_link('templates.title') %>
+ <%= _('Organisation') %> <%= paginable_sort_link('orgs.name') %>
+ <%= _('Status') %>
+ <%= _('Edited Date') %> <%= paginable_sort_link('templates.updated_at') %>
+
+
+
+ <% scope.each do |template| %>
+
+
+ <%= "#{template.is_default? ? '* ' : ''}#{template.title}" %>
+
+
+ <%= template.org.name %>
+
+
+ <% if template.published? %>
+ <%= _('Published') %>
+ <% elsif template.draft? %>
+ <% tooltip = _('This template is published changes but has unpublished changes!') %>
+ <%= _('Published') %> <%= tooltip %>
+
+ <% else %>
+ <%= _('Unpublished') %>
+ <% end %>
+
+
+ <% last_temp_updated = template.updated_at %>
+ <%= l last_temp_updated.to_date, formats: :short %>
+
+
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/paginable/templates/_organisational.html.erb b/app/views/paginable/templates/_organisational.html.erb
new file mode 100644
index 0000000..98c7904
--- /dev/null
+++ b/app/views/paginable/templates/_organisational.html.erb
@@ -0,0 +1,80 @@
+<% # locals: templates %>
+
+
+
+
+ <%= _('Template Name') %> <%= paginable_sort_link('templates.title') %>
+ <% if action == 'organisational' %>
+ <%= _('Description') %> <%= paginable_sort_link('templates.description') %>
+ <% else %>
+ <%= (action == 'customizable' ? _('Funder') : _('Organisation')) %> <%= paginable_sort_link('orgs.name') %>
+ <% end %>
+ <%= _('Status') %>
+ <%= _('Edited Date') %> <%= paginable_sort_link('templates.updated_at') %>
+ <% if action != 'index' %>
+
+ <% end %>
+
+
+
+ <% scope.each do |template| %>
+
+
+ <%= template.title %>
+
+
+ <%= action == 'organisational' ? raw(template.description) : template.org.name %>
+
+
+ <%# Leaving this line here as a placeholder for determining how to notify user of changes now that dirty flag is removed %>
+ <%# if template.dirty? %>
+ <%# _('Unpublished changes') %>
+
+ <% if template.published? %>
+ <%= _('Published') %>
+ <% elsif template.draft? %>
+ <% tooltip = _('You have unpublished changes! Select "Publish changes" in the Actions menu when you are ready to make them available to users.') %>
+ <%= _('Published') %> <%= tooltip %>
+
+ <% else %>
+ <%= _('Unpublished') %>
+ <% end %>
+
+
+ <% last_temp_updated = template.updated_at %>
+ <%= l last_temp_updated.to_date, formats: :short %>
+
+ <% if action != 'index' %>
+
+
+
+ <%= _('Actions') %>
+
+
+
+
+ <% end %>
+
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/paginable/templates/_orgs.html.erb b/app/views/paginable/templates/_orgs.html.erb
deleted file mode 100644
index 7361570..0000000
--- a/app/views/paginable/templates/_orgs.html.erb
+++ /dev/null
@@ -1,80 +0,0 @@
-<% # locals: templates, current_org %>
-
-
-
-
- <% if scopes.present? %>
-
- <% scopes.keys.each do |k| %>
- <% unless k == :dmptemplate_ids %>
- <%= link_to "#{k.capitalize} (#{scopes[k]})", "#{orgs_paginable_templates_path(1)}?scope=#{k}", class: 'template-scope', 'data-remote': true %>
- <% end %>
- <% end %>
-
- <% end %>
-
- <%= _('Template Name') %> <%= paginable_sort_link('templates.title') %>
- <%= _('Description') %> <%= paginable_sort_link('templates.description') %>
- <%= _('Status') %>
- <%= _('Edited Date') %> <%= paginable_sort_link('templates.updated_at') %>
-
-
-
-
- <% scope.each do |template| %>
-
-
- <%= template.title %>
-
-
- <%= raw(template.description) %>
-
-
- <% if published[template.dmptemplate_id].present? && !template.published? %>
- <%= _('Unpublished changes') %>
- <% elsif template.published? %>
- <%= _('Published') %>
- <% else %>
- <%= _('Unpublished') %>
- <% end %>
-
-
- <% last_temp_updated = template.updated_at %>
- <%= l last_temp_updated.to_date, formats: :short %>
-
-
-
- <% # Span used to trigger the display of the action dropdowns via JS %>
- <%= template.org.id %>
-
-
- <%= _('Actions') %>
-
-
-
-
-
- <% end %>
-
-
-
\ No newline at end of file
diff --git a/app/views/paginable/templates/_publicly_visible.html.erb b/app/views/paginable/templates/_publicly_visible.html.erb
index 58c030f..6c43a0b 100644
--- a/app/views/paginable/templates/_publicly_visible.html.erb
+++ b/app/views/paginable/templates/_publicly_visible.html.erb
@@ -15,8 +15,8 @@
<%= template.title %>
- <%= link_to _('DOCX'), template_export_path(template.dmptemplate_id, format: :docx), target: '_blank' %>
- <%= link_to _('PDF'), template_export_path(template.dmptemplate_id, format: :pdf), target: '_blank' %>
+ <%= link_to _('DOCX'), template_export_path(template.family_id, format: :docx), target: '_blank' %>
+ <%= link_to _('PDF'), template_export_path(template.family_id, format: :pdf), target: '_blank' %>
<%= template.org.name %>
<%= l(template.updated_at.to_date, formats: :short) %>
diff --git a/app/views/phases/_admin_add.html.erb b/app/views/phases/_admin_add.html.erb
deleted file mode 100644
index 2ab4baf..0000000
--- a/app/views/phases/_admin_add.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-<%= _('Phase details') %>
-<%= _('When you create a new phase for your template, a version will automatically be created. Once you complete the form below you will be provided with options to create sections and questions.') %>
-<%= form_for :phase, { url: admin_create_phase_path(r: current_tab) } do |f| %>
- <%= f.hidden_field :template_id, value: @template.id%>
-
- <%= f.label(:title, _('Title') ,class: "control-label") %>
- <%= f.text_field(:title, class: "form-control", 'aria-required': false, 'data-toggle': 'tooltip', title: _('Enter a title for the phase e.g. intial DMP, full DMP... This is what users will see in the tabs when completing a plan. If you only have one phase, call it something generic e.g. Glasgow DMP')) %>
-
-
-
-
-
-
-
- <%= f.button(_('Save'), class: 'btn btn-default', type: "submit") %>
- <%= link_to(_('Cancel'), edit_org_admin_template_path(@template), { class: 'btn btn-default', role: "button" }) %>
-
-<% end %>
\ No newline at end of file
diff --git a/app/views/phases/_admin_show.html.erb b/app/views/phases/_admin_show.html.erb
deleted file mode 100644
index d29df78..0000000
--- a/app/views/phases/_admin_show.html.erb
+++ /dev/null
@@ -1,85 +0,0 @@
-<% # locals: { phase, template, edit, current_section } %>
-<%= _('Phase details')%>
-
-
- <% if phase.modifiable && edit %>
-
- <%= render partial: "phases/edit_phase", locals: { phase: phase, current_tab: current_tab }%>
-
- <% end %>
-
-
-
-
-
- <%= render partial: "phases/show_phase", locals: { phase: phase, edit: edit, current_tab: current_tab } %>
-
-
-
-
-
- <% if phase.sections.length > 1 %>
-
- <% end %>
-
-
-
-
-
-
- <% phase.sections.each do |section| %>
-
-
-
"
- class="panel-collapse collapse<%= " in" if section.id == current_section %>"
- role="tabpanel"
- aria-labelledby="<%= "headingSection#{section.id}" %>">
-
- <% if edit && section.modifiable %>
- <%= render partial: 'sections/edit_section', locals: { template: template, section: section, edit: edit, phase: phase, current_tab: current_tab } %>
- <% else %>
- <%= render partial: 'sections/show_section', locals: { template: template, section: section, current_tab: current_tab, edit: edit } %>
- <% end %>
-
-
-
- <% end %>
-
- <% if edit || template.customization_of.present? %>
-
-
-
- <%= link_to(_('Add Section'), "#section_new#{phase.id}", { class: "btn btn-default section_new_link", role: "button" }) %>
-
-
-
-
- <%= render partial: 'sections/add_section', locals: { phase: phase, current_tab: current_tab } %>
-
-
-
- <% end %>
-
-
diff --git a/app/views/phases/_edit_phase.html.erb b/app/views/phases/_edit_phase.html.erb
deleted file mode 100644
index ec55c1f..0000000
--- a/app/views/phases/_edit_phase.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-<%= form_for :phase, { url: admin_update_phase_path(phase.id, r: current_tab), html: { method: :put }} do |f| %>
-
- <%= f.label(:title, _('Title') ,class: "control-label") %>
- <%= f.text_field(:title, class: "form-control", 'aria-required': false, 'data-toggle': 'tooltip', title: _('Enter a title for the phase e.g. intial DMP, full DMP... This is what users will see in the tabs when completing a plan. If you only have one phase, call it something generic e.g. Glasgow DMP')) %>
-
-
-
-
-
-
-
-<% end %>
\ No newline at end of file
diff --git a/app/views/phases/_edit_plan_answers.html.erb b/app/views/phases/_edit_plan_answers.html.erb
index bad5182..41cc613 100644
--- a/app/views/phases/_edit_plan_answers.html.erb
+++ b/app/views/phases/_edit_plan_answers.html.erb
@@ -38,7 +38,7 @@
<%= section.title %>
<% if plan.present? %>
- <%= render :partial => "/sections/progress", locals: { section: section, plan: plan } %>
+ <%= render :partial => "/org_admin/sections/progress", locals: { section: section, plan: plan } %>
<% end %>
diff --git a/app/views/phases/_guidances_notes.html.erb b/app/views/phases/_guidances_notes.html.erb
index 7c89413..9ad6e2a 100644
--- a/app/views/phases/_guidances_notes.html.erb
+++ b/app/views/phases/_guidances_notes.html.erb
@@ -54,7 +54,7 @@
<% num_annotations = 0 %>
<% i = 0 %>
<% annotations.each do |annotation| %>
- <%= render partial: 'annotations/show',
+ <%= render partial: 'org_admin/annotations/show',
locals: {
template: template,
example_answer: (annotation.example_answer? ? annotation : nil),
diff --git a/app/views/phases/_overview.html.erb b/app/views/phases/_overview.html.erb
index 829b724..f216c85 100644
--- a/app/views/phases/_overview.html.erb
+++ b/app/views/phases/_overview.html.erb
@@ -3,7 +3,7 @@
<%= raw(phase.description) %>
diff --git a/app/views/phases/_show_phase.html.erb b/app/views/phases/_show_phase.html.erb
deleted file mode 100644
index 325a3b5..0000000
--- a/app/views/phases/_show_phase.html.erb
+++ /dev/null
@@ -1,18 +0,0 @@
-
- <%= _('Title') %>
- <%= phase.title %>
- <%= _('Order of display') %>
- <%= phase.number %>
- <%= _('Description') %>
- <%= raw phase.description %>
-
-<% if phase.modifiable && edit %>
-
-
- <%= link_to(_('Edit phase details'), '#', { class: "btn btn-default phase_edit_link", role: "button" }) %>
- <%= link_to(_('Preview'), admin_preview_phase_path(phase, r: current_tab), { class: 'btn btn-default phase_preview_link', role: 'button' }) %>
-
-
-<% end %>
-
-
diff --git a/app/views/phases/admin_preview.html.erb b/app/views/phases/admin_preview.html.erb
deleted file mode 100644
index 338caeb..0000000
--- a/app/views/phases/admin_preview.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
<%= @template.title %>
-
-
- <%= link_to _('Back to edit phase'), admin_show_phase_path(id: @phase.id, r: @current_tab), class: 'btn btn-primary' %>
- <%= link_to _('View all templates'), org_admin_templates_path(r: @current_tab), class: 'btn btn-primary' %>
-
-
-
-
-
-
-
- <%= render partial: "/org_admin/templates/admin_nav_tabs", locals: { template: @template, active: @phase.id, edit: false, current_tab: @current_tab } %>
-
-
-
-
-
- <%= render partial: '/phases/edit_plan_answers', locals: { plan: nil, phase: @phase, readonly: true, question_guidance: {}, edit: false, guidance_groups: [], base_template_org: @base_template_org } %>
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/views/phases/edit.html.erb b/app/views/phases/edit.html.erb
index c135c06..f54c5f3 100644
--- a/app/views/phases/edit.html.erb
+++ b/app/views/phases/edit.html.erb
@@ -7,6 +7,6 @@
- <%= render partial: 'edit_plan_answers', layout: 'plans/navigation', locals: local_assigns %>
+ <%= render partial: 'phases/edit_plan_answers', layout: 'plans/navigation', locals: local_assigns %>
\ No newline at end of file
diff --git a/app/views/plans/_navigation.html.erb b/app/views/plans/_navigation.html.erb
index 20cb5d0..1201abf 100644
--- a/app/views/plans/_navigation.html.erb
+++ b/app/views/plans/_navigation.html.erb
@@ -7,8 +7,8 @@
<%= link_to(_('Plan overview'), overview_plan_path(plan), role: 'tab', 'aria-controls': 'content') %>
<% phases.each do |phase| %>
-
-
+
+
<%= (phases.size > 1 ? phase.title : _('Write Plan')) %>
@@ -18,7 +18,7 @@
<%= _('Share') %>
<% end %>
- <% if !plan.reviewable_by?(current_user.id) %>
+ <% if plan.readable_by?(current_user.id) %>
<%= _('Download') %>
diff --git a/app/views/question_options/_option_fields.html.erb b/app/views/question_options/_option_fields.html.erb
deleted file mode 100644
index 0282d82..0000000
--- a/app/views/question_options/_option_fields.html.erb
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
- <%= _('Order')%>
-
-
- <%= _('Text')%>
-
-
- <%= _('Default')%>
-
-
-
-
-<% if q.question_options.count == 0 %>
- <% 2.times {q.question_options.build } %>
-<% end %>
-<% i = 0 %>
- <% q.question_options.to_a.sort_by{|op| op['number']}.each do |options_q| %>
- <%= f.fields_for :question_options, options_q do |op|%>
- <% i = i + 1 %>
- <% options_q.number = i %>
-
-
- <%= op.number_field :number, in: 1..20, class: 'form-control' %>
-
-
- <%= op.text_field :text, as: :string, class: 'form-control' %>
-
-
- <%= op.check_box :is_default %>
-
-
-
- <% end %>
- <% end %>
-
diff --git a/app/views/questions/_add_question.html.erb b/app/views/questions/_add_question.html.erb
deleted file mode 100644
index 5a9c3f1..0000000
--- a/app/views/questions/_add_question.html.erb
+++ /dev/null
@@ -1,92 +0,0 @@
-
-<% @new_question = Question.new %>
-<% @new_question.number = section.questions.count + 1 %>
-<%= form_for @new_question, url: admin_create_question_path(r: current_tab) , html: {id: "new_question_#{section.id}", class: 'question_form'} do |f| %>
- <%= f.hidden_field :section_id, value: section.id %>
- <%= hidden_field_tag :section_id, section.id, class: "section_id_new" %>
-
-
-
- <%= f.label(:number, _('Question Number'), class: "control-label") %>
- <%= f.number_field(:number, in: 1..50, class: "form-control", "aria-required": true, 'aria-required': true) %>
-
-
-
-
- <%= f.label(:text, _('Question text'), class: "control-label") %>
- <%= f.text_area(:text, class: "question") %>
-
-
-
-
-
-
-
-
-
- <%= f.check_box :option_comment_display, as: :check_boxes %><%= _('Display additional comment area.') %>
-
-
-
-
-
-
-
-
-
-
- <%= render partial: 'org_admin/shared/theme_selector',
- locals: { f: f, all_themes: Theme.all.order("title"),
- popover_message: _('Select one or more themes that are relevant to this question. This will allow similarly themed organisation-level guidance to appear alongside your question.') } %>
-
-
-<% end %>
diff --git a/app/views/questions/_edit_question.html.erb b/app/views/questions/_edit_question.html.erb
deleted file mode 100644
index 8d452db..0000000
--- a/app/views/questions/_edit_question.html.erb
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
-
- <%= form_for(question, url: admin_update_question_path(question, r: current_tab), html: { method: :put, class: 'question_form' }) do |f| %>
- <%= f.hidden_field :id,{ class: "quest_id" } %>
- <%= hidden_field_tag :question_id, question.id, class: "question_id" %>
-
-
- <%= f.label(:number, _('Question Number'), class: "control-label") %>
- <%= f.number_field(:number, in: 1..50, class: "form-control", "aria-required": true, 'aria-required': true) %>
-
-
-
- <%= f.label(:text, _('Question text'), class: "control-label") %>
- <%= f.text_area(:text, class: "question") %>
-
-
-
-
-
- <% comment_disp = question.question_format.option_based? || question.question_format.rda_metadata? %>
-
-
- <%= f.check_box :option_comment_display, as: :check_boxes %><%= _('Display additional comment area.') %>
-
-
-
-
-
-
-
-
-
-
- <%= render partial: 'org_admin/shared/theme_selector',
- locals: { f: f, all_themes: Theme.all.order("title"),
- popover_message: _('Select one or more themes that are relevant to this question. This will allow similarly themed organisation-level guidance to appear alongside your question.') } %>
-
-
- <% end %>
-
-
-
-
-
- <%#= render partial: "guidances/guidance_display", locals: {question: question} %>
-
-
diff --git a/app/views/questions/_new_edit_question_option_based.html.erb b/app/views/questions/_new_edit_question_option_based.html.erb
index 171bf4d..07299d3 100644
--- a/app/views/questions/_new_edit_question_option_based.html.erb
+++ b/app/views/questions/_new_edit_question_option_based.html.erb
@@ -5,7 +5,7 @@
<% options.each do |op| %>
- <%= f.check_box(:question_option_ids, { multiple: true, checked: answer.has_question_option(op.id) }, op.id, nil) %>
+ <%= f.check_box(:question_option_ids, { multiple: true, checked: answer.has_question_option(op.id) || (answer.question_options.empty? && op.is_default?) }, op.id, nil) %>
<%= raw op.text %>
@@ -15,7 +15,7 @@
<% options.each do |op| %>
- <%= f.radio_button :question_option_ids, op.id, { checked: answer.has_question_option(op.id), id: "answer_option_ids_#{op.id}" } %>
+ <%= f.radio_button :question_option_ids, op.id, { checked: answer.has_question_option(op.id) || (answer.question_options.empty? && op.is_default?), id: "answer_option_ids_#{op.id}" } %>
<%= raw op.text %>
@@ -24,7 +24,7 @@
<%
options_html = ""
options.each do |op|
- options_html += answer.has_question_option(op.id) ?
+ options_html += answer.has_question_option(op.id) || (answer.question_options.empty? && op.is_default?) ?
"
#{op.text} " :
"
#{op.text} "
end
diff --git a/app/views/questions/_show_question.html.erb b/app/views/questions/_show_question.html.erb
deleted file mode 100644
index 8a5cc30..0000000
--- a/app/views/questions/_show_question.html.erb
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
- <% q_format = question.question_format %>
-
- <%= _('Question number')%>
- <%= question.number %>
- <%= _('Question text')%>
- <%= raw question.text %>
-
-
-
-
- <% if q_format.textfield? || q_format.textarea? %>
- <% if !question.default_value.nil? %>
- <%= _('Default value')%>
- <%= raw question.default_value %>
- <% end %>
- <% end %>
-
- <%= _('Answer format')%>
-
- <%= q_format.title %>
- <% if q_format.option_based? %>
- <%= _('Additional comment area will be displayed.')%>
- <% else %>
- <%= _('No additional comment area will be displayed.')%>
- <% end %>
-
-
- <% if !question.section.phase.template.org.funder? %>
- <% example_answer = question.get_example_answers(@original_org.id).first %>
- <% if example_answer.present? && example_answer.text.present? %>
- <%= _('example answer')%>
- <%= raw example_answer.text %>
- <% end %>
- <% end %>
-
- <% guidance = question.get_guidance_annotation(@original_org.id) %>
- <% if guidance.present? %>
- <%= _('Guidance')%>
- <%= raw guidance.text %>
- <% end %>
-
- <% themes_q = question.themes %>
- <% if !themes_q.nil? %>
- <%= _('Themes')%>
- <%= themes_q.join(', ') %>
- <% end %>
-
-
-
-
-
-
- <% example_answer = question.get_example_answers(current_user.org_id).first %>
- <% guidance = question.get_guidance_annotation(current_user.org_id) %>
- <% editing = (example_answer.present? || guidance.present?) %>
- <% if !question.modifiable %>
-
<%= _('Annotations') %>
-
- <%= render partial: 'annotations/show',
- locals: { example_answer: example_answer,
- guidance: guidance,
- template: template,
- for_plan: false } %>
- <% unless question.modifiable %>
-
- <%= link_to _('%{add_or_edit} Annotations') % { add_or_edit: (editing ? 'Edit' : 'Add') },
- "#annotations_div_#{question.id}", class: "btn btn-default annotations_button", role:"button" %>
-
- <% end %>
-
-
- <%= render partial: 'annotations/new_edit',
- locals: {
- example_answer: example_answer,
- guidance: guidance,
- question: question,
- options: { url: admin_update_annotation_path(r: current_tab), method: 'PUT' }
- } %>
-
- <% end %>
-
- <% if (question.modifiable && edit) %>
- <%= link_to _('Edit question'), "#question_edit#{question.id}", class: "btn btn-default question_edit_link", role: "button" %>
- <%= link_to _('Delete question'), admin_destroy_question_path(question_id: question.id, r: current_tab),
- confirm: _("You are about to delete '%{question_text}'. Are you sure?") % { :question_text => question.text }, method: :delete, class: "btn btn-default", role:"button" %>
- <% end %>
-
-
-
-
-
- <%#= render partial: 'guidances/guidance_display', locals: {question: question} %>
-
-
diff --git a/app/views/sections/_add_section.html.erb b/app/views/sections/_add_section.html.erb
deleted file mode 100644
index d64c5a2..0000000
--- a/app/views/sections/_add_section.html.erb
+++ /dev/null
@@ -1,36 +0,0 @@
-
-<% new_section = Section.new %>
-<% new_section.number = phase.sections.count + 1 %>
-<%= form_for new_section, { url: admin_create_section_path(r: current_tab), html: { class: 'form-horizontal' }} do |f| %>
- <%= f.hidden_field :phase_id, value: phase.id %>
-
-
-
-
- <%= f.text_field(:title, { class: "form-control", 'aria-required': false, placeholder: _('Enter a title for the section') } ) %>
-
-
-
-
-
-
- <%= f.label(:number, _('Order of display'), class: "control-label") %>
-
-
- <%= f.number_field(:number, in: 1..15, class: "form-control", 'aria-required': false, 'data-toggle': 'tooltip', title: _('This allows you to order sections.')) %>
-
-
-
- <%= f.label(:description, _('Description'), class: "control-label") %>
-
">
- <%= text_area_tag('section-desc', '', class: 'tinymce form-control') %>
-
-
-
-
- <%= f.button(_('Save'), class: 'btn btn-default', type: "submit") %>
- <%= link_to(_('Cancel'), '#', { class: 'btn btn-default section_new_cancel', role: "button" }) %>
-
-
-
-<% end %>
\ No newline at end of file
diff --git a/app/views/sections/_edit_section.html.erb b/app/views/sections/_edit_section.html.erb
deleted file mode 100644
index b97d078..0000000
--- a/app/views/sections/_edit_section.html.erb
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
<%= _('Section details') %>
-
-
-
-
- <%= form_for(section, url: admin_update_section_path(section, phase: phase, r: current_tab), html: { method: :put }) do |f| %>
-
- <%= f.label(:title, _('Title') ,class: "control-label") %>
- <%= f.text_field(:title, { class: "form-control", 'aria-required': false, placeholder: _('Enter a title for the section'), 'data-toggle': 'tooltip', title: _('Enter a title for the section')} ) %>
-
-
-
-
-
-
-
- <% end %>
-
-
-
<%= _('Questions') %>
- <% questions = section.questions.order('number') %>
- <% if questions.present? %>
- <% questions.each do |question| %>
-
-
">
- <%= render partial: 'questions/show_question', locals: {template: template, question: question, current_tab: current_tab, edit: edit} %>
-
-
" style="display: none;">
- <%= render partial: 'questions/edit_question', locals: {template: template, question: question, current_tab: current_tab} %>
-
- <%= raw("
") if questions.last.id == question.id %>
- <% end %>
- <% end %>
-
-
-<% if edit %>
-
-
-
- <%= link_to(_('Add Question'), '#', { class: 'btn btn-default question_new_link', role: "button" }) %>
-
-
- <%= render partial: 'questions/add_question', locals: { section: section, current_tab: current_tab } %>
-
-
-
-<% end %>
\ No newline at end of file
diff --git a/app/views/sections/_progress.html.erb b/app/views/sections/_progress.html.erb
deleted file mode 100644
index d02cbac..0000000
--- a/app/views/sections/_progress.html.erb
+++ /dev/null
@@ -1,7 +0,0 @@
-<%# locals: { section, plan } %>
-
-<% num_section_questions = section.questions.size() %>
-<% num_section_answers = section.num_answered_questions(plan) %>
-
- (<%= num_section_answers %> / <%= num_section_questions %>)
-
\ No newline at end of file
diff --git a/app/views/sections/_show_section.html.erb b/app/views/sections/_show_section.html.erb
deleted file mode 100644
index 4848a8c..0000000
--- a/app/views/sections/_show_section.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
- <%= raw section.description %>
-
-
-
-
-
-
<%= _('Questions') %>
- <% questions = section.questions.order('number') %>
- <% if questions.present? %>
- <% questions.each do |question| %>
-
-
">
- <%= render partial: 'questions/show_question', locals: {template: template, question: question, current_tab: current_tab, edit: edit} %>
-
- <% if question.modifiable && edit %>
-
" style="display: none;">
- <%= render partial: 'questions/edit_question', locals: {template: template, question: question, current_tab: current_tab} %>
-
- <% end %>
- <% if questions.last.id != question.id %>
-
- <% end %>
- <% end %>
- <% end %>
-
-
\ No newline at end of file
diff --git a/app/views/shared/_my_org.html.erb b/app/views/shared/_my_org.html.erb
index 076501a..66b3415 100644
--- a/app/views/shared/_my_org.html.erb
+++ b/app/views/shared/_my_org.html.erb
@@ -1,7 +1,8 @@
<%= f.label :org_name, _('Organisation'), class: 'control-label' %>
+<% object_name = (f.options[:namespace].present? ? "#{f.options[:namespace]}_#{f.object_name}" : f.object_name) %>
<%= render partial: "shared/accessible_combobox",
- locals: {name: "#{f.object_name}[org_name]",
- id: "#{f.object_name}_org_name",
+ locals: {name: "#{object_name}[org_name]",
+ id: "#{object_name}_org_name",
default_selection: default_org,
models: orgs,
attribute: 'name'} %>
diff --git a/config/application.rb b/config/application.rb
index 4444622..7c2e2f1 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -22,9 +22,6 @@
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
-
- #commented 15.03.2016
- #config.autoload_paths << Rails.root.join('lib')
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
@@ -42,6 +39,8 @@
# Enable escaping HTML in JSON.
config.active_support.escape_html_entities_in_json = true
+
+ config.eager_load_paths << "app/models/scopes"
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
diff --git a/config/locale/en_US/app.po b/config/locale/en_US/app.po
index 8d6f264..a6ba8eb 100644
--- a/config/locale/en_US/app.po
+++ b/config/locale/en_US/app.po
@@ -1137,7 +1137,7 @@
msgstr "Download settings"
msgid "Draft"
-msgstr "Drafgt"
+msgstr "Draft"
msgid "Edit"
msgstr "Edit"
diff --git a/config/routes.rb b/config/routes.rb
index 19a1333..7f71956 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -136,40 +136,6 @@
end
end
- resources :phases, path: 'org/admin/templates/phases', only: [] do
- member do
- get 'admin_show'
- get 'admin_preview'
- get 'admin_add'
- put 'admin_update'
- post 'admin_create'
- delete 'admin_destroy'
- end
- end
-
- resources :sections, path: 'org/admin/templates/sections', only: [] do
- member do
- post 'admin_create'
- put 'admin_update'
- delete 'admin_destroy'
- end
- end
-
- resources :questions, path: 'org/admin/templates/questions', only: [] do
- member do
- post 'admin_create'
- put 'admin_update'
- delete 'admin_destroy'
- end
- end
-
- resources :annotations, path: 'org/admin/templates/annotations', only: [] do
- member do
- put 'admin_update'
- delete 'admin_destroy'
- end
- end
-
resources :answers, only: [] do
post 'create_or_update', on: :collection
end
@@ -184,15 +150,6 @@
end
resources :plans do
- resources :phases do
- member do
- get 'edit'
- get 'status'
- post 'update'
- end
- end
-
-
member do
get 'status'
get 'locked'
@@ -213,6 +170,7 @@
post 'set_test', constraints: {format: [:json]}
get 'request_feedback'
get 'overview'
+ get 'phase_status'
end
collection do
@@ -278,9 +236,9 @@
end
# Paginable actions for templates
resources :templates, only: [] do
- get 'all/:page', action: :all, on: :collection, as: :all
- get 'funders/:page', action: :funders, on: :collection, as: :funders
- get 'orgs/:page', action: :orgs, on: :collection, as: :orgs
+ get 'index/:page', action: :index, on: :collection, as: :index
+ get 'customisable/:page', action: :customisable, on: :collection, as: :customisable
+ get 'organisational/:page', action: :organisational, on: :collection, as: :organisational
get 'publicly_visible/:page', action: :publicly_visible, on: :collection, as: :publicly_visible
get ':id/history/:page', action: :history, on: :collection, as: :history
end
@@ -301,16 +259,35 @@
get 'feedback_complete'
end
end
- resources :templates, only: [:index, :new, :create, :edit, :update, :destroy] do
+ resources :templates, only: [:index, :show, :new, :edit, :create, :update, :destroy] do
member do
get 'history'
- get 'customize'
- get 'transfer_customization'
- get 'copy', action: :copy, constraints: {format: [:json]}
- get 'publish', action: :publish, constraints: {format: [:json]}
- get 'unpublish', action: :unpublish, constraints: {format: [:json]}
+ post 'customize'
+ post 'transfer_customization'
+ post 'copy', action: :copy, constraints: {format: [:json]}
+ patch 'publish', action: :publish, constraints: {format: [:json]}
+ patch 'unpublish', action: :unpublish, constraints: {format: [:json]}
+ end
+
+ # Used for the organisational and customizable views of index
+ collection do
+ get 'organisational'
+ get 'customisable'
+ end
+
+ resources :phases, only: [:show, :edit, :new, :create, :edit, :update, :destroy] do
+ member do
+ get 'preview'
+ end
+
+ resources :sections, only: [:index, :show, :edit, :update, :create, :destroy] do
+ resources :questions, only: [:show, :edit, :new, :update, :create, :destroy] do
+ end
+ end
end
end
+
+ resources :annotations, only: [:create, :destroy, :update] do ; end
get 'template_options' => 'templates#template_options', constraints: {format: [:json]}
get 'download_plans' => 'plans#download_plans'
diff --git a/db/migrate/20180405151713_rename_template_fields.rb b/db/migrate/20180405151713_rename_template_fields.rb
new file mode 100644
index 0000000..c4cc5e3
--- /dev/null
+++ b/db/migrate/20180405151713_rename_template_fields.rb
@@ -0,0 +1,11 @@
+class RenameTemplateFields < ActiveRecord::Migration
+ def up
+ rename_column :templates, :migrated, :archived
+ rename_column :templates, :dmptemplate_id, :family_id
+ end
+
+ def down
+ rename_column :templates, :archived, :migrated
+ rename_column :templates, :family_id, :dmptemplate_id
+ end
+end
diff --git a/db/migrate/20180405151942_remove_dirty_from_templates.rb b/db/migrate/20180405151942_remove_dirty_from_templates.rb
new file mode 100644
index 0000000..f77515e
--- /dev/null
+++ b/db/migrate/20180405151942_remove_dirty_from_templates.rb
@@ -0,0 +1,9 @@
+class RemoveDirtyFromTemplates < ActiveRecord::Migration
+ def up
+ remove_column :templates, :dirty
+ end
+
+ def down
+ add_column :templates, :dirty, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20180405152454_add_family_id_index_to_templates.rb b/db/migrate/20180405152454_add_family_id_index_to_templates.rb
new file mode 100644
index 0000000..aee8a0c
--- /dev/null
+++ b/db/migrate/20180405152454_add_family_id_index_to_templates.rb
@@ -0,0 +1,9 @@
+class AddFamilyIdIndexToTemplates < ActiveRecord::Migration
+ def up
+ add_index :templates, :family_id
+ end
+
+ def down
+ remove_index :templates, :family_id
+ end
+end
diff --git a/db/migrate/20180417124026_add_unique_index_family_id_version_to_template.rb b/db/migrate/20180417124026_add_unique_index_family_id_version_to_template.rb
new file mode 100644
index 0000000..dac9d72
--- /dev/null
+++ b/db/migrate/20180417124026_add_unique_index_family_id_version_to_template.rb
@@ -0,0 +1,5 @@
+class AddUniqueIndexFamilyIdVersionToTemplate < ActiveRecord::Migration
+ def change
+ add_index(:templates, [:family_id, :version], unique: true)
+ end
+end
diff --git a/db/migrate/20180418115318_add_unique_index_customization_of_version_org_id_to_template.rb b/db/migrate/20180418115318_add_unique_index_customization_of_version_org_id_to_template.rb
new file mode 100644
index 0000000..0cb1bfd
--- /dev/null
+++ b/db/migrate/20180418115318_add_unique_index_customization_of_version_org_id_to_template.rb
@@ -0,0 +1,5 @@
+class AddUniqueIndexCustomizationOfVersionOrgIdToTemplate < ActiveRecord::Migration
+ def change
+ add_index(:templates, [:customization_of, :version, :org_id], unique: true)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 475283f..a78eda1 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180412092647) do
+ActiveRecord::Schema.define(version: 20180418115318) do
create_table "annotations", force: :cascade do |t|
t.integer "question_id"
@@ -358,13 +358,15 @@
t.integer "version"
t.integer "visibility"
t.integer "customization_of"
- t.integer "dmptemplate_id"
- t.boolean "migrated"
- t.boolean "dirty", default: false
+ t.integer "family_id"
+ t.boolean "archived"
t.text "links", default: "{\"funder\":[], \"sample_plan\":[]}"
end
- add_index "templates", ["org_id", "dmptemplate_id"], name: "template_organisation_dmptemplate_index"
+ add_index "templates", ["customization_of", "version", "org_id"], name: "index_templates_on_customization_of_and_version_and_org_id", unique: true
+ add_index "templates", ["family_id", "version"], name: "index_templates_on_family_id_and_version", unique: true
+ add_index "templates", ["family_id"], name: "index_templates_on_family_id"
+ add_index "templates", ["org_id", "family_id"], name: "template_organisation_dmptemplate_index"
add_index "templates", ["org_id"], name: "index_templates_on_org_id"
create_table "themes", force: :cascade do |t|
@@ -443,6 +445,5 @@
t.integer "perm_id"
end
- add_index "users_perms", ["user_id"], name: "index_users_perms_on_user_id"
-
+ add_index "users_perms", ["user_id"], name: "index_users_perms_on_user_id", using: :btree
end
diff --git a/lib/assets/javascripts/application.js b/lib/assets/javascripts/application.js
index 0262849..196a5ee 100644
--- a/lib/assets/javascripts/application.js
+++ b/lib/assets/javascripts/application.js
@@ -10,8 +10,6 @@
// Page specific JS
import './views/answers/edit';
import './views/answers/rda_metadata';
-import './views/annotations/add';
-import './views/annotations/edit';
import './views/contacts/new';
import './views/devise/invitations/edit';
import './views/devise/passwords/edit';
@@ -21,26 +19,22 @@
import './views/guidance_groups/admin_new';
import './views/guidances/new_edit';
import './views/notes/index';
+import './views/org_admin/phases/new_edit';
+import './views/org_admin/phases/preview';
+import './views/org_admin/question_options/index';
+import './views/org_admin/questions/sharedEventHandlers';
+import './views/org_admin/sections/index';
import './views/org_admin/templates/edit';
import './views/org_admin/templates/index';
-import './views/org_admin/templates/show';
+import './views/org_admin/templates/new';
import './views/orgs/admin_edit';
import './views/orgs/shibboleth_ds';
-import './views/phases/edit';
-import './views/phases/show';
import './views/plans/download';
import './views/plans/edit_details';
import './views/plans/index';
import './views/plans/new';
import './views/plans/share';
import './views/roles/edit';
-import './views/sections/edit';
-import './views/sections/index';
-import './views/sections/new';
-import './views/questions/new_edit';
-import './views/questions/index';
-import './views/questions/show';
-import './views/question_options/index';
import './views/shared/create_account_form';
import './views/shared/my_org';
import './views/shared/sign_in_form';
diff --git a/lib/assets/javascripts/utils/ariatiseForm.js b/lib/assets/javascripts/utils/ariatiseForm.js
index aae08c9..b9a9ad2 100644
--- a/lib/assets/javascripts/utils/ariatiseForm.js
+++ b/lib/assets/javascripts/utils/ariatiseForm.js
@@ -207,6 +207,7 @@
// Bind validations to the form's submit button
$(`${options.selector}`).submit((e) => {
let anyInvalid = false;
+ let firstInvalid;
validatable.each((i, el) => {
const type = getValidationTypeForElement(el);
const required = ($(el).attr('aria-required') && $(el).attr('aria-required') === 'true');
@@ -218,11 +219,18 @@
} else {
anyInvalid = true;
invalid(el);
+ if (!isObject(firstInvalid)) {
+ firstInvalid = el;
+ }
}
}
});
if (anyInvalid) {
e.preventDefault();
+ // Set focus on the first invalid input
+ if (isObject(firstInvalid)) {
+ firstInvalid.focus();
+ }
}
});
}
diff --git a/lib/assets/javascripts/utils/expandCollapseAll.js b/lib/assets/javascripts/utils/expandCollapseAll.js
index f779915..5e88627 100644
--- a/lib/assets/javascripts/utils/expandCollapseAll.js
+++ b/lib/assets/javascripts/utils/expandCollapseAll.js
@@ -45,7 +45,13 @@
const panelCollapse = $(el);
// Expands or collapses the panel according to the
// direction passed (e.g. show --> expands, hide --> collapses)
- $(el).collapse(direction);
+ if (direction === 'show') {
+ if (!panelCollapse.hasClass('in')) {
+ panelCollapse.prev().trigger('click');
+ }
+ } else {
+ panelCollapse.collapse(direction);
+ }
// Sets icon at panel-title accordingly
panelCollapse.prev().find('i.fa')
.removeClass('fa-plus fa-minus').addClass(direction === 'show' ? 'fa-minus' : 'fa-plus');
diff --git a/lib/assets/javascripts/utils/validation.js b/lib/assets/javascripts/utils/validation.js
index 0fdf521..df50fbf 100644
--- a/lib/assets/javascripts/utils/validation.js
+++ b/lib/assets/javascripts/utils/validation.js
@@ -223,6 +223,7 @@
export const validate = (ctx) => {
let anyInvalid = false;
+ let firstInvalid;
if (isObject(ctx)) {
if ($(ctx).is('input')) {
anyInvalid = !checkValidations(ctx);
@@ -230,8 +231,15 @@
validatableFields(ctx).each((i, el) => {
if (!checkValidations(el)) {
anyInvalid = true;
+ if (!isObject(firstInvalid)) {
+ firstInvalid = el;
+ }
}
});
+ // Set focus on the first invalid input
+ if (isObject(firstInvalid)) {
+ firstInvalid.focus();
+ }
}
}
return !anyInvalid;
diff --git a/lib/assets/javascripts/views/annotations/add.js b/lib/assets/javascripts/views/annotations/add.js
deleted file mode 100644
index 498c8f5..0000000
--- a/lib/assets/javascripts/views/annotations/add.js
+++ /dev/null
@@ -1,9 +0,0 @@
-$(() => {
- $('.cancel_add_annotations').on('click', (e) => {
- e.preventDefault();
- const target = $(e.target).attr('href');
- $(target).hide();
- $(target).closest('.col-md-12').find('.add_annotations_button').show();
- $(target).closest('.col-md-12').find('.show_annotations_div').show();
- });
-});
diff --git a/lib/assets/javascripts/views/annotations/edit.js b/lib/assets/javascripts/views/annotations/edit.js
deleted file mode 100644
index 0884ed9..0000000
--- a/lib/assets/javascripts/views/annotations/edit.js
+++ /dev/null
@@ -1,9 +0,0 @@
-$(() => {
- $('.cancel_edit_annotations').on('click', (e) => {
- e.preventDefault();
- const target = $(e.target).attr('href');
- $(target).hide();
- $(target).closest('.col-md-12').find('.edit_annotations_button').show();
- $(target).closest('.col-md-12').find('.show_annotations_div').show();
- });
-});
diff --git a/lib/assets/javascripts/views/org_admin/phases/new_edit.js b/lib/assets/javascripts/views/org_admin/phases/new_edit.js
new file mode 100644
index 0000000..9e85c68
--- /dev/null
+++ b/lib/assets/javascripts/views/org_admin/phases/new_edit.js
@@ -0,0 +1,121 @@
+import 'bootstrap-sass/assets/javascripts/bootstrap/collapse';
+import { Tinymce } from '../../../utils/tinymce';
+import { isObject, isString } from '../../../utils/isType';
+import getConstant from '../../../constants';
+import expandCollapseAll from '../../../utils/expandCollapseAll';
+import ariatiseForm from '../../../utils/ariatiseForm';
+
+import onChangeQuestionFormat from '../questions/sharedEventHandlers';
+import initQuestionOption from '../question_options/index';
+
+$(() => {
+ // Attach handlers for the expand/collapse all accordions
+ expandCollapseAll();
+
+ Tinymce.init({ selector: '.phase' });
+ ariatiseForm({ selector: '.phase_form' });
+ const parentSelector = '#sections_accordion';
+
+ const initQuestion = (context) => {
+ const target = $(context);
+ if (isObject(target)) {
+ Tinymce.init({ selector: `#${context} .question` });
+ ariatiseForm({ selector: `#${context} .question_form` });
+ initQuestionOption(context);
+ // Swap in the question_formats when the user selects an option based question type
+ $(`#${context} select.question_format`).change((e) => {
+ onChangeQuestionFormat(e);
+ });
+ }
+ };
+ const getQuestionPanel = (target) => {
+ let panelBody;
+ if (isObject(target)) {
+ panelBody = target.closest('.question_container');
+ if (!isObject(panelBody) || !isString(panelBody.attr('id'))) {
+ panelBody = target.closest('.panel-body').find('.new-question');
+ }
+ }
+ return panelBody;
+ };
+ const initSection = (selector) => {
+ if (isString(selector)) {
+ // Wire up the section and its Questions
+ Tinymce.init({ selector: `${selector} .section` });
+ ariatiseForm({ selector: `${selector} .section_form` });
+
+ const questionForm = $(selector).find('.question_form');
+ if (questionForm.length > 0) {
+ // Load Tinymce when the 'show' form has a question form.
+ // ONLY applicable for template customizations
+ Tinymce.init({ selector: `${selector} .question_form .question` });
+ }
+ }
+ };
+
+ // Attach handlers for the Section expansion
+ $(parentSelector).on('ajax:before', 'a.ajaxified-section[data-remote="true"]', (e) => {
+ const panelBody = $(e.target).parent().find('.panel-body');
+ return panelBody.attr('data-loaded') === 'false';
+ });
+ $(parentSelector).on('ajax:success', 'a.ajaxified-section[data-remote="true"]', (e, data) => {
+ const panelBody = $(e.target).parent().find('.panel-body');
+ const panel = panelBody.parent();
+ if (isObject(panelBody)) {
+ // Display the section's html
+ panelBody.attr('data-loaded', 'true');
+ panelBody.html(data);
+ // Wire up the section
+ initSection(`#${panel.attr('id')}`);
+ }
+ });
+
+ // Attach handlers for the Question show/edit/new
+ $(parentSelector).on('ajax:before', 'a.ajaxified-question[data-remote="true"]', (e) => {
+ const panelBody = getQuestionPanel($(e.target));
+ if (isObject(panelBody)) {
+ // Release any Tinymce editors that have been loaded
+ panelBody.find('.question').each((idx, el) => {
+ Tinymce.destroyEditorById($(el).attr('id'));
+ });
+ }
+ });
+ $(parentSelector).on('ajax:success', 'a.ajaxified-question[data-remote="true"]', (e, data) => {
+ const target = $(e.target);
+ const panelBody = getQuestionPanel(target);
+ if (isObject(panelBody)) {
+ const id = panelBody.attr('id');
+ // Display the section's html
+ panelBody.html(data);
+ initQuestion(id);
+ if (panelBody.is('.new-question')) {
+ target.hide();
+ }
+ }
+ });
+ $(parentSelector).on('ajax:error', 'a.ajaxified-question[data-remote="true"]', (e) => {
+ const panelBody = getQuestionPanel($(e.target));
+ if (isObject(panelBody)) {
+ panelBody.html(`
${getConstant('AJAX_UNABLE_TO_LOAD_TEMPLATE_SECTION')}
`);
+ }
+ });
+ // When we cancel the new question we just remove the form and its Tinymce editors
+ $(parentSelector).on('click', '.cancel-new-question', (e) => {
+ e.preventDefault();
+ const target = $(e.target);
+ const panel = target.closest('.question_container');
+ panel.find('.question').each((idx, el) => {
+ Tinymce.destroyEditorById($(el).attr('id'));
+ });
+ panel.html('');
+ panel.closest('.panel-body').find('.new-question-button a.ajaxified-question[data-remote="true"]').show();
+ });
+
+ // Handle the section that has focus on initial page load
+ const currentSection = $('#sections_accordion .in');
+ if (currentSection.length > 0) {
+ initSection(`#${currentSection.attr('id')}`);
+ }
+ // Handle the new section
+ initSection('#new_section_new_section');
+});
diff --git a/lib/assets/javascripts/views/org_admin/phases/preview.js b/lib/assets/javascripts/views/org_admin/phases/preview.js
new file mode 100644
index 0000000..9ccc465
--- /dev/null
+++ b/lib/assets/javascripts/views/org_admin/phases/preview.js
@@ -0,0 +1,5 @@
+$(() => {
+ $('.preview-tab').click((e) => {
+ e.preventDefault();
+ });
+});
diff --git a/lib/assets/javascripts/views/org_admin/question_options/index.js b/lib/assets/javascripts/views/org_admin/question_options/index.js
new file mode 100644
index 0000000..0b939b9
--- /dev/null
+++ b/lib/assets/javascripts/views/org_admin/question_options/index.js
@@ -0,0 +1,34 @@
+export default (context) => {
+ $(`#${context} .delete_question_option`).on('click', (e) => {
+ e.preventDefault();
+ const source = $(e.target).closest('[data-attribute="question_option"]');
+ source.find('.destroy-question-option').val(true);
+ source.hide();
+ // $(source).closest('[data-attribute="question_option"]').remove();
+ });
+ $(`#${context} .new_question_option`).on('click', (e) => {
+ e.preventDefault();
+ const source = e.target;
+ const last = $(source).closest('[data-attribute="question_options"]').find('[data-attribute="question_option"]').last();
+ const cloned = last.clone(true);
+ const array = $(cloned).find('[id$="_number"]').prop('id').match(/_[\d]_+/);
+ if (array) {
+ const index = Number(array[0].replace(/_/g, ''));
+ // Reset values for the new cloned inputs
+ cloned.find('[id$="_number"]').val(index + 2);
+ cloned.find('[id$="_text"]').val('');
+ cloned.find('[id$="_is_default"]').prop('checked', false);
+ cloned.find('[id$="__destroy"]').val(false);
+ cloned.find('input').each((i, el) => {
+ const target = $(el);
+ const id = target.prop('id').replace(/_[\d]+_/g, `_${index + 1}_`);
+ const name = target.prop('name').replace(/\[[\d]+\]/g, `[${index + 1}]`);
+ target.prop('id', id);
+ target.prop('name', name);
+ });
+ last.after(cloned);
+ cloned.show();
+ }
+ });
+};
+
diff --git a/lib/assets/javascripts/views/org_admin/questions/sharedEventHandlers.js b/lib/assets/javascripts/views/org_admin/questions/sharedEventHandlers.js
new file mode 100644
index 0000000..484dece
--- /dev/null
+++ b/lib/assets/javascripts/views/org_admin/questions/sharedEventHandlers.js
@@ -0,0 +1,40 @@
+const onChangeQuestionFormat = (e) => {
+ const source = e.target;
+ const selected = source.value;
+ const defaultValue = $(source).closest('form').find('[data-attribute="default_value"]');
+ const questionOptions = $(source).closest('form').find('[data-attribute="question_options"]');
+ const opComment = $(source).closest('form').find('[data-attribute="option_comment"]');
+ switch (selected) {
+ case '1':
+ questionOptions.hide();
+ opComment.hide();
+ defaultValue.show();
+ defaultValue.find('[data-attribute="textfield"]').hide();
+ defaultValue.find('[data-attribute="textarea"]').show();
+ break;
+ case '2':
+ questionOptions.hide();
+ opComment.hide();
+ defaultValue.show();
+ defaultValue.find('[data-attribute="textarea"]').hide();
+ defaultValue.find('[data-attribute="textfield"]').show();
+ break;
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ defaultValue.hide();
+ questionOptions.show();
+ opComment.show();
+ break;
+ case '7':
+ defaultValue.hide();
+ questionOptions.hide();
+ opComment.show();
+ break;
+ default :
+ break;
+ }
+};
+
+export { onChangeQuestionFormat as default };
diff --git a/lib/assets/javascripts/views/org_admin/sections/index.js b/lib/assets/javascripts/views/org_admin/sections/index.js
new file mode 100644
index 0000000..c96ed30
--- /dev/null
+++ b/lib/assets/javascripts/views/org_admin/sections/index.js
@@ -0,0 +1,9 @@
+import ariatiseForm from '../../../utils/ariatiseForm';
+
+$(() => {
+ ariatiseForm({ selector: '.new_section' });
+ $('.section_new_link').on('click', (e) => {
+ $(e.target).hide();
+ $(e.target).closest('.row').find('.section_new').show();
+ });
+});
diff --git a/lib/assets/javascripts/views/org_admin/templates/edit.js b/lib/assets/javascripts/views/org_admin/templates/edit.js
index f1a8452..8c759ab 100644
--- a/lib/assets/javascripts/views/org_admin/templates/edit.js
+++ b/lib/assets/javascripts/views/org_admin/templates/edit.js
@@ -8,11 +8,6 @@
$(() => {
Tinymce.init({ selector: '.template' });
enableValidations($('.edit_template'));
- $('.template_show_link').on('click', (e) => {
- e.preventDefault();
- $(e.target).closest('.template_edit').hide();
- $(e.target).closest('.tab-pane').find('.template_show').show();
- });
$('.edit_template').on('ajax:before', (e) => {
const links = {};
eachLinks((ctx, value) => {
diff --git a/lib/assets/javascripts/views/org_admin/templates/index.js b/lib/assets/javascripts/views/org_admin/templates/index.js
index c60f8cc..aeaf252 100644
--- a/lib/assets/javascripts/views/org_admin/templates/index.js
+++ b/lib/assets/javascripts/views/org_admin/templates/index.js
@@ -1,6 +1,6 @@
$(() => {
// Update the contents of the table when user clicks on a scope link
$('.template-scope').on('ajax:success', 'a[data-remote="true"]', (e, data) => {
- $(e.target).closest('.paginable').html(data);
+ $(e.target).closest('.template-scope').find('.paginable').html(data);
});
});
diff --git a/lib/assets/javascripts/views/org_admin/templates/new.js b/lib/assets/javascripts/views/org_admin/templates/new.js
new file mode 100644
index 0000000..19dc3ab
--- /dev/null
+++ b/lib/assets/javascripts/views/org_admin/templates/new.js
@@ -0,0 +1,19 @@
+import { Tinymce } from '../../../utils/tinymce';
+import { enableValidations, validate } from '../../../utils/validation';
+import { eachLinks } from '../../../utils/links';
+
+$(() => {
+ Tinymce.init({ selector: '.template' });
+ enableValidations($('.new_template'));
+ $('.new_template').on('submit', (e) => {
+ const links = {};
+ eachLinks((ctx, value) => {
+ links[ctx] = value;
+ }).done(() => {
+ $('#template-links').val(JSON.stringify(links));
+ });
+ if (!validate(e.target)) {
+ e.preventDefault();
+ }
+ });
+});
diff --git a/lib/assets/javascripts/views/org_admin/templates/show.js b/lib/assets/javascripts/views/org_admin/templates/show.js
deleted file mode 100644
index fd89a07..0000000
--- a/lib/assets/javascripts/views/org_admin/templates/show.js
+++ /dev/null
@@ -1,7 +0,0 @@
-$(() => {
- $('.template_edit_link').on('click', (e) => {
- e.preventDefault();
- $(e.target).closest('.template_show').hide();
- $(e.target).closest('.tab-pane').find('.template_edit').show();
- });
-});
diff --git a/lib/assets/javascripts/views/phases/edit.js b/lib/assets/javascripts/views/phases/edit.js
deleted file mode 100644
index d3bbefd..0000000
--- a/lib/assets/javascripts/views/phases/edit.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import 'bootstrap-sass/assets/javascripts/bootstrap/collapse';
-import expandCollapseAll from '../../utils/expandCollapseAll';
-import { Tinymce } from '../../utils/tinymce';
-
-$(() => {
- // Attach handlers for the expand/collapse all accordions
- expandCollapseAll();
- Tinymce.init({ selector: '.phase' });
- $('.phase_show_link').on('click', (e) => {
- e.preventDefault();
- $(e.target).closest('.phase_edit').hide();
- $(e.target).closest('.tab-pane').find('.phase_show').show();
- });
-});
diff --git a/lib/assets/javascripts/views/phases/show.js b/lib/assets/javascripts/views/phases/show.js
deleted file mode 100644
index a4c160f..0000000
--- a/lib/assets/javascripts/views/phases/show.js
+++ /dev/null
@@ -1,7 +0,0 @@
-$(() => {
- $('.phase_edit_link').on('click', (e) => {
- e.preventDefault();
- $(e.target).closest('.phase_show').hide();
- $(e.target).closest('.tab-pane').find('.phase_edit').show();
- });
-});
diff --git a/lib/assets/javascripts/views/question_options/index.js b/lib/assets/javascripts/views/question_options/index.js
deleted file mode 100644
index fbbfc9f..0000000
--- a/lib/assets/javascripts/views/question_options/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-$(() => {
- $('.delete_question_option').on('click', (e) => {
- e.preventDefault();
- const source = e.target;
- $(source).closest('[data-attribute="question_option"]').hide();
- });
- $('.new_question_option').on('click', (e) => {
- e.preventDefault();
- const source = e.target;
- const last = $(source).closest('[data-attribute="question_options"]').find('[data-attribute="question_option"]').last();
- const cloned = last.clone(true);
- const array = $(cloned).find('[id$="_number"]').prop('id').match(/[^\d]*(\d)+[^$]*/);
- if (array) {
- const index = Number(array[1]);
- // Reset values for the new cloned inputs
- cloned.find(`[id$="${index}_number"]`).val(index + 2);
- cloned.find(`[id$=${index}_text]`).val('');
- cloned.find(`[id$=${index}_is_default]`).prop('checked', false);
- cloned.find(`[id$="${index}__destroy"]`).val(false);
- cloned.find('input').each((i, el) => {
- // Rename id and name for the cloned inputs
- $(el).prop('id', $(el).prop('id').replace(/_\d+_/g, `_${index + 1}_`));
- $(el).prop('name', $(el).prop('name').replace(/\[\d+\]/g, `[${index + 1}]`));
- });
- last.after(cloned);
- cloned.show();
- }
- });
-});
-
diff --git a/lib/assets/javascripts/views/questions/index.js b/lib/assets/javascripts/views/questions/index.js
deleted file mode 100644
index 2d24174..0000000
--- a/lib/assets/javascripts/views/questions/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-$(() => {
- $('.question_new_link').on('click', (e) => {
- e.preventDefault();
- $(e.target).hide();
- $(e.target).closest('.row').find('.question_new').show();
- });
-});
diff --git a/lib/assets/javascripts/views/questions/new_edit.js b/lib/assets/javascripts/views/questions/new_edit.js
deleted file mode 100644
index ecaf228..0000000
--- a/lib/assets/javascripts/views/questions/new_edit.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Tinymce } from '../../utils/tinymce';
-import ariatiseForm from '../../utils/ariatiseForm';
-import onChangeQuestionFormat from './sharedEventHandlers';
-
-$(() => {
- Tinymce.init({ selector: '.question' });
- ariatiseForm({ selector: '.question_form' });
- $('.edit_question_cancel').on('click', (e) => {
- e.preventDefault();
- const questionEdit = $(e.target).closest('.question_edit');
- questionEdit.hide();
- questionEdit.parent().find('.question_show').show();
- });
- $('.new_question_cancel').on('click', (e) => {
- const questionNew = $(e.target).closest('.question_new');
- questionNew.hide();
- questionNew.closest('.row').find('.question_new_link').show();
- });
- $('[name="question[question_format_id]"]').on('change', onChangeQuestionFormat);
-});
diff --git a/lib/assets/javascripts/views/questions/sharedEventHandlers.js b/lib/assets/javascripts/views/questions/sharedEventHandlers.js
deleted file mode 100644
index 484dece..0000000
--- a/lib/assets/javascripts/views/questions/sharedEventHandlers.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const onChangeQuestionFormat = (e) => {
- const source = e.target;
- const selected = source.value;
- const defaultValue = $(source).closest('form').find('[data-attribute="default_value"]');
- const questionOptions = $(source).closest('form').find('[data-attribute="question_options"]');
- const opComment = $(source).closest('form').find('[data-attribute="option_comment"]');
- switch (selected) {
- case '1':
- questionOptions.hide();
- opComment.hide();
- defaultValue.show();
- defaultValue.find('[data-attribute="textfield"]').hide();
- defaultValue.find('[data-attribute="textarea"]').show();
- break;
- case '2':
- questionOptions.hide();
- opComment.hide();
- defaultValue.show();
- defaultValue.find('[data-attribute="textarea"]').hide();
- defaultValue.find('[data-attribute="textfield"]').show();
- break;
- case '3':
- case '4':
- case '5':
- case '6':
- defaultValue.hide();
- questionOptions.show();
- opComment.show();
- break;
- case '7':
- defaultValue.hide();
- questionOptions.hide();
- opComment.show();
- break;
- default :
- break;
- }
-};
-
-export { onChangeQuestionFormat as default };
diff --git a/lib/assets/javascripts/views/questions/show.js b/lib/assets/javascripts/views/questions/show.js
deleted file mode 100644
index 7a744fd..0000000
--- a/lib/assets/javascripts/views/questions/show.js
+++ /dev/null
@@ -1,22 +0,0 @@
-$(() => {
- $('.question_edit_link').on('click', (e) => {
- const source = e.target;
- const target = $(source).attr('href');
- $(source).closest('.question_show').hide();
- $(target).show();
- });
-
- $('.annotations_button').on('click', (e) => {
- e.preventDefault();
- const target = $(e.target).attr('href');
- $(target).show();
- $(target).closest('.col-md-12').find('.show_annotations_div').hide();
- });
-
- $('.cancel_edit_annotations').on('click', (e) => {
- e.preventDefault();
- const target = $(e.target).attr('href');
- $(target).hide();
- $(target).closest('.col-md-12').find('.show_annotations_div').show();
- });
-});
diff --git a/lib/assets/javascripts/views/sections/edit.js b/lib/assets/javascripts/views/sections/edit.js
deleted file mode 100644
index 44a1faa..0000000
--- a/lib/assets/javascripts/views/sections/edit.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import { Tinymce } from '../../utils/tinymce';
-
-$(() => {
- Tinymce.init({ selector: '.section' });
-});
diff --git a/lib/assets/javascripts/views/sections/index.js b/lib/assets/javascripts/views/sections/index.js
deleted file mode 100644
index 6ef5ba3..0000000
--- a/lib/assets/javascripts/views/sections/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-$(() => {
- $('.section_new_link').on('click', (e) => {
- $(e.target).hide();
- $(e.target).closest('.row').find('.section_new').show();
- });
-});
diff --git a/lib/assets/javascripts/views/sections/new.js b/lib/assets/javascripts/views/sections/new.js
deleted file mode 100644
index e703eca..0000000
--- a/lib/assets/javascripts/views/sections/new.js
+++ /dev/null
@@ -1,7 +0,0 @@
-$(() => {
- $('.section_new_cancel').on('click', (e) => {
- const sectionNew = $(e.target).closest('.section_new');
- sectionNew.hide();
- sectionNew.closest('.row').find('.section_new_link').show();
- });
-});
diff --git a/lib/assets/stylesheets/overrides.scss b/lib/assets/stylesheets/overrides.scss
index d0801b7..1f833b3 100644
--- a/lib/assets/stylesheets/overrides.scss
+++ b/lib/assets/stylesheets/overrides.scss
@@ -502,6 +502,12 @@
}
}
+/* Templates page table pre-defined filters */
+.template-table-filters .navbar-nav > li > a {
+ color: $grey;
+ padding: 5px 15px 5px 5px;
+}
+
/* Sharp edges */
#app-navbar,
#org-navbar,
diff --git a/lib/tasks/upgrade.rake b/lib/tasks/upgrade.rake
index eb96b99..c0723dd 100644
--- a/lib/tasks/upgrade.rake
+++ b/lib/tasks/upgrade.rake
@@ -1,3 +1,4 @@
+require 'set'
namespace :upgrade do
desc "Upgrade to 1.0"
@@ -274,5 +275,98 @@
end
end
+ desc "Remove duplicated non customised template versions"
+ task remove_duplicated_non_customised_template_versions: :environment do
+ templates = Template
+ .select(:id, :family_id, :version, :updated_at)
+ .group(:family_id, :version, :id)
+ .order(family_id: :asc, version: :asc, updated_at: :desc)
+ current_family_id = nil
+ unique_versions = Set.new
+ duplicates = []
+ templates.each do |template|
+ if current_family_id != template.family_id
+ current_family_id = template.family_id
+ unique_versions = Set.new
+ end
+ if unique_versions.add?(template.version).nil?
+ duplicates << template
+ end
+ end
+ current_family_id = nil
+ version_counter = nil
+ duplicates.each do |template|
+ if current_family_id != template.family_id
+ current_family_id = template.family_id
+ version_counter = nil
+ end
+ num_plans = Plan.where(template_id: template.id).count
+ if num_plans > 0
+ version_counter = version_counter.nil? ? -1 : version_counter - 1
+ unsaved_template = Template.find(template.id)
+ unsaved_template.version = version_counter
+ if Template.exists?(customization_of: template.family_id)
+ puts "template with id: #{template.id} has NOT been ARCHIVED since it had customised templates"
+ else
+ puts "template with id: #{template.id} has been ARCHIVED since it had plans associated but no customised templates"
+ unsaved_template.archived = true
+ end
+ unsaved_template.save!
+ else
+ Template.destroy(template.id)
+ puts "template with id: #{template.id} has been REMOVED since it had no plans associated"
+ end
+ end
+ puts "remove_duplicated_non_customised_template_versions DONE"
+ end
+ desc "Remove duplicated customised template versions"
+ task remove_duplicated_customised_template_versions: :environment do
+ templates = Template
+ .select(:id, :customization_of, :version, :org_id, :updated_at)
+ .where('customization_of IS NOT NULL')
+ .group(:customization_of, :org_id, :version, :id)
+ .order(customization_of: :asc, org_id: :asc, version: :asc, updated_at: :desc)
+ generate_compound_key = lambda{ |customization_of, org_id| return "#{customization_of}_#{org_id}" }
+ current = nil
+ unique_versions = Set.new
+ duplicates = []
+ templates.each do |template|
+ key = generate_compound_key.call(template.customization_of, template.org_id)
+ if current != key
+ current = key
+ unique_versions = Set.new
+ end
+ if unique_versions.add?(template.version).nil?
+ duplicates << template
+ end
+ end
+ current = nil
+ version_counter = nil
+ duplicates.each do |template|
+ key = generate_compound_key.call(template.customization_of, template.org_id)
+ if current != key
+ current = key
+ version_counter = nil
+ end
+ num_plans = Plan.where(template_id: template.id).count
+ if num_plans > 0
+ version_counter = version_counter.nil? ? -1 : version_counter - 1
+ unsaved_template = Template.find(template.id)
+ unsaved_template.version = version_counter
+ unsaved_template.archived = true
+ unsaved_template.save!
+ puts "template with id: #{template.id} has been ARCHIVED since it had plans associated"
+ else
+ Template.destroy(template.id)
+ puts "template with id: #{template.id} has been REMOVED since it has no plans associated"
+ end
+ end
+ puts "remove_duplicated_customised_template_versions DONE"
+ end
+ desc "Remove duplicated template versions"
+ task remove_duplicated_template_versions: :environment do
+ Rake::Task['upgrade:remove_duplicated_non_customised_template_versions'].execute
+ Rake::Task['upgrade:remove_duplicated_customised_template_versions'].execute
+ end
end
diff --git a/lib/template_filter.rb b/lib/template_filter.rb
deleted file mode 100644
index 44a5189..0000000
--- a/lib/template_filter.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-module TemplateFilter
- # Applies scoping to the template list
- def apply_scoping(scope, customizable = false, all = false)
- if customizable
- # Retrieve all of the publicly visible published funder templates
- orgs = Org.funder.where.not(id: current_user.org.id)
- # Include the default template in the list of funder templates
- orgs << Template.default.org unless current_user.org == Template.default.org
-
- templates = Template.get_public_published_template_versions(orgs)
-
- # If the user is an Org Admin look for customizations to funder templates
- customizations = {}
- if current_user.can_org_admin?
- families = templates.collect(&:dmptemplate_id).uniq
- Template.org_customizations(families, current_user.org_id).each do |customization|
- customizations[customization.customization_of] = customization if customization.present?
- end
- end
-
- scopes = calculate_table_scopes(templates, customizations)
-
- # We scope based on the customizations
- if params[:scope].present? && params[:scope] != 'all'
- scoped = templates.select do |t|
- c = customizations[t.dmptemplate_id]
- (params[:scope] == 'unpublished' && (!c.present? || !c.published?)) || (params[:scope] == 'published' && c.present? && c.published?)
- end
- templates = Template.where(id: scoped.collect(&:id))
- end
-
- else
- # If we're collecting all templates
- if all
- templates = Template.get_latest_template_versions(Org.all)
- else
- templates = Template.get_latest_template_versions(Org.where(id: current_user.org.id))
- end
-
- scopes = calculate_table_scopes(templates, {})
-
- if params[:scope].present? && params[:scope] != 'all'
- templates = templates.where(published: true) if params[:scope] == 'published'
- templates = templates.where(published: false) if params[:scope] == 'unpublished'
- end
- end
-
- { templates: templates,
- customizations: customizations || {},
- scopes: scopes }
- end
-
- private
- # Gets the nbr of templates and nbr of published/unpublished templates
- def calculate_table_scopes(templates, customizations)
- scopes = { all: templates.length, published: 0, unpublished: 0, dmptemplate_ids: templates.collect(&:dmptemplate_id).uniq }
- templates.each do |t|
- # If we have customizations use their status
- if customizations.keys.length > 0
- c = customizations[t.dmptemplate_id]
- # If the template was not customized then its unpublished
- if c.nil?
- scopes[:unpublished] += 1
- else
- scopes[:published] += 1 if c.published?
- scopes[:unpublished] += 1 unless c.published?
- end
- else
- # Otherwise just use the template's published status
- scopes[:published] += 1 if t.published?
- scopes[:unpublished] += 1 unless t.published?
- end
- end
- scopes
- end
-
- def get_publication_dates(family_ids)
- published = {}
- lives = Template.live(family_ids)
- lives.each do |live|
- published[live.dmptemplate_id] = live.updated_at
- end
- published
- end
-end
\ No newline at end of file
diff --git a/test/functional/annotations_controller_test.rb b/test/functional/annotations_controller_test.rb
deleted file mode 100644
index f8ea039..0000000
--- a/test/functional/annotations_controller_test.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-require 'test_helper'
-
-class AnnotationsControllerTest < ActionDispatch::IntegrationTest
-
- include Devise::Test::IntegrationHelpers
-
- setup do
- @question = Annotation.first.question
-
- # Get the first Org Admin
- scaffold_org_admin(@question.section.phase.template.org)
-
- # clear the existing annotations
- @question.annotations.where(org: @user.org).each do |annotation|
- annotation.destroy!
- end
-
- @create_hash = {question_id: @question.id, example_answer_text: "New example", guidance_text: "New guidance"}
- @example_answer_qry = {question: @question, org: @user.org, type: Annotation.types[:example_answer]}
- @guidance_qry = {question: @question, org: @user.org, type: Annotation.types[:guidance]}
- end
-
- test "cannot create/update if not logged in" do
- # Should redirect user to the root path if they are not logged in!
- put admin_update_annotation_path(id: @question.section.phase.id), @create_hash
- assert_unauthorized_redirect_to_root_path
- end
-
- test "can create example answer and guidance at the same time" do
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), @create_hash
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('example answer') && flash[:notice].include?('guidance')
- assert_equal 'New example', Annotation.find_by(@example_answer_qry).text, "expected example answer to have been created."
- assert_equal 'New guidance', Annotation.find_by(@guidance_qry).text, "expected guidance to have been created."
- end
- test "can create example answer without a guidance" do
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), {question_id: @question.id, example_answer_text: "New example"}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('updated')
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert_equal 'New example', Annotation.find_by(@example_answer_qry).text, "expected example answer to have been created."
- assert Annotation.find_by(@guidance_qry).nil?, "expected no guidance to have been created."
- end
- test "can create guidance without an example answer" do
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), {question_id: @question.id, guidance_text: "New guidance"}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('updated')
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert Annotation.find_by(@example_answer_qry).nil?, "expected no example answer to have been created."
- assert_equal 'New guidance', Annotation.find_by(@guidance_qry).text, "expected guidance to have been created."
- end
-
- test "can update example answer and guidance at the same time" do
- put admin_update_annotation_path(id: @question.section.phase.id), @create_hash
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), {question_id: @question.id, example_answer_text: "Updated example", guidance_text: "Updated guidance"}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('updated')
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert_equal 'Updated example', Annotation.find_by(@example_answer_qry).text, "expected example answer to have been updated."
- assert_equal 'Updated guidance', Annotation.find_by(@guidance_qry).text, "expected guidance to have been updated."
- end
- test "can remove example answer by not submitting it during save" do
- put admin_update_annotation_path(id: @question.section.phase.id), @create_hash
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), {question_id: @question.id, guidance_text: "Updated guidance"}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('updated')
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert Annotation.find_by(@example_answer_qry).nil?, "expected example answer to have been removed."
- assert_equal 'Updated guidance', Annotation.find_by(@guidance_qry).text, "expected guidance to have been updated."
- end
- test "can remove guidance by not submitting it during save" do
- put admin_update_annotation_path(id: @question.section.phase.id), @create_hash
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), {question_id: @question.id, example_answer_text: "Updated example"}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('updated')
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert_equal 'Updated example', Annotation.find_by(@example_answer_qry).text, "expected example answer to have been updated."
- assert Annotation.find_by(@guidance_qry).nil?, "expected guidance to have been removed."
- end
-
- test "can delete a specific annotation" do
- sign_in @user
- put admin_update_annotation_path(id: @question.section.phase.id), @create_hash
- delete admin_destroy_annotation_path(Annotation.find_by(@example_answer_qry))
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('deleted')
- assert_response :redirect
- assert_redirected_to "#{admin_show_phase_path(@question.section.phase.id)}?section_id=#{@question.section.id}&r=all-templates"
- assert Annotation.find_by(@example_answer_qry).nil?
- assert_equal 'New guidance', Annotation.find_by(@guidance_qry).text, "expected guidance to have been unchanged."
- end
-end
\ No newline at end of file
diff --git a/test/functional/org_admin/phases_controller_test.rb b/test/functional/org_admin/phases_controller_test.rb
new file mode 100644
index 0000000..b7d4263
--- /dev/null
+++ b/test/functional/org_admin/phases_controller_test.rb
@@ -0,0 +1,146 @@
+require 'test_helper'
+
+class PhasesControllerTest < ActionDispatch::IntegrationTest
+
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @institution = init_institution
+ @researcher = init_researcher(@institution)
+ @org_admin = init_org_admin(@institution)
+ @template = init_template(@institution, {
+ title: 'Test Template',
+ published: true,
+ visibility: Template.visibilities[:publicly_visible]
+ })
+ @phase = init_phase(@template)
+ end
+
+ test "unauthorized user cannot access the show/edit page" do
+ get org_admin_template_phase_path(@template, @phase)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ get org_admin_template_phase_path(@template, @phase)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can access the show/edit page' do
+ sign_in @org_admin
+ get org_admin_template_phase_path(@template, @phase)
+ assert_response :success
+ assert_nil flash[:notice]
+ assert_nil flash[:alert]
+ end
+
+ test "unauthorized user cannot access the preview phase page" do
+ get preview_org_admin_template_phase_path(@template, @phase)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ get preview_org_admin_template_phase_path(@template, @phase)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can access the preview phase page' do
+ sign_in @org_admin
+ get preview_org_admin_template_phase_path(@template, @phase)
+ assert_response :success
+ assert_nil flash[:notice]
+ assert_nil flash[:alert]
+ end
+
+ test "unauthorized user cannot access the new phase page" do
+ get new_org_admin_template_phase_path(@template)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ get new_org_admin_template_phase_path(@template)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can access the new phase page' do
+ sign_in @org_admin
+ get new_org_admin_template_phase_path(@template)
+ assert_response :success
+ assert_nil flash[:notice]
+ assert_nil flash[:alert]
+ end
+
+ test 'unauthorized user cannot create a phase' do
+ params = { phase: { title: 'New phase', number: 2 } }
+ post org_admin_template_phases_path(@template), params
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ post org_admin_template_phases_path(@template), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can create a phase for an unpublished template' do
+ @template.update!(published: false)
+ params = { phase: { title: 'New phase', number: 2 } }
+ sign_in @org_admin
+ post org_admin_template_phases_path(@template), params
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @template.phases.last.id)
+ end
+
+ test 'authorized user can create a phase for a published template' do
+ params = { phase: { title: 'New phase', number: 2 } }
+ sign_in @org_admin
+ post org_admin_template_phases_path(@template), params
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.last.id)
+ end
+
+ test 'unauthorized user cannot edit a phase' do
+ params = { phase: { title: 'New phase' } }
+ put org_admin_template_phase_path(@template, @phase), params
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ put org_admin_template_phase_path(@template, @phase), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can edit a phase for an unpublished template' do
+ @template.update!(published: false)
+ params = { phase: { title: 'New phase' } }
+ sign_in @org_admin
+ put org_admin_template_phase_path(@template, @phase), params
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @template.phases.last.id)
+ end
+
+ test 'authorized user can edit a phase for a published template' do
+ params = { phase: { title: 'New phase' } }
+ sign_in @org_admin
+ put org_admin_template_phase_path(@template, @phase), params
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.last.id)
+ end
+
+ test 'unauthorized user cannot delete a phase' do
+ delete org_admin_template_phase_path(@template, @phase)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ delete org_admin_template_phase_path(@template, @phase)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can delete a phase from an unpublished template' do
+ @template.update!(published: false)
+ params = { phase: { title: 'New phase' } }
+ sign_in @org_admin
+ delete org_admin_template_phase_path(@template, @phase)
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_path(@template.id)
+ end
+
+ test 'authorized user can delete a phase from a published template' do
+ params = { phase: { title: 'New phase' } }
+ sign_in @org_admin
+ delete org_admin_template_phase_path(@template, @phase)
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_path(template.id)
+ end
+end
diff --git a/test/functional/org_admin/questions_controller_test.rb b/test/functional/org_admin/questions_controller_test.rb
new file mode 100644
index 0000000..1324e3f
--- /dev/null
+++ b/test/functional/org_admin/questions_controller_test.rb
@@ -0,0 +1,133 @@
+require 'test_helper'
+
+class QuestionsControllerTest < ActionDispatch::IntegrationTest
+
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @institution = init_institution
+ @researcher = init_researcher(@institution)
+ @org_admin = init_org_admin(@institution)
+ @template = init_template(@institution, {
+ title: 'Test Template',
+ published: true,
+ visibility: Template.visibilities[:publicly_visible]
+ })
+ @phase = init_phase(@template)
+ @section = init_section(@phase)
+ @text_area = init_question_format({ title: 'Test question format' })
+ @question = init_question(@section)
+ end
+
+ test 'unauthorized user cannot call question_controller#create' do
+ params = { question: { text: 'New question test', number: 2, question_format_id: @text_area.id } }
+ post org_admin_template_phase_section_questions_path(@template, @phase, @section), params
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ post org_admin_template_phase_section_questions_path(@template, @phase, @section), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'unauthorized user cannot call question_controller#create for another org\'s template' do
+ params = { question: { text: 'New question test', number: 2, question_format_id: @text_area.id } }
+ funder = init_funder
+ funder_template = init_template(funder)
+ funder_phase = init_phase(funder_template)
+ funder_section = init_section(funder_phase)
+ sign_in @org_admin
+ post org_admin_template_phase_section_questions_path(funder_template, funder_phase, funder_section), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can call question_controller#create for an unpublished template' do
+ @template.update!(published: false)
+ params = { question: { text: 'New question test', number: 2, question_format_id: @text_area.id } }
+ sign_in @org_admin
+ post org_admin_template_phase_section_questions_path(@template, @phase, @section), params
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @phase.id, section: @section.id)
+ end
+
+ test 'authorized user can call question_controller#create for a published template' do
+ params = { question: { text: 'New question test', number: 2, question_format_id: @text_area.id } }
+ sign_in @org_admin
+ post org_admin_template_phase_section_questions_path(@template, @phase, @section), params
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.first.id, section: template.phases.first.sections.first.id)
+ end
+
+ test 'unauthorized user cannot call question_controller#edit' do
+ params = { section: { text: 'Edited question' } }
+ put org_admin_template_phase_section_question_path(@template, @phase, @section, @question), params
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ put org_admin_template_phase_section_question_path(@template, @phase, @section, @question), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'unauthorized user cannot call question_controller#edit for another org\'s template' do
+ params = { section: { text: 'Edited question' } }
+ funder = init_funder
+ funder_template = init_template(funder)
+ funder_phase = init_phase(funder_template)
+ funder_section = init_section(funder_phase)
+ funder_question = init_question(funder_section)
+ sign_in @org_admin
+ put org_admin_template_phase_section_question_path(funder_template, funder_phase, funder_section, funder_question), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can call question_controller#edit for an unpublished template' do
+ @template.update!(published: false)
+ params = { section: { text: 'Edited question' } }
+ sign_in @org_admin
+ put org_admin_template_phase_section_question_path(@template, @phase, @section, @question), params
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @phase.id, section: @section.id)
+ end
+
+ test 'authorized user can call question_controller#edit for a published template' do
+ params = { section: { text: 'Edited question' } }
+ sign_in @org_admin
+ put org_admin_template_phase_section_question_path(@template, @phase, @section, @question), params
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.first.id, section: template.phases.first.sections.first.id)
+ end
+
+ test 'unauthorized user cannot call question_controller#destroy' do
+ delete org_admin_template_phase_section_question_path(@template, @phase, @section, @question)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ delete org_admin_template_phase_section_question_path(@template, @phase, @section, @question)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'unauthorized user cannot call question_controller#destroy for another org\'s template' do
+ funder = init_funder
+ funder_template = init_template(funder)
+ funder_phase = init_phase(funder_template)
+ funder_section = init_section(funder_phase)
+ funder_question = init_question(funder_section)
+ sign_in @org_admin
+ delete org_admin_template_phase_section_question_path(funder_template, funder_phase, funder_section, funder_question)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can call question_controller#destroy for an unpublished template' do
+ @template.update!(published: false)
+ sign_in @org_admin
+ delete org_admin_template_phase_section_question_path(@template, @phase, @section, @question)
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @phase.id, section: @section.id)
+ end
+
+ test 'authorized user can call question_controller#destroy for a published template' do
+ sign_in @org_admin
+ delete org_admin_template_phase_section_question_path(@template, @phase, @section, @question)
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.first.id, section: template.phases.first.sections.first.id)
+ end
+end
\ No newline at end of file
diff --git a/test/functional/org_admin/sections_controller_test.rb b/test/functional/org_admin/sections_controller_test.rb
new file mode 100644
index 0000000..6bb2c4c
--- /dev/null
+++ b/test/functional/org_admin/sections_controller_test.rb
@@ -0,0 +1,174 @@
+require 'test_helper'
+
+class SectionsControllerTest < ActionDispatch::IntegrationTest
+
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @institution = init_institution
+ @researcher = init_researcher(@institution)
+ @org_admin = init_org_admin(@institution)
+ @template = init_template(@institution, {
+ title: 'Test Template',
+ published: true,
+ visibility: Template.visibilities[:publicly_visible]
+ })
+ @phase = init_phase(@template)
+ @section = init_section(@phase)
+ end
+
+ test "unauthorized user cannot access the index page" do
+ get org_admin_template_phase_sections_path(@template, @phase)
+ assert_unauthorized_redirect_to_root_path
+ end
+
+ test 'authorized user can access the index page' do
+ [@researcher, @org_admin].each do |user|
+ sign_in user
+ get org_admin_template_phase_sections_path(@template, @phase)
+ assert_response :success, "expected #{user.name(false)} to be able to access the section_controller#index page"
+ assert_nil flash[:notice]
+ assert_nil flash[:alert]
+ end
+ end
+
+ test "unauthorized user cannot access the section_controller#show page" do
+ get org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_unauthorized_redirect_to_root_path
+ end
+
+ test 'authorized user can access the section_controller#show page' do
+ [@researcher, @org_admin].each do |user|
+ sign_in user
+ get org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_response :success, "expected #{user.name(false)} to be able to access the section_controller#show page"
+ assert_nil flash[:notice]
+ assert_nil flash[:alert]
+ end
+ end
+
+ test "unauthorized user cannot access the section_controller#edit page" do
+ get edit_org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ get edit_org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can access the section_controller#edit page' do
+ sign_in @org_admin
+ get edit_org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_response :success
+ assert_nil flash[:notice]
+ assert_nil flash[:alert]
+ end
+
+ test 'unauthorized user cannot call section_controller#create' do
+ params = { section: { title: 'New section', number: 2 } }
+ post org_admin_template_phase_sections_path(@template, @phase), params
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ post org_admin_template_phase_sections_path(@template, @phase), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'unauthorized user cannot call section_controller#create for another org\'s template' do
+ params = { section: { title: 'New section', number: 2 } }
+ funder = init_funder
+ funder_template = init_template(funder)
+ funder_phase = init_phase(funder_template)
+ sign_in @org_admin
+ post org_admin_template_phase_sections_path(funder_template, funder_phase), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can call section_controller#create for an unpublished template' do
+ @template.update!(published: false)
+ params = { section: { title: 'New section', number: 2 } }
+ sign_in @org_admin
+ post org_admin_template_phase_sections_path(@template, @phase), params
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @phase.id, section: @phase.sections.last.id)
+ end
+
+ test 'authorized user can call section_controller#create for a published template' do
+ params = { section: { title: 'New section', number: 2 } }
+ sign_in @org_admin
+ post org_admin_template_phase_sections_path(@template, @phase), params
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.first.id, section: template.phases.first.sections.last.id)
+ end
+
+ test 'unauthorized user cannot call section_controller#edit' do
+ params = { section: { title: 'Edited section' } }
+ put org_admin_template_phase_section_path(@template, @phase, @section), params
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ put org_admin_template_phase_section_path(@template, @phase, @section), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'unauthorized user cannot call section_controller#edit for another org\'s template' do
+ params = { section: { title: 'Edited section' } }
+ funder = init_funder
+ funder_template = init_template(funder)
+ funder_phase = init_phase(funder_template)
+ funder_section = init_section(funder_phase)
+ sign_in @org_admin
+ put org_admin_template_phase_section_path(funder_template, funder_phase, funder_section), params
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can call section_controller#edit for an unpublished template' do
+ @template.update!(published: false)
+ params = { section: { title: 'Edited section' } }
+ sign_in @org_admin
+ put org_admin_template_phase_section_path(@template, @phase, @section), params
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @phase.id, section: @phase.sections.last.id)
+ end
+
+ test 'authorized user can call section_controller#edit for a published template' do
+ params = { section: { title: 'Edited section' } }
+ sign_in @org_admin
+ put org_admin_template_phase_section_path(@template, @phase, @section), params
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.first.id, section: template.phases.first.sections.last.id)
+ end
+
+ test 'unauthorized user cannot call section_controller#destroy' do
+ delete org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ delete org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'unauthorized user cannot call section_controller#destroy for another org\'s template' do
+ funder = init_funder
+ funder_template = init_template(funder)
+ funder_phase = init_phase(funder_template)
+ funder_section = init_section(funder_phase)
+ sign_in @org_admin
+ delete org_admin_template_phase_section_path(funder_template, funder_phase, funder_section)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test 'authorized user can call section_controller#destroy for an unpublished template' do
+ @template.update!(published: false)
+ sign_in @org_admin
+ delete org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: @template.id, id: @phase.id)
+ end
+
+ test 'authorized user can call section_controller#destroy for a published template' do
+ sign_in @org_admin
+ delete org_admin_template_phase_section_path(@template, @phase, @section)
+ assert_response :redirect
+ template = Template.latest_version(@template.family_id).first
+ assert_redirected_to edit_org_admin_template_phase_path(template_id: template.id, id: template.phases.first.id)
+ end
+end
\ No newline at end of file
diff --git a/test/functional/org_admin/templates_controller_test.rb b/test/functional/org_admin/templates_controller_test.rb
index 569cfb0..d09ff86 100644
--- a/test/functional/org_admin/templates_controller_test.rb
+++ b/test/functional/org_admin/templates_controller_test.rb
@@ -5,567 +5,305 @@
include Devise::Test::IntegrationHelpers
setup do
- scaffold_template
-
- # Get the first Org Admin
- scaffold_org_admin(@template.org)
+ @funder = init_funder
+ @institution = init_institution
+ @organisation = init_organisation
- @regular_user = User.find_by(email: 'org_user@example.com')
+ @researcher = init_researcher(@institution)
+ @org_admin = init_org_admin(@institution)
+ @super_admin = init_super_admin(@organisation)
+
+ @funder_template = init_template(@funder, {
+ title: 'Test Funder Template',
+ published: true,
+ visibility: Template.visibilities[:publicly_visible]
+ })
+ @org_template = init_template(@institution, {
+ title: 'Test Org Template',
+ published: true
+ })
end
- test "unauthorized user cannot access the templates page" do
- # Should redirect user to the root path if they are not logged in!
+ test "unauthorized user cannot access the templates#index page" do
get org_admin_templates_path
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
+ sign_in @researcher
+ get org_admin_templates_path
+ assert_authorized_redirect_to_plans_page
+ sign_in @org_admin
get org_admin_templates_path
assert_authorized_redirect_to_plans_page
end
- test "Org admin sees the correct templates on the templates page" do
- init_templates
- sign_in @org_admin
- get org_admin_templates_path
-
- verify_all_templates_table(@org_admin)
- verify_own_templates_table(@org_admin)
- verify_funder_templates_table(@org_admin)
- end
-
- test "Funder admin sees the correct templates on the templates page" do
- init_templates
- sign_in @funder_admin
- get org_admin_templates_path
-
- verify_all_templates_table(@funder_admin)
- verify_own_templates_table(@funder_admin)
- verify_funder_templates_table(@funder_admin)
- end
-
- test "Super admin sees the correct templates on the templates page" do
- init_templates
+ test "authorized user can access the templates#index page" do
sign_in @super_admin
get org_admin_templates_path
-
- verify_all_templates_table(@super_admin)
- verify_own_templates_table(@super_admin)
- verify_funder_templates_table(@super_admin)
- end
-
- test "Predefined scopes correctly filter results on all templates table" do
- init_templates
- sign_in @super_admin
- get org_admin_templates_path
-
- verify_all_templates_table(@super_admin)
-
- published = Template.latest_version.where(published: true, customization_of: nil)
- unpublished = Template.latest_version.where(published: false, customization_of: nil)
- verify_templates_table_scoping(all_paginable_templates_path('ALL'), '#all-templates', published, unpublished)
- end
-
- test "Predefined scopes correctly filter results on own templates table" do
- init_templates
- sign_in @org_admin
- get org_admin_templates_path
-
- verify_all_templates_table(@org_admin)
-
- published = Template.get_latest_template_versions(@org_admin.org).where(published: true, customization_of: nil)
- unpublished = Template.get_latest_template_versions(@org_admin.org).where(published: false, customization_of: nil)
- verify_templates_table_scoping(orgs_paginable_templates_path('ALL'), '#organisation-templates', published, unpublished)
- end
-
- test "Predefined scopes correctly filter results on customizable templates table" do
- init_templates
- sign_in @org_admin
- get org_admin_templates_path
-
- verify_all_templates_table(@org_admin)
-
- published = Template.where(title: 'UOS customization of Default template')
- unpublished = Template.where('published = 1 AND visibility = 1 AND is_default = 0')
- verify_templates_table_scoping(funders_paginable_templates_path('ALL'), '#funders-templates', published, unpublished)
- end
-
- test "unauthorized user cannot access the template edit page" do
- # Should redirect user to the root path if they are not logged in!
- get edit_org_admin_template_path(@template)
- assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get edit_org_admin_template_path(@template)
- assert_authorized_redirect_to_plans_page
- end
-
- test 'get templates#edit returns ok when template is current and is NOT published' do
- sign_in @user
- get(edit_org_admin_template_path(@template.id))
- assert_response(:ok)
- assert_nil(flash[:notice])
- end
-
- test 'get templates#edit returns ok with flash notice when template is not current' do
- new_version = Template.deep_copy(@template)
- new_version.version = (@template.version + 1)
- new_version.save
- sign_in @user
- get(edit_org_admin_template_path(@template.id))
- assert_response(:ok)
- assert_equal(_('You are viewing a historical version of this template. You will not be able to make changes.'), flash[:notice])
- end
-
- test "unauthorized user cannot access the new template page" do
- # Should redirect user to the root path if they are not logged in!
- get new_org_admin_template_path(Template.last.id)
- assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get new_org_admin_template_path(Template.last.id)
- assert_authorized_redirect_to_plans_page
- end
-
- test "get the new template page" do
- sign_in @user
-
- get new_org_admin_template_path(Template.last.id)
assert_response :success
end
- test "unauthorized user cannot access the template history page" do
- # Should redirect user to the root path if they are not logged in!
- get history_org_admin_template_path(@template)
+ test "unauthorized user cannot access the templates#organisational page" do
+ get organisational_org_admin_templates_path
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get history_org_admin_template_path(@template)
+ sign_in @researcher
+ get organisational_org_admin_templates_path
assert_authorized_redirect_to_plans_page
end
-
- test "get the template history page" do
- sign_in @user
- get history_org_admin_template_path(@template)
+ test "authorized user can access the templates#organisational page" do
+ sign_in @org_admin
+ get organisational_org_admin_templates_path
assert_response :success
-
- assert assigns(:template)
- assert assigns(:templates)
- assert assigns(:current)
end
-
- test "unauthorized user cannot delete a template" do
- # Should redirect user to the root path if they are not logged in!
- delete org_admin_template_path(@template)
+
+ test "unauthorized user cannot access the templates#customisable page" do
+ get customisable_org_admin_templates_path
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- delete org_admin_template_path(@template)
+ sign_in @researcher
+ get customisable_org_admin_templates_path
assert_authorized_redirect_to_plans_page
end
- test "delete the admin template" do
- id = @template.id
- sign_in @user
+ test "authorized user can access the templates#customisable page" do
+ sign_in @org_admin
+ get customisable_org_admin_templates_path
+ assert_response :success
+ end
+
+ test "unauthorized user cannot access the template#edit page" do
+ get edit_org_admin_template_path(@org_template)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ get edit_org_admin_template_path(@org_template)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test "authorized user can access the template#edit page" do
+ sign_in @org_admin
+ get edit_org_admin_template_path(@org_template)
+ assert_response :success
+ end
- family = @template.dmptemplate_id
- prior = Template.current(family)
-
- version_the_template
-
- current = Template.current(family)
-
- # Try to delete a historical version should fail
- delete org_admin_template_path(prior)
- assert_equal _('You cannot delete historical versions of this template.'), flash[:alert]
- assert_response :redirect
- assert_redirected_to org_admin_templates_path(r: 'all-templates')
- assert_not Template.find(prior.id).nil?
-
- # Try to delete the current version should work
- delete org_admin_template_path(current)
- assert_response :redirect
- assert_redirected_to org_admin_templates_path(r: 'all-templates')
- assert_raise ActiveRecord::RecordNotFound do
- Template.find(current.id).nil?
+ test "admin cannot access another org's template#edit page" do
+ sign_in @org_admin
+ get edit_org_admin_template_path(@funder_template)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test "super admin can access any org's template#edit page" do
+ sign_in @super_admin
+ [@org_template, @funder_template].each do |template|
+ get edit_org_admin_template_path(template)
+ assert_response :success
end
- assert_equal prior, Template.current(family), "expected the old version to now be the current version"
-
- # Should not be able to delete a template that has plans!
end
- test "unauthorized user cannot create a template" do
- # Should redirect user to the root path if they are not logged in!
- post org_admin_templates_path(@user.org), {template: {title: ''}}
+ test 'get templates#edit returns ok when template is latest' do
+ sign_in @org_admin
+ get(edit_org_admin_template_path(@org_template))
+ assert_response :success
+ assert_nil flash[:notice], 'expected no warning messages'
+ end
+
+ test 'get templates#edit returns ok with flash notice when template is not latest' do
+ new_version = @org_template.generate_version!
+ sign_in @org_admin
+ get(edit_org_admin_template_path(@org_template.id))
+ assert_response :success
+ assert_not_nil flash[:notice], 'expected a warning message'
+ end
+
+ test "unauthorized user cannot access the template#new page" do
+ get new_org_admin_template_path
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- post org_admin_templates_path(@user.org), {template: {title: ''}}
+ sign_in @researcher
+ get new_org_admin_template_path
assert_authorized_redirect_to_plans_page
end
- test "create a template" do
- params = {title: 'Testing create route'}
- sign_in @user
+ test "authorized user can access the template#new page" do
+ sign_in @org_admin
+ get new_org_admin_template_path
+ assert_response :success
+ end
+
+ test "unauthorized user cannot access the template#history page" do
+ get history_org_admin_template_path(@org_template)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ get history_org_admin_template_path(@org_template)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test "authorized user can access the template#history page" do
+ sign_in @org_admin
+ get history_org_admin_template_path(@org_template)
+ assert_response :success
+ end
- post org_admin_templates_path(@user.org), {template: params}
+ test "unauthorized user cannot access template#delete" do
+ delete org_admin_template_path(@org_template)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ delete org_admin_template_path(@org_template)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test "authorized user can access template#delete" do
+ sign_in @org_admin
+ delete org_admin_template_path(@org_template)
+ assert_response :redirect
+ assert_redirected_to org_admin_templates_path
+ assert_nil flash[:alert]
+ end
+
+ test "unauthorized user cannot create a template#create" do
+ post org_admin_templates_path(@institution), {template: {title: ''}}
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ post org_admin_templates_path(@institution), {template: {title: ''}}
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test "authorized user can create a template#create" do
+ params = {title: 'Testing create route'}
+ sign_in @org_admin
+
+ post org_admin_templates_path(@institution), {template: params}
assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('created')
assert_response :redirect
assert_redirected_to edit_org_admin_template_url(Template.last.id)
- assert assigns(:template)
- assert_equal 'Testing create route', Template.last.title, "expected the record to have been created!"
-
- # Invalid object
- post org_admin_templates_path(@user.org), {template: {title: nil, org_id: @user.org.id}}
- assert flash[:alert].starts_with?(_('Could not create your'))
- assert_response :success
- assert assigns(:template)
- assert assigns(:hash)
end
- test "unauthorized user cannot update a template" do
- # Should redirect user to the root path if they are not logged in!
- put org_admin_template_path(@template), {template: {title: ''}}
+ test "unauthorized user cannot update a template#update" do
+ put org_admin_template_path(@org_template), {template: {title: ''}}
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- put org_admin_template_path(@template), {template: {title: ''}}
+ sign_in @researcher
+ put org_admin_template_path(@org_template), {template: {title: ''}}
assert_authorized_redirect_to_plans_page
end
- test "update the template" do
+ test "authorized user can update the template#update" do
params = {title: 'ABCD'}
- sign_in @user
-
- family = @template.dmptemplate_id
- prior = Template.current(family)
-
- version_the_template
-
- current = Template.current(family)
-
- # We shouldn't be able to edit a historical version
- put org_admin_template_path(prior), {template: params}
- assert_response :forbidden
- json_body = ActiveSupport::JSON.decode(response.body)
- assert_equal(_('You can not edit a historical version of this template.'), json_body["msg"])
-
- # Make sure we get the right response when editing an unpublished template
- put org_admin_template_path(current), {template: params}
+ sign_in @org_admin
+ put org_admin_template_path(@org_template), {template: params}
assert_response :ok
json_body = ActiveSupport::JSON.decode(response.body)
assert json_body["msg"].start_with?('Successfully') && json_body["msg"].include?('saved')
- assert_equal('ABCD', current.reload.title, "expected the record to have been updated")
-
- # Make sure we get the right response when providing an invalid template
- put org_admin_template_path(current), {template: {title: nil}}
- assert_response :bad_request
- json_body = ActiveSupport::JSON.decode(response.body)
- assert json_body["msg"].starts_with?(_('Could not update your'))
end
- test "unauthorized user cannot customize a template" do
- # Make sure we are redirected if we're not logged in
- get customize_org_admin_template_path(@template)
+ test "unauthorized user cannot customize a template#customize" do
+ post customize_org_admin_template_path(@org_template)
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get customize_org_admin_template_path(@template)
+ sign_in @researcher
+ post customize_org_admin_template_path(@org_template)
+ assert_authorized_redirect_to_plans_page
+ end
+
+ test "authorized user can customize a funder template#customize" do
+ @funder_template.update!({ published: true })
+ sign_in @org_admin
+ post customize_org_admin_template_path(@funder_template)
+ assert_response :redirect
+ assert_redirected_to org_admin_template_url(Template.latest_customized_version(@funder_template.family_id, @institution.id).first)
+ end
+
+ test "unauthorized user cannot publish a template#publish" do
+ patch publish_org_admin_template_path(@org_template)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ patch publish_org_admin_template_path(@org_template)
assert_authorized_redirect_to_plans_page
end
- test "customize a funder template" do
- funder_template = Template.create(org: Org.funder.first, title: 'Testing integration')
-
- # Sign in as the funder so that we cna publish the template
- sign_in User.find_by(org: funder_template.org)
-
- get publish_org_admin_template_path(funder_template)
- assert_response :redirect
- assert_redirected_to "#{org_admin_templates_path}#organisation-templates"
-
- # Sign in as the regular user so we can customize the funder template
- sign_in @user
-
- template = Template.live(funder_template.dmptemplate_id)
-
- get customize_org_admin_template_path(template)
-
- customization = Template.where(customization_of: template.dmptemplate_id).last
-
- assert_response :redirect
- assert_redirected_to edit_org_admin_template_url(Template.last, r: 'funder-templates')
- assert assigns(:template)
-
- assert_equal 0, customization.version
- assert_not customization.published?
- assert customization.dirty?
-
- # Make sure the funder templates data is not modifiable!
- customization.phases.each do |p|
- assert_not p.modifiable
- p.sections.each do |s|
- assert_not s.modifiable
- s.questions.each do |q|
- assert_not q.modifiable
- end
- end
- end
- end
-
- test "unauthorized user cannot publish a template" do
- # Should redirect user to the root path if they are not logged in!
- get publish_org_admin_template_path(@template)
- assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get publish_org_admin_template_path(@template)
+ test "authorized user cannot publish another org's template#publish" do
+ sign_in @org_admin
+ patch publish_org_admin_template_path(@funder_template)
assert_authorized_redirect_to_plans_page
end
- test "publish a template" do
- sign_in @user
-
- family = @template.dmptemplate_id
- prior = Template.current(family)
-
- version_the_template
-
- current = Template.current(family)
-
- # We shouldn't be able to edit a historical version
- get publish_org_admin_template_path(prior)
- assert_equal _('You can not publish a historical version of this template.'), flash[:alert]
- assert_response :redirect
- assert_redirected_to org_admin_templates_path
-
- # Publish the current template
- get publish_org_admin_template_path(current)
+ test "authorized user can publish a template#publish" do
+ sign_in @org_admin
+ patch publish_org_admin_template_path(@org_template)
assert_equal _('Your template has been published and is now available to users.'), flash[:notice]
assert_response :redirect
- assert_redirected_to "#{org_admin_templates_path}#organisation-templates"
- current = Template.current(family)
+ assert_redirected_to org_admin_templates_path
end
- test "unauthorized user cannot unpublish a template" do
- # Should redirect user to the root path if they are not logged in!
- get unpublish_org_admin_template_path(@template)
+ test "unauthorized user cannot unpublish a template#unpublish" do
+ patch unpublish_org_admin_template_path(@org_template)
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get unpublish_org_admin_template_path(@template)
+ sign_in @researcher
+ patch unpublish_org_admin_template_path(@org_template)
assert_authorized_redirect_to_plans_page
end
- test "unpublish a template" do
- sign_in @user
-
- family = @template.dmptemplate_id
-
- prior = Template.current(family)
-
- version_the_template
-
- current = Template.current(family)
-
- # Publish it so we can unpublish
- get publish_org_admin_template_path(current)
- assert_not Template.live(family).nil?
-
- get unpublish_org_admin_template_path(current)
- assert_equal _('Your template is no longer published. Users will not be able to create new DMPs for this template until you re-publish it'), flash[:notice]
+ test "authorized user can unpublish a template#unpublish" do
+ sign_in @org_admin
+ patch unpublish_org_admin_template_path(@org_template)
assert_response :redirect
- assert_redirected_to "#{org_admin_templates_path}#organisation-templates"
-
- # Make sure there are no published versions
- assert Template.live(family).nil?
+ assert_redirected_to org_admin_templates_path
end
- test "unauthorized user cannot copy a template" do
- # Should redirect user to the root path if they are not logged in!
- get copy_org_admin_template_path(@template)
+ test "unauthorized user cannot copy a template#copy" do
+ post copy_org_admin_template_path(@org_template)
assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get copy_org_admin_template_path(@template)
+ sign_in @researcher
+ post copy_org_admin_template_path(@org_template)
assert_authorized_redirect_to_plans_page
end
- test "copy a template" do
- sign_in @user
- get copy_org_admin_template_path(@template)
+ test "unauthorized user cannot copy another org's template template#copy" do
+ sign_in @researcher
+ post copy_org_admin_template_path(@funder_template)
assert_response :redirect
- assert_redirected_to edit_org_admin_template_url(Template.last, edit: true, r: 'organisation-templates')
- end
-
- test "unauthorized user cannot transfer a template customization" do
- # Should redirect user to the root path if they are not logged in!
- get transfer_customization_org_admin_template_path(@template)
- assert_unauthorized_redirect_to_root_path
- # Non Org-Admin cannot perform this action
- sign_in @regular_user
- get transfer_customization_org_admin_template_path(@template)
assert_authorized_redirect_to_plans_page
end
- test "transfer a template customization" do
- # TODO add test for this. Could not get working, getting a nil for max_version within the method (NOT SURE IF THIS IS STILL IN USE!)
- end
-
- private
- def init_templates
- # First clear out any existing templates
- Template.all.each do |template|
- template.destroy!
- end
-
- @super_admin = User.find_by(email: 'super_admin@example.com')
- @org_admin = User.find_by(email: 'org_admin@example.com')
- @funder_admin = User.find_by(email: 'funder_admin@example.com')
-
- default_org = Org.find_by(org_type: 4)
- funder_org = Org.find_by(org_type: 2)
- institution_org = Org.find_by(org_type: 1)
- other_org = Org.create!(name: 'Another Org', abbreviation: 'BLAH', org_type: 3, links: {"org":[]})
-
- params = [{ title: 'Default template', org: default_org, migrated: false, dmptemplate_id: '00000100', published: true, version: 0, visibility: Template.visibilities[:publicly_visible], is_default: true },
- { title: 'UOS published A', org: institution_org, migrated: false, dmptemplate_id: '00000099', published: true, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'UOS published B', org: institution_org, migrated: false, dmptemplate_id: '00000098', published: true, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'UOS unpublished C', org: institution_org, migrated: false, dmptemplate_id: '00000097', published: false, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'UOS unpublished Dv0', org: institution_org, migrated: false, dmptemplate_id: '00000096', published: false, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'UOS published Dv1', org: institution_org, migrated: false, dmptemplate_id: '00000096', published: true, version: 1, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'UOS published Ev0', org: institution_org, migrated: false, dmptemplate_id: '00000095', published: true, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'UOS unpublished Ev1', org: institution_org, migrated: false, dmptemplate_id: '00000095', published: false, version: 1, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'BLAH internal published A', org: other_org, migrated: false, dmptemplate_id: '00000079', published: true, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'BLAH public published B', org: other_org, migrated: false, dmptemplate_id: '00000078', published: true, version: 0, visibility: Template.visibilities[:publicly_visible], is_default: false },
- { title: 'Funder public published A', org: funder_org, migrated: false, dmptemplate_id: '00000089', published: true, version: 0, visibility: Template.visibilities[:publicly_visible], is_default: false },
- { title: 'Funder internal published B', org: funder_org, migrated: false, dmptemplate_id: '00000088', published: true, version: 0, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'Funder internal unpublished B', org: funder_org, migrated: false, dmptemplate_id: '00000088', published: false, version: 1, visibility: Template.visibilities[:organisationally_visible], is_default: false },
- { title: 'Funder public unpublished C', org: funder_org, migrated: false, dmptemplate_id: '00000087', published: false, version: 0, visibility: Template.visibilities[:publicly_visible], is_default: false },
- { title: 'Funder public unpublished Dv0', org: funder_org, migrated: false, dmptemplate_id: '00000086', published: false, version: 0, visibility: Template.visibilities[:publicly_visible], is_default: false },
- { title: 'Funder public published Dv1', org: funder_org, migrated: false, dmptemplate_id: '00000086', published: true, version: 1, visibility: Template.visibilities[:publicly_visible], is_default: false },
- { title: 'Funder public published Ev0', org: funder_org, migrated: false, dmptemplate_id: '00000085', published: true, version: 0, visibility: Template.visibilities[:publicly_visible], is_default: false },
- { title: 'Funder public unpublished Ev1', org: funder_org, migrated: false, dmptemplate_id: '00000085', published: false, version: 1, visibility: Template.visibilities[:publicly_visible], is_default: false }]
-
- params.each do |hash|
- begin
- template = Template.new(hash)
- template.save!
- # Template's have default values when created, so override those defaults
- template.update_attributes!(published: hash[:published], visibility: hash[:visibility], is_default: hash[:is_default], dmptemplate_id: hash[:dmptemplate_id])
-
- if template.is_default?
- cust = Template.create!({ title: 'UOS customization of Default template', org: institution_org, migrated: false, version: 0})
- cust.update_attributes(published: true, customization_of: template.dmptemplate_id, visibility: Template.visibilities[:organisationally_visible])
- elsif template.title == 'Funder public published A'
- cust = Template.create!({ title: 'UOS customization of Funder public published A', org: institution_org, migrated: false, version: 0})
- cust.update_attributes(published: false, customization_of: template.dmptemplate_id, visibility: Template.visibilities[:organisationally_visible])
- end
- rescue ActiveRecord::RecordInvalid
- puts "EXCEPTION: #{template.errors.collect{ |e, m| "#{e}: #{m}" }.join(', ')}"
- end
- end
+ test "authorized super admin can copy another org's template template#copy" do
+ sign_in @super_admin
+ post copy_org_admin_template_path(@funder_template)
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_url(Template.where(org_id: @organisation.id).order(id: :desc).last)
end
- def verify_all_templates_table(user)
- if user.can_super_admin?
- assert_select "#all-templates table tbody", true, "expected a super admin to be able to see the all templates table"
- else
- assert_select "#all-templates table tbody", false, "expected a non-super admin to NOT see the all templates table"
- end
+ test "authorized user can copy a template#copy" do
+ sign_in @org_admin
+ post copy_org_admin_template_path(@org_template)
+ assert_response :redirect
+ assert_redirected_to edit_org_admin_template_url(Template.where(org_id: @institution.id).last)
+ end
+
+ test "unauthorized user cannot transfer a template customization template#transfer_customization" do
+ post transfer_customization_org_admin_template_path(@org_template)
+ assert_unauthorized_redirect_to_root_path
+ sign_in @researcher
+ post transfer_customization_org_admin_template_path(@org_template)
+ assert_authorized_redirect_to_plans_page
end
- def verify_own_templates_table(user)
- assert_select "#organisation-templates table tbody" do |el|
- templates = Template.where(org: user.org, customization_of: nil)
-
- # Org Admins (funder or non-funder)
- if user.can_org_admin?
- # An Org Admin (for a non-funder Org) should only see their current templates in the own templates table
- templates.each do |template|
- # Expect to see the most current version of organisational templates
- current = Template.current(template.dmptemplate_id)
- if template == current
- assert el.to_s.include?(template.title), "expected #{user.email}'s own templates table to have the institutional template: '#{template.title}'"
- else
- assert_not el.to_s.include?(template.title), "expected #{user.email}'s own templates table to NOT have an older version of an the org's template: '#{template.title}'"
- end
- end
-
- # Expect to see no templates for other orgs in the own templates table
- Template.where.not(id: templates.collect(&:id)).each do |template|
- assert_not el.to_s.include?(template.title), " expected #{user.email}'s own templates table to NOT have: '#{template.title}'"
- end
-
- # Expect the funder templates table to contain NO 'Edit/Publish menus
- assert_not el.to_s.include?('Customise'), "expected #{user.email}'s own templates table to NOT contain any of the Customization menu items in the funder templates table"
- end
- end
+ test "authorized user can transfer a template customization template#transfer_customization" do
+# TODO: This will not work because Rails is persisting these transactions to the DB at the same time, so their created_at
+# timestamps match even if we add a 'sleep' statement. The template.upgrade_customization? will fail because of this.
+# sign_in @org_admin
+# original = @funder_template.customize!(@organisation)
+# # Add a phase to the funder template and republish it
+# phase = init_phase(@funder_template, { title: 'testing transfer of customizations' })
+# phase.template.update!({ published: true, title: 'upgraded funder template' })
+# post transfer_customization_org_admin_template_path(original)
+# assert_response :redirect
+# assert_redirected_to edit_org_admin_template_url(Template.latest_customized_version(@funder_template.family_id, @organisation.id).first)
end
- def verify_funder_templates_table(user)
- if user.org.funder_only?
- assert_select "#funder-templates table tbody", 0, "expected a funder only Org to NOT see the customizable table"
- else
- assert_select "#funder-templates table tbody" do |el|
- # An Org Admin should see all of the funder/default templates (except ones that belong to their org)
- templates = Template.where("(org_id IN (?) OR is_default = ?) AND org_id != ?", Org.where(org_type: [2,3]).collect(&:id), true, user.org.id)
- if user.can_org_admin?
- templates.each do |template|
- # Expect to only see published public templates
- if template.publicly_visible? && template.published?
- assert el.to_s.include?(template.title), "expected #{user.email}'s customizable table to have the funder (or default) template: '#{template.title}'"
- else
- assert_not el.to_s.include?(template.title), "expected #{user.email}'s customizable table to NOT have the unpublished/non-public funder template: '#{template.title}' (from org: #{template.org.abbreviation})"
- end
- end
-
- # Expect to see only the current org's customizations
- Template.where.not(id: templates.collect(&:id)).each do |template|
- if template.customization_of.nil?
- assert_not el.to_s.include?(template.title), "expected #{user.email}'s customizable table to NOT have the template from a non-funder org: '#{template.title}'"
- else
- if template.org == user.org
- assert el.to_s.include?(template.title), "expected #{user.email}'s customizable table to have their own customization: '#{template.title}'"
- else
- assert_not el.to_s.include?(template.title), "expected #{user.email}'s customizable table to NOT have a customization from another organisation: '#{template.title}'"
- end
- end
- end
- end
- end
- end
+ test "unauthorized user cannot get template#template_options" do
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]=#{@funder.id}"
+ assert_unauthorized_redirect_to_root_path
end
- def verify_templates_table_scoping(path, selector, published, unpublished)
- get "#{path}?scope=published"
- assert_select "table tbody" do |el|
- published.each do |template|
- assert el.to_s.include?(template.title), "expected to see '#{template.title}' in #{selector} after clicking the 'published' predefined scope"
- end
- unpublished.each do |template|
- assert_not el.to_s.include?(template.title), "expected to NOT see '#{template.title}' in #{selector} after clicking the 'published' predefined scope"
- end
- end
-
- get "#{path}?scope=unpublished"
- assert_select "table tbody" do |el|
- published.each do |template|
- assert_not el.to_s.include?(template.title), "expected to NOT see '#{template.title}' in #{selector} after clicking the 'unpublished' predefined scope"
- end
- unpublished.each do |template|
- assert el.to_s.include?(template.title), "expected to see '#{template.title}' #{selector} after clicking the 'unpublished' predefined scope"
- end
- end
-
- get "#{path}?scope=all"
- assert_select "table tbody" do |el|
- published.each do |template|
- assert el.to_s.include?(template.title), "expected to see '#{template.title}' in #{selector} after clicking the 'all' predefined scope"
- end
- unpublished.each do |template|
- assert el.to_s.include?(template.title), "expected to see '#{template.title}' in #{selector} after clicking the 'all' predefined scope"
- end
- end
+ test "authorized user can get template#template_options" do
+ sign_in @researcher
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]=#{@funder.id}"
+ assert_response :success
+ json_body = JSON.parse(@response.body)
+ assert json_body["templates"].length > 0
end
end
diff --git a/test/functional/phases_controller_test.rb b/test/functional/phases_controller_test.rb
deleted file mode 100644
index a7571b0..0000000
--- a/test/functional/phases_controller_test.rb
+++ /dev/null
@@ -1,234 +0,0 @@
-require 'test_helper'
-
-class PhasesControllerTest < ActionDispatch::IntegrationTest
-
- include Devise::Test::IntegrationHelpers
-
- setup do
- scaffold_template
-
- # Get the first Org Admin
- scaffold_org_admin(@template.org)
-
- @plan = Plan.create!(template: @template, title: 'Test Plan', visibility: :privately_visible,
- roles: [Role.new(user: @user, creator: true)])
- end
-
-# TODO: The following methods SHOULD replace the old 'admin_' prefixed methods. The routes file already has
-# these defined. They are defined multiple times though and we need to clean this up! In particular
-# look at the unnamed routes after 'new_plan_phase' below. They are not named because they are duplicates.
-# We should just have:
-#
-# SHOULD BE:
-# --------------------------------------------------
-# phases GET /templates/:template_id/phases phases#index
-# POST /templates/:template_id/phases phases#create
-# phase GET /templates/:template_id/phase/:id phases#show
-# PATCH /templates/:template_id/phase/:id phases#update
-# PUT /templates/:template_id/phase/:id phases#update
-# DELETE /templates/:template_id/phase/:id phases#destroy
-# edit_phase GET /templates/:template_id/phase/:id/edit phases#edit
-# new_phase GET /templates/:template_id/phase/new phases#new
-#
-# CURRENT RESULTS OF `rake routes`
-# --------------------------------------------------
-# admin_show_phase GET /org/admin/templates/phases/:id/admin_show(.:format) phases#admin_show
-# admin_preview_phase GET /org/admin/templates/phases/:id/admin_preview(.:format) phases#admin_preview
-# admin_add_phase GET /org/admin/templates/phases/:id/admin_add(.:format) phases#admin_add
-# admin_update_phase PUT /org/admin/templates/phases/:id/admin_update(.:format) phases#admin_update
-# admin_create_phase POST /org/admin/templates/phases/:id/admin_create(.:format) phases#admin_create
-# admin_destroy_phase DELETE /org/admin/templates/phases/:id/admin_destroy(.:format) phases#admin_destroy
-#
-# edit_plan_phase GET /plans/:plan_id/phases/:id/edit(.:format) phases#edit
-# status_plan_phase GET /plans/:plan_id/phases/:id/status(.:format) phases#status
-# plan_phase POST /plans/:plan_id/phases/:id/update(.:format) phases#update
-# plan_phases GET /plans/:plan_id/phases(.:format) phases#index
-# POST /plans/:plan_id/phases(.:format) phases#create
-# new_plan_phase GET /plans/:plan_id/phases/new(.:format) phases#new
-# GET /plans/:plan_id/phases/:id/edit(.:format) phases#edit
-# GET /plans/:plan_id/phases/:id(.:format) phases#show
-# PATCH /plans/:plan_id/phases/:id(.:format) phases#update
-# PUT /plans/:plan_id/phases/:id(.:format) phases#update
-# DELETE /plans/:plan_id/phases/:id(.:format) phases#destroy
-
-
-
- # GET /plans/:plan_id/phases/:id/edit (edit_plan_phase_path)
- # ----------------------------------------------------------
- test "show the edit phase page" do
- # Should redirect user to the root path if they are not logged in!
- get edit_plan_phase_path(@plan, @template.phases.first)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- # TODO: Why does the policy check fail when @user is the creator and owner of @plan!?
- # Trying `@plan.assign_editor(@user)` doesn't work either!
- #get edit_plan_phase_path(@plan, @template.phases.first)
- #assert_response :success
-
- #assert assigns(:plan)
- #assert assigns(:phase)
- #assert assigns(:question_guidance)
- end
-
- # GET /plans/:plan_id/phases/:id/status (status_plan_phase_path)
- # ----------------------------------------------------------
- test "get the phase's status" do
- # Should redirect user to the root path if they are not logged in!
- get status_plan_phase_path(plan_id: @plan.id, id: @template.phases.first.id), format: :json
- assert_unauthorized_redirect_to_root_path
-
- @plan.assign_creator(@user)
- @plan.save!
- sign_in @user
-
- get status_plan_phase_path(plan_id: @plan.id, id: @template.phases.first.id), format: :json
- assert_response :success
- assert assigns(:plan)
- end
-
-# TODO: Why are we passing an :id here!? Its a new record but we seem to need the last template's id
- # GET /org/admin/templates/phases/:id/admin_show (admin_show_phase_path)
- # ----------------------------------------------------------
- test "show the phase" do
- # Should redirect user to the root path if they are not logged in!
- get admin_show_phase_path(@template.phases.first)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- get admin_show_phase_path(@template.phases.first)
- assert_response :success
-
- assert assigns(:phase)
- end
-
- # GET /org/admin/templates/phases/:id/admin_preview (admin_preview_phase_path)
- # ----------------------------------------------------------
- test "preview the phase" do
- # Should redirect user to the root path if they are not logged in!
- get admin_preview_phase_path(@template.phases.first)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- get admin_preview_phase_path(@template.phases.first)
- assert_response :success
-
- assert assigns(:template)
- assert assigns(:phase)
- end
-
- # GET /org/admin/templates/phases/:id/admin_add (admin_add_phase) Why do we have an id here!?
- # ----------------------------------------------------------
- test "show the new phase page" do
- # Should redirect user to the root path if they are not logged in!
- get admin_add_phase_path(@template.id)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- get admin_add_phase_path(@template.id)
- assert_response :success
-
- assert assigns(:template)
- assert assigns(:phase)
- end
-
-# TODO: Why are we passing an :id here!? Its a new record but we seem to need the last template's id
- # POST /org/admin/templates/phases/:id/admin_create (admin_create_phase_path)
- # ----------------------------------------------------------
- test "create a phase " do
- params = {template_id: @template.id, title: 'Phase: Tester 2', number: 2}
-
- @template.dirty = false
- @template.save!
-
- # Should redirect user to the root path if they are not logged in!
- post admin_create_phase_path(@template.phases.first), {phase: params}
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- post admin_create_phase_path(@template.phases.first), {phase: params}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('created')
- assert_response :redirect
- assert_redirected_to admin_show_phase_path(id: Phase.last.id, r: 'all-templates')
- assert assigns(:phase)
- assert_equal 'Phase: Tester 2', Phase.last.title, "expected the record to have been created!"
-
- # Make sure that the template's dirty flag got set
- assert @template.reload.dirty?, "expected the templates dirty flag to be true"
-
- # Invalid object
- post admin_create_phase_path(@template.phases.first), {phase: {template_id: @template.id}}
- assert flash[:alert].starts_with?(_('Could not create your'))
- assert_response :redirect
- assert assigns(:phase)
- assert assigns(:template)
- end
-
- # PUT /org/admin/templates/phases/:id/admin_update (admin_update_phase_path)
- # ----------------------------------------------------------
- test "update the phase" do
- params = {title: 'Phase - UPDATE'}
-
- @template.dirty = false
- @template.save!
-
- # Should redirect user to the root path if they are not logged in!
- put admin_update_phase_path(@template.phases.first), {phase: params}
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- # Valid save
- put admin_update_phase_path(@template.phases.first), {phase: params}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('saved')
- assert_response :redirect
- assert_redirected_to admin_show_phase_url(@template.phases.first, r: 'all-templates')
- assert assigns(:phase)
- assert_equal 'Phase - UPDATE', @template.phases.first.title, "expected the record to have been updated"
-
- # Make sure that the template's dirty flag got set
- assert @template.reload.dirty?, "expected the templates dirty flag to be true"
-
- # Invalid save
- put admin_update_phase_path(@template.phases.first), {phase: {title: nil}}
- assert flash[:alert].starts_with?(_('Could not update your'))
- assert_response :redirect
- assert assigns(:phase)
- assert assigns(:template)
- assert assigns(:sections)
- assert assigns(:edit)
- end
-
- # DELETE /org/admin/templates/phases/:id/admin_destroy (admin_destroy_phase_path)
- # ----------------------------------------------------------
- test "delete the phase" do
- id = @template.phases.first.id
-
- @template.dirty = false
- @template.save!
-
- # Should redirect user to the root path if they are not logged in!
- # TODO: Why are we not just using id: here? shouldn't need to specify the key
- delete admin_destroy_phase_path(id: @template.phases.first.id, phase_id: id)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- delete admin_destroy_phase_path(id: @template.phases.first.id, phase_id: id)
- assert_response :redirect
- assert_redirected_to edit_org_admin_template_path(@template, r: 'all-templates')
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('deleted')
- assert_raise ActiveRecord::RecordNotFound do
- Phase.find(id).nil?
- end
-
- # Make sure that the template's dirty flag got set
- assert @template.reload.dirty?, "expected the templates dirty flag to be true"
- end
-
-end
diff --git a/test/functional/public_pages_controller_test.rb b/test/functional/public_pages_controller_test.rb
index 6dd41a3..9531032 100644
--- a/test/functional/public_pages_controller_test.rb
+++ b/test/functional/public_pages_controller_test.rb
@@ -17,9 +17,9 @@
roles: [Role.new(user: User.last, creator: true)])
end
- @inst_tmplt = Template.create!(title: 'Inst template', org: Org.institution.first, migrated: false, published: true)
- @dflt_tmplt = Template.create!(title: 'Dflt template', org: Org.managing_orgs.first, migrated: false, published: true)
- @fndr_tmplt = Template.create!(title: 'Fndr template', org: Org.funder.first, migrated: false, published: true)
+ @inst_tmplt = Template.create!(title: 'Inst template', org: Org.institution.first, archived: false, published: true)
+ @dflt_tmplt = Template.create!(title: 'Dflt template', org: Org.managing_orgs.first, archived: false, published: true)
+ @fndr_tmplt = Template.create!(title: 'Fndr template', org: Org.funder.first, archived: false, published: true)
[@inst_tmplt, @dflt_tmplt, @fndr_tmplt].each do |t|
t.published = true
@@ -77,31 +77,31 @@
get public_templates_path
assert_response :success
assert assigns(:templates)
- assert @response.body.include?(template_export_path(@fndr_tmplt.dmptemplate_id)), "expected to see the funder template download link when NOT logged in"
- assert @response.body.include?(template_export_path(@dflt_tmplt.dmptemplate_id)), "expected to see the default template download link when NOT logged in"
- assert_not @response.body.include?(template_export_path(@inst_tmplt.dmptemplate_id)), "expected to NOT see the institution template download link when NOT logged in"
+ assert @response.body.include?(template_export_path(@fndr_tmplt.family_id)), "expected to see the funder template download link when NOT logged in"
+ assert @response.body.include?(template_export_path(@dflt_tmplt.family_id)), "expected to see the default template download link when NOT logged in"
+ assert_not @response.body.include?(template_export_path(@inst_tmplt.family_id)), "expected to NOT see the institution template download link when NOT logged in"
# Verify the same results are received when the user is logged in
sign_in @user
get public_templates_path
assert_response :success
assert assigns(:templates)
- assert @response.body.include?(template_export_path(@fndr_tmplt.dmptemplate_id)), "expected to see the funder template download link when NOT logged in"
- assert @response.body.include?(template_export_path(@dflt_tmplt.dmptemplate_id)), "expected to see the default template download link when NOT logged in"
- assert_not @response.body.include?(template_export_path(@inst_tmplt.dmptemplate_id)), "expected to NOT see the institution template download link when NOT logged in"
+ assert @response.body.include?(template_export_path(@fndr_tmplt.family_id)), "expected to see the funder template download link when NOT logged in"
+ assert @response.body.include?(template_export_path(@dflt_tmplt.family_id)), "expected to see the default template download link when NOT logged in"
+ assert_not @response.body.include?(template_export_path(@inst_tmplt.family_id)), "expected to NOT see the institution template download link when NOT logged in"
end
# TODO: Need to install the wkhtmltopdf library on Travis for this to work!
- # GET /template_export/:dmptemplate_id (template_export_path)
+ # GET /template_export/:family_id (template_export_path)
# ----------------------------------------------------------
test 'export a public template' do
-# get template_export_path(@fndr_tmplt.dmptemplate_id, format: :pdf)
+# get template_export_path(@fndr_tmplt.family_id, format: :pdf)
# assert_response :success
-# get template_export_path(@dflt_tmplt.dmptemplate_id, format: :pdf)
+# get template_export_path(@dflt_tmplt.family_id, format: :pdf)
# assert_response :success
-# get template_export_path(@inst_tmplt.dmptemplate_id, format: :pdf)
+# get template_export_path(@inst_tmplt.family_id, format: :pdf)
# assert_response :redirect
# assert_equal "You need to sign in or sign up before continuing.", flash[:alert]
# assert_redirected_to root_path
diff --git a/test/functional/questions_controller_test.rb b/test/functional/questions_controller_test.rb
deleted file mode 100644
index bbe42f4..0000000
--- a/test/functional/questions_controller_test.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-require 'test_helper'
-
-class QuestionsControllerTest < ActionDispatch::IntegrationTest
-
- include Devise::Test::IntegrationHelpers
-
- setup do
- scaffold_template
- @section = @template.phases.first.sections.first
-
- # Get the first Org Admin
- scaffold_org_admin(@template.org)
-
- @question_format = QuestionFormat.where(option_based: false).first
- end
-
-# TODO: The following methods SHOULD replace the old 'admin_' prefixed methods. The routes file already has
-# these defined. They are defined multiple times though and we need to clean this up! In particular
-# look at the unnamed routes after 'new_plan_phase' below. They are not named because they are duplicates.
-# We should just have:
-#
-# SHOULD BE:
-# --------------------------------------------------
-# questions GET /templates/:template_id/phases/:phase_id/sections/:section_id/questions sections#index
-# POST /templates/:template_id/phases/:phase_id/sections/:section_id/questions sections#create
-# question GET /templates/:template_id/phases/:phase_id/section/:section_id/questions/:id sections#show
-# PATCH /templates/:template_id/phases/:phase_id/section/:section_id/questions/:id sections#update
-# PUT /templates/:template_id/phases/:phase_id/section/:section_id/questions/:id sections#update
-# DELETE /templates/:template_id/phases/:phase_id/section/:section_id/questions/:id sections#destroy
-#
-# CURRENT RESULTS OF `rake routes`
-# --------------------------------------------------
-# admin_create_question POST /org/admin/templates/questions/:id/admin_create questions#admin_create
-# admin_update_question PUT /org/admin/templates/questions/:id/admin_update questions#admin_update
-# admin_destroy_question DELETE /org/admin/templates/questions/:id/admin_destroy questions#admin_destroy
-
-
- # POST /org/admin/templates/questions/:id/admin_create (admin_create_question_path)
- # ----------------------------------------------------------
- test "create a new question" do
- params = {section_id: @section.id, text: 'Test Question', number: 9, question_format_id: @question_format.id}
-
- @section.phase.template.dirty = false
- @section.phase.template.save!
-
- # Should redirect user to the root path if they are not logged in!
- post admin_create_question_path(@section), {question: params}
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
- @new_question = Question.new
- @new_question.number = @section.questions.count + 1
- example_answer = @new_question.annotations.build
- example_answer.type = :example_answer
- example_answer.save
- post admin_create_question_path(@section), {question: params}
- assert_response :redirect
- assert assigns(:question)
- assert_redirected_to admin_show_phase_url(id: @section.phase.id, section_id: @section.id, question_id: Question.last.id, r: 'all-templates')
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('created')
- assert_equal 'Test Question', Question.last.text, "expected the record to have been created!"
-
- # Make sure that the template's dirty flag got set
- assert @section.phase.template.reload.dirty?, "expected the templates dirty flag to be true"
-
- # Invalid object
- post admin_create_question_path(@section), {question: {section_id: @section.id, text: nil, question_format_id: @question_format.id}}
- assert flash[:alert].starts_with?(_('Could not create your'))
- assert_response :redirect
- assert assigns(:question)
- assert assigns(:section)
- assert assigns(:phase)
- assert assigns(:edit)
- assert assigns(:open)
- assert assigns(:sections)
- assert assigns(:section_id)
- end
-
- # PUT /org/admin/templates/questions/:id/admin_update (admin_update_question_path)
- # ----------------------------------------------------------
- test "update the question" do
- params = {text: 'Question - UPDATE'}
-
- @section.phase.template.dirty = false
- @section.phase.template.save!
-
- # Should redirect user to the root path if they are not logged in!
- put admin_update_question_path(@section.questions.first), {question: params}
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- # Valid save
- put admin_update_question_path(@section.questions.first), {question: params}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('saved')
- assert_response :redirect
- assert_redirected_to admin_show_phase_url(id: @section.phase.id, section_id: @section.id, question_id: @section.questions.first.id, r: 'all-templates')
- assert assigns(:phase)
- assert assigns(:section)
- assert assigns(:question)
- assert_equal 'Question - UPDATE', @section.questions.first.text, "expected the record to have been updated"
-
- # Make sure that the template's dirty flag got set
- assert @section.phase.template.reload.dirty?, "expected the templates dirty flag to be true"
-
- # Invalid save
- put admin_update_question_path(@section.questions.first), {question: {text: nil}}
- assert flash[:alert].starts_with?(_('Could not update your'))
- assert_response :redirect
- assert assigns(:question)
- assert assigns(:section)
- assert assigns(:phase)
- assert assigns(:edit)
- assert assigns(:open)
- assert assigns(:sections)
- assert assigns(:section_id)
- assert assigns(:question_id)
- end
-
- # DELETE /org/admin/templates/questions/:id/admin_destroy (admin_destroy_question_path)
- # ----------------------------------------------------------
- test "delete the question" do
- id = @section.questions.first.id
-
- @section.phase.template.dirty = false
- @section.phase.template.save!
-
- # Should redirect user to the root path if they are not logged in!
- delete admin_destroy_question_path(id: @section.id, question_id: id)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- delete admin_destroy_question_path(id: @section.id, question_id: id)
- assert_response :redirect
- assert assigns(:phase)
- assert assigns(:section)
- assert assigns(:question)
- assert_redirected_to admin_show_phase_url(id: @section.phase.id, section_id: @section.id, r: 'all-templates')
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('deleted')
- assert_raise ActiveRecord::RecordNotFound do
- Question.find(id).nil?
- end
-
- # Make sure that the template's dirty flag got set
- assert @section.phase.template.reload.dirty?, "expected the templates dirty flag to be true"
- end
-
-end
\ No newline at end of file
diff --git a/test/functional/sections_controller_test.rb b/test/functional/sections_controller_test.rb
deleted file mode 100644
index 5ee66de..0000000
--- a/test/functional/sections_controller_test.rb
+++ /dev/null
@@ -1,135 +0,0 @@
-require 'test_helper'
-
-class SectionsControllerTest < ActionDispatch::IntegrationTest
-
- include Devise::Test::IntegrationHelpers
-
- setup do
- scaffold_template
- @phase = @template.phases.first
-
- # Get the first Org Admin
- scaffold_org_admin(@template.org)
- end
-
-# TODO: The following methods SHOULD replace the old 'admin_' prefixed methods. The routes file already has
-# these defined. They are defined multiple times though and we need to clean this up! In particular
-# look at the unnamed routes after 'new_plan_phase' below. They are not named because they are duplicates.
-# We should just have:
-#
-# SHOULD BE:
-# --------------------------------------------------
-# sections GET /templates/:template_id/phases/:phase_id/sections sections#index
-# POST /templates/:template_id/phases/:phase_id/sections sections#create
-# section GET /templates/:template_id/phases/:phase_id/section/:id sections#show
-# PATCH /templates/:template_id/phases/:phase_id/section/:id sections#update
-# PUT /templates/:template_id/phases/:phase_id/section/:id sections#update
-# DELETE /templates/:template_id/phases/:phase_id/section/:id sections#destroy
-#
-# CURRENT RESULTS OF `rake routes`
-# --------------------------------------------------
-# admin_create_section POST /org/admin/templates/sections/:id/admin_create sections#admin_create
-# admin_update_section PUT /org/admin/templates/sections/:id/admin_update sections#admin_update
-# admin_destroy_section DELETE /org/admin/templates/sections/:id/admin_destroy sections#admin_destroy
-
-
-
- # POST /org/admin/templates/sections/:id/admin_create (admin_create_section_path)
- # ----------------------------------------------------------
- test "create a new section" do
- params = {phase_id: @phase.id, title: 'Section Tester', number: 99}
-
- @phase.template.dirty = false
- @phase.template.save!
-
- # Should redirect user to the root path if they are not logged in!
- post admin_create_section_path(@phase), {section: params}
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- post admin_create_section_path(@phase), {section: params}
- assert_response :redirect
- assert_redirected_to admin_show_phase_url(id: @phase.id, section_id: Section.last.id, r: 'all-templates')
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('created')
- assert_equal 'Section Tester', Section.last.title, "expected the record to have been created!"
-
- # Make sure that the template's dirty flag got set
- assert @phase.template.reload.dirty?, "expected the templates dirty flag to be true"
-
- # Invalid object
- post admin_create_section_path(@phase), {section: {phase_id: @phase.id, title: nil}}
- assert flash[:alert].starts_with?(_('Could not create your'))
- assert_response :redirect
- assert assigns(:section)
- assert assigns(:phase)
- assert assigns(:edit)
- assert assigns(:open)
- assert assigns(:sections)
- end
-
- # PUT /org/admin/templates/sections/:id/admin_update (admin_update_section_path)
- # ----------------------------------------------------------
- test "update the section" do
- params = {title: 'Phase - UPDATE'}
-
- @phase.template.dirty = false
- @phase.template.save!
-
- # Should redirect user to the root path if they are not logged in!
- put admin_update_section_path(@phase.sections.first), {section: params}
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- # Valid save
- put admin_update_section_path(@phase.sections.first), {section: params}
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('saved')
- assert_response :redirect
- assert_redirected_to admin_show_phase_url(id: @phase.id, section_id: @phase.sections.first.id, r: 'all-templates')
- assert_equal 'Phase - UPDATE', @phase.sections.first.title, "expected the record to have been updated"
-
- # Make sure that the template's dirty flag got set
- assert @phase.template.reload.dirty?, "expected the templates dirty flag to be true"
-
- # Invalid save
- put admin_update_section_path(@phase.sections.first), {section: {title: nil}}
- assert flash[:alert].starts_with?(_('Could not update your'))
- assert_response :redirect
- assert assigns(:section)
- assert assigns(:phase)
- assert assigns(:edit)
- assert assigns(:open)
- assert assigns(:sections)
- assert assigns(:section_id)
- end
-
- # DELETE /org/admin/templates/sections/:id/admin_destroy (admin_destroy_section_path)
- # ----------------------------------------------------------
- test "delete the section" do
- id = @phase.sections.first.id
-
- @phase.template.dirty = false
- @phase.template.save!
-
- # Should redirect user to the root path if they are not logged in!
- delete admin_destroy_section_path(id: @phase.id, section_id: id)
- assert_unauthorized_redirect_to_root_path
-
- sign_in @user
-
- delete admin_destroy_section_path(id: @phase.id, section_id: id)
- assert_response :redirect
- assert assigns(:section)
- assert assigns(:phase)
- assert_redirected_to admin_show_phase_url(id: @phase.id, r: 'all-templates')
- assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('deleted')
- assert_raise ActiveRecord::RecordNotFound do
- Section.find(id).nil?
- end
-
- # Make sure that the template's dirty flag got set
- assert @phase.template.reload.dirty?, "expected the templates dirty flag to be true"
- end
-
-end
\ No newline at end of file
diff --git a/test/integration/download_plan_path_test.rb b/test/integration/download_plan_path_test.rb
new file mode 100644
index 0000000..cb6521e
--- /dev/null
+++ b/test/integration/download_plan_path_test.rb
@@ -0,0 +1,67 @@
+require 'test_helper'
+
+class DownloadPlanPathTest < ActionDispatch::IntegrationTest
+ include Devise::Test::IntegrationHelpers
+
+ setup do
+ @org = init_organisation
+ template = init_template(@org)
+ phase = init_phase(template)
+ section = init_section(phase)
+ init_question(section)
+ @plan = init_plan(template)
+ @user = User.create(user_seed.merge({ org: @org }))
+ end
+
+ def assert_download_link_present(plan, user)
+ sign_in user
+ get(download_plan_path(plan))
+ links = css_select("a[href=\"#{download_plan_path(plan)}\"]")
+ refute_empty(links)
+ assert_equal(links[0].text, _('Download'))
+ end
+
+ def refute_download_link_present(plan, user)
+ sign_in user
+ get(download_plan_path(plan))
+ links = css_select("a[href=\"#{download_plan_path(plan)}\"]")
+ assert_empty(links)
+ end
+
+ test 'download tab is visible when user has role creator, administrator, commenter, editor on the plan' do
+ assign_roles = [
+ lambda{ |plan, user| plan.assign_creator(user.id) },
+ lambda{ |plan, user| plan.assign_administrator(user.id) },
+ lambda{ |plan, user| plan.assign_editor(user.id) },
+ lambda{ |plan, user| plan.assign_reader(user.id) }
+ ]
+ assign_roles.each do |assign_role|
+ assign_role.call(@plan, @user)
+ assert_download_link_present(@plan, @user)
+ end
+ end
+
+ test 'download tab is visible when user is super_admin' do
+ @user.perms = Perm.all
+ assert_download_link_present(@plan, @user)
+ end
+
+ test 'download tab is visible when user is an org_admin from the same org that any owner\'s org' do
+ @plan.assign_creator(@user.id)
+ user2 = User.create(user_seed.merge({ org: @org, email: 'foo@bar.com' }))
+ user2.perms << Perm.grant_permissions
+ assert_download_link_present(@plan, user2)
+ end
+
+ test 'download tab is NOT visible when user is an org_admin from an org different from every owner\'s org' do
+ @plan.assign_creator(@user.id)
+ user2 = User.create(user_seed.merge({ org: init_funder_organisation, email: 'foo@bar.com' }))
+ user2.perms << Perm.grant_permissions
+ refute_download_link_present(@plan, user2)
+ end
+
+ test 'download tab is NOT visible when user is not super_admin nor org_admin nor has commenter role' do
+ @plan.roles << Role.new(user_id: @user.id, reviewer: true)
+ refute_download_link_present(@plan, @user)
+ end
+end
\ No newline at end of file
diff --git a/test/integration/template_selection_test.rb b/test/integration/template_selection_test.rb
index 7f3bfb8..af69cd4 100644
--- a/test/integration/template_selection_test.rb
+++ b/test/integration/template_selection_test.rb
@@ -4,167 +4,164 @@
include Devise::Test::IntegrationHelpers
setup do
- scaffold_template
- @template = Template.default
-
- @researcher = User.last
- scaffold_org_admin(@template.org)
-
- @funder = Org.find_by(org_type: 2)
- @funder_template = @funder.templates.where(published: true).first #Template.create(title: 'Funder template', org: @funder, migrated: false)
- # Template can't be published on creation so do it afterward
- @funder_template.published = true
- @funder_template.visibility = Template.visibilities[:publicly_visible]
- @funder_template.save
-
- @org = @researcher.org
- @org_template = Template.create(title: 'Org template', org: @org, migrated: false)
- # Template can't be published on creation so do it afterward
- @org_template.published = true
- @org_template.visibility = Template.visibilities[:organisationally_visible]
- @org_template.save
+ # Need to clear the tables until we get seed.rb out of test_helper.rb
+ Template.delete_all
+
+ @funder = init_funder
+ @institution = init_institution
+ @organisation = init_organisation
+ @funder2 = init_funder({ name: 'Funder 2', abbreviation: 'F2' })
+
+ @researcher = init_researcher(@institution)
+ @org_admin = init_org_admin(@institution)
+
+ @funder_published_public_template = init_template(@funder, {
+ title: 'Test Funder public Template',
+ published: true
+ })
+ @funder_published_private_template = init_template(@funder, {
+ title: 'Test Funder private Template',
+ published: true
+ })
+ # funder templates are public by default on creation so set it to organisationally_visible afterward
+ @funder_published_private_template.update!({ visibility: Template.visibilities[:organisationally_visible] })
+ @funder_unpublished_template = init_template(@funder, {
+ title: 'Test Funder unpublished Template',
+ published: false
+ })
+ @funder2_published_public_template = init_template(@funder2, {
+ title: 'Test Funder 2 Template',
+ published: true
+ })
+ @org_published_private_template = init_template(@institution, {
+ title: 'Test Org Template',
+ published: true
+ })
+ @default_published_private_template = init_template(@organisation, {
+ title: 'Default Template',
+ published: true,
+ is_default: true
+ })
+ end
+
+ # ----------------------------------------------------------
+ test 'new plan gets published versions of templates not the latest version' do
+ version = @org_published_private_template.generate_version!
+ sign_in @researcher
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}"
+ json = JSON.parse(@response.body)
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal @org_published_private_template.id, json['templates'][0]['id'], 'expected the published version of the template'
end
# ----------------------------------------------------------
- test 'plan gets publish versions of templates' do
- original_id = @template.id
- template = version_template(@template)
-
+ test 'new plan gets default template when no funder or research org is specified' do
sign_in @researcher
-
- get "#{org_admin_template_options_path}?plan[org_id]=#{@template.org_id}"
- assert_response :success
+ get "#{org_admin_template_options_path}?plan[org_id]=&plan[funder_id]="
json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal original_id, json['templates'][0]['id']
- assert_equal original_id, Template.live(@template.dmptemplate_id).id
-
- # Version the template again
- original_id = template.id
- template = version_template(template)
-
- # Make sure the published version is used
- get "#{org_admin_template_options_path}?plan[org_id]=#{@template.org_id}"
- assert_response :success
- json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal original_id, json['templates'][0]['id']
- assert_equal original_id, Template.live(@template.dmptemplate_id).id
-
- # Update the template and make sure the published version stayed the same
- sign_in @user
- put org_admin_template_path(template), {template: {title: "Blah blah blah"}}
-
- sign_in @researcher
-
- get "#{org_admin_template_options_path}?plan[org_id]=#{@template.org_id}"
- assert_response :success
- json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal original_id, json['templates'][0]['id']
- assert_equal original_id, Template.live(@template.dmptemplate_id).id
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal @default_published_private_template.id, json['templates'][0]['id'], 'expected the default template'
end
# ----------------------------------------------------------
- test 'plan gets generic template when no funder or org' do
- temp = Template.find_by(published: true, is_default: true)
- if temp.blank?
- @template.is_default = true
- @template.save!
- temp = @template
- end
-
+ test 'new plan gets org template when a research org is specified but no funder is specified' do
sign_in @researcher
- get "#{org_admin_template_options_path}?plan[org_id]="
- assert_response :success
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]="
json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal @template.id, json['templates'][0]['id']
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal @org_published_private_template.id, json['templates'][0]['id'], 'expected 1 org template'
end
# ----------------------------------------------------------
- test 'plan gets org template when no funder' do
+ test 'new plan gets multiple org templates when a research org is specified but no funder is specified' do
+ template2 = init_template(@institution, {
+ title: 'Test Org Template 2',
+ published: true,
+ is_default: false,
+ })
+ template2.update!(visibility: Template.visibilities[:organisationally_visible])
sign_in @researcher
- get "#{org_admin_template_options_path}?plan[org_id]=#{@org.id}&plan[funder_id]="
-
- assert_response :success
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]="
json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal @org_template.id, json['templates'][0]['id']
+ assert_equal 2, json['templates'].size, "expected 2 templates but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ json['templates'].each{ |h| assert [@org_published_private_template.id, template2.id].include?(h['id']), 'expected the json to include only the 2 org templates' }
end
# ----------------------------------------------------------
- test 'plan gets funder template when no org' do
+ test 'new plan gets public funder template when no research org is specified' do
sign_in @researcher
get "#{org_admin_template_options_path}?plan[org_id]=&plan[funder_id]=#{@funder.id}"
-
- assert_response :success
json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal @funder_template.id, json['templates'][0]['id']
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal @funder_published_public_template.id, json['templates'][0]['id'], 'expected the funder template'
end
# ----------------------------------------------------------
- test 'plan gets funder template when org has no customization' do
+ test 'new plan gets multiple public funder templates when no research org is specified' do
+ template2 = init_template(@funder, {
+ title: 'Test Funder Template 2',
+ published: true,
+ is_default: false,
+ visibility: Template.visibilities[:publicly_visible]
+ })
sign_in @researcher
-
- get "#{org_admin_template_options_path}?plan[org_id]=#{@org.id}&plan[funder_id]=#{@funder.id}"
- assert_response :success
+ get "#{org_admin_template_options_path}?plan[org_id]=&plan[funder_id]=#{@funder.id}"
json = JSON.parse(@response.body)
-
- assert_equal 1, json['templates'].size
- assert_equal @funder_template.id, json['templates'][0]['id']
+ assert_equal 2, json['templates'].size, "expected 2 templates but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ json['templates'].each{ |h| assert [@funder_published_public_template.id, template2.id].include?(h['id']), 'expected the json to include only the 2 funder templates' }
+ end
+
+ # ----------------------------------------------------------
+ test 'new plan gets both the public funder template when both research org and funder are specified' do
+ sign_in @researcher
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]=#{@funder.id}"
+ json = JSON.parse(@response.body)
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal @funder_published_public_template.id, json['templates'][0]['id'], 'expected the funder template'
end
# ----------------------------------------------------------
- test 'plan gets customized version of funder template' do
- customization = Template.create(title: 'Customization', org: @org)
- # Template can't be published on creation so do it afterward
- customization.published = true
- customization.visibility = Template.visibilities[:organisationally_visible]
- customization.customization_of = @funder_template.dmptemplate_id
- customization.save
-
+ test 'new plan gets the customized version of funder template when the specified research org has customized it' do
+ customization = @funder_published_public_template.customize!(@institution)
+ customization.update!(title: 'Customization test', published: true)
sign_in @researcher
-
- get "#{org_admin_template_options_path}?plan[org_id]=#{@org.id}&plan[funder_id]=#{@funder.id}"
- assert_response :success
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]=#{@funder.id}"
json = JSON.parse(@response.body)
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal customization.id, json['templates'][0]['id'], 'expected the customization of the funder template'
+ end
- assert_equal 1, json['templates'].size
- assert_equal customization.id, json['templates'][0]['id']
- end
-
# ----------------------------------------------------------
- test 'list of templates is returned when the funder has multiples' do
- funder_template2 = Template.create(title: 'Funder template 2', org: @funder)
- # Template can't be published on creation so do it afterward
- funder_template2.published = true
- funder_template2.visibility = Template.visibilities[:publicly_visible]
- funder_template2.save
-
+ test 'plan gets choice between multiple funder templates when both research org and funder are specified and both the org and funder have multiple templates' do
+ funder_template2 = init_template(@funder, { title: 'Funder template 2', published: true, visibility: Template.visibilities[:publicly_visible] })
+ org_template2 = init_template(@institution, { title: 'Org template 2', published: true, visibility: Template.visibilities[:organisationally_visible] })
sign_in @researcher
-
- get "#{org_admin_template_options_path}?plan[org_id]=#{@org.id}&plan[funder_id]=#{@funder.id}"
- assert_response :success
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]=#{@funder.id}"
json = JSON.parse(@response.body)
-
- assert_equal 2, json['templates'].size
- assert_equal @funder_template.id, json['templates'][0]['id']
- assert_equal funder_template2.id, json['templates'][1]['id']
+ assert_equal 2, json['templates'].size, "expected 2 templates but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ json['templates'].each{ |h| assert [@funder.id, funder_template2.id].include?(h['id']), 'expected the json to include only the funder templates' }
end
-
-
- private
- # ----------------------------------------------------------
- def version_template(template)
- get publish_org_admin_template_path(template)
- Template.current(template.dmptemplate_id)
- end
+
+ # ----------------------------------------------------------
+ test 'new plan gets default template when combination of specified funder and research org have no templates' do
+ @org_published_private_template.destroy!
+ @funder_published_public_template.destroy!
+ sign_in @researcher
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]=#{@funder.id}"
+ json = JSON.parse(@response.body)
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal @default_published_private_template.id, json['templates'][0]['id'], 'expected the default template'
+ end
+
+ # ----------------------------------------------------------
+ test 'new plan gets customized version of the default template if the research org has no template of its own but has customized the default template' do
+ @org_published_private_template.destroy
+ customization = @default_published_private_template.customize!(@institution)
+ customization.update!(title: 'Default template customization test', published: true)
+ sign_in @researcher
+ get "#{org_admin_template_options_path}?plan[org_id]=#{@institution.id}&plan[funder_id]="
+ json = JSON.parse(@response.body)
+ assert_equal 1, json['templates'].size, "expected 1 template but got: #{json['templates'].collect{|h| h['title'] }.join(', ')}"
+ assert_equal customization.id, json['templates'][0]['id'], "expected the customized version of the default template"
+ end
end
diff --git a/test/integration/template_versioning_test.rb b/test/integration/template_versioning_test.rb
deleted file mode 100644
index 6de1c8a..0000000
--- a/test/integration/template_versioning_test.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require 'test_helper'
-
-class TemplateVersioningTest < ActionDispatch::IntegrationTest
- include Devise::Test::IntegrationHelpers
-
- setup do
- scaffold_template
- scaffold_org_admin(@template.org)
-
- sign_in @user
-
- # Make sure the template starts out as unpublished. The controller will not allow changes once its published
- @template.published = false
- @template.save!
-
- @initial_id = @template.id
- @initial_version = @template.version
- @initial_title = @template.title
- @dmptemplate_id = @template.dmptemplate_id
- end
-
- # ----------------------------------------------------------
- test 'template gets versioned when its phases are modified and it is already published' do
- @template.dirty = false
- @template.save!
-
- put admin_update_phase_path @template.phases.first, {phase: {title: 'UPDATED'}}
- @template.reload
- assert @template.dirty
- end
-
- # ----------------------------------------------------------
- test 'template gets versioned when its sections are modified and it is already published' do
- @template.dirty = false
- @template.save!
-
- put admin_update_section_path @template.phases.first.sections.first, {section: {title: 'UPDATED'}}
- @template.reload
- assert @template.dirty
- end
-
- # ----------------------------------------------------------
- test 'template gets versioned when its questions are modified and it is already published' do
- @template.dirty = false
- @template.save!
-
- put admin_update_question_path @template.phases.first.sections.first.questions.first, {question: {text: 'UPDATED'}}
- @template.reload
- assert @template.dirty
- end
-
- # ----------------------------------------------------------
- test 'template does NOT get versioned if its unpublished' do
- # Change the title after its been published
- put org_admin_template_path(@template), {template: {title: "Blah blah blah"}}
- @template = Template.current(@dmptemplate_id)
-
- assert_equal @initial_version, @template.version, "expected the version to have stayed the same"
- assert_equal @initial_id, @template.id, "expected the id to been the same"
- assert_equal @dmptemplate_id, @template.dmptemplate_id, "expected the dmptemplate_id to match"
- assert_equal false, @template.published?, "expected the version to have remained unpublished"
- end
-
- # ----------------------------------------------------------
- test 'publishing a plan unpublishes the old published plan' do
- get publish_org_admin_template_path(@template)
- assert_not Template.live(@dmptemplate_id).nil?
- assert_equal 1, Template.where(org: @user.org, dmptemplate_id: @dmptemplate_id, published: true).count
- end
-
- # ----------------------------------------------------------
- test 'unpublishing a plan makes all historical versions unpublished' do
- get publish_org_admin_template_path(@template)
- get unpublish_org_admin_template_path(@template)
- assert Template.live(@dmptemplate_id).nil?
- end
-end
diff --git a/test/mailers/previews/user_mailer_preview.rb b/test/mailers/previews/user_mailer_preview.rb
index ab7cd42..d3949b2 100644
--- a/test/mailers/previews/user_mailer_preview.rb
+++ b/test/mailers/previews/user_mailer_preview.rb
@@ -8,7 +8,7 @@
password: "password123", password_confirmation: "password123", org: @org,
accept_terms: true, confirmed_at: Time.zone.now)
@template = Template.new(title: 'Test template', description: 'My test template', org: @org,
- migrated: false, dmptemplate_id: "9999999")
+ archived: false, family_id: "9999999")
@plan = Plan.new(template: @template, title: 'Test Plan', grant_number: 'Grant-123',
principal_investigator: 'Researcher', principal_investigator_identifier: 'researcher-1234',
description: "this is my plan's informative description",
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 255410e..0c0f4c7 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -27,6 +27,303 @@
# Sometimes TravisCI fails when accessing the LANGUAGES array, so reload it here if necessary
LANGUAGES = Language.all if LANGUAGES.empty?
+ # Default attributes for model initialization
+ def org_seed
+ { name: 'Test Institution',
+ abbreviation: 'TST',
+ org_type: Org.org_type_values_for(:institution).min,
+ target_url: 'http://test-funder.org',
+ language: LANGUAGES.first,
+ contact_email: 'help.desk@test-funder.org',
+ contact_name: 'Help Desk',
+ links: {"org":[{"link":"http://dmproadmap.org","text":"DMPRoadmap"}]},
+ }
+ end
+ def user_seed
+ {
+ email: 'test-user@testing-roadmap.org',
+ firstname: 'Test',
+ surname: 'User',
+ language: Language.find_by(abbreviation: FastGettext.locale),
+ password: "password123",
+ password_confirmation: "password123",
+ accept_terms: true,
+ confirmed_at: Time.zone.now,
+ }
+ end
+
+ def template_seed
+ {
+ title: 'Test template',
+ description: 'this is a test template',
+ org: Org.first,
+ }
+ end
+ def phase_seed
+ {
+ title: 'Test phase',
+ description: 'This is a phase used for testing',
+ number: 1,
+ modifiable: true,
+ }
+ end
+ def section_seed
+ {
+ title: 'Test section',
+ description: 'This is a section used for testing',
+ number: 1,
+ modifiable: true,
+ }
+ end
+ def question_format_seed
+ {
+ title: 'Text area',
+ option_based: false,
+ formattype: QuestionFormat.formattypes[:text_area]
+ }
+ end
+ def question_seed
+ {
+ text: 'how is our test coverage?',
+ default_value: 'Not as good as it could be.',
+ number: 1,
+ option_comment_display: true,
+ modifiable: true,
+ }
+ end
+ def annotation_seed
+ {
+ text: 'This is some test guidance for a customization',
+ type: Annotation.types[:guidance]
+ }
+ end
+ def question_option_seed
+ {
+ text: 'Option A',
+ number: 1,
+ is_default: true,
+ }
+ end
+ def plan_seed
+ {
+ title: 'Test plan',
+ funder_name: 'Organisation with a lot of funds',
+ grant_number: 'Grant123',
+ identifier: '123456789',
+ description: 'This is the project abstract.',
+ visibility: Plan.visibilities[:privately_visible],
+ principal_investigator: 'Jane Doe',
+ principal_investigator_identifier: 'ORCID123',
+ principal_investigator_email: 'jane.doe@pi.roadmap.org',
+ principal_investigator_phone: '1234',
+ data_contact: 'John Doe',
+ data_contact_email: 'john.doe@pi.roadmap.org',
+ data_contact_phone: '5678',
+ }
+ end
+ def theme_seed
+ {
+ title: 'Test theme',
+ description: 'This theme is used for testing',
+ locale: Language.find_by(abbreviation: FastGettext.locale),
+ }
+ end
+ def guidance_group_seed
+ {
+ name: 'Test guidance group',
+ optional_subset: false,
+ published: true,
+ }
+ end
+ def guidance_seed
+ {
+ text: 'This is thematic test guidance.',
+ published: true,
+ }
+ end
+
+ def validate_and_create_obj(obj)
+ obj.validate
+ if obj.errors.present?
+ # Unable to save the object, so output an error rather than burying it
+ puts "Unable to save #{obj.class.name} because: #{obj.errors.collect{ |e,m| "#{e}: #{m}" }.join(', ')}"
+ else
+ obj.save!
+ end
+ assert obj.valid?
+ obj
+ end
+
+ # Org initializers
+ def init_institution(**props)
+ validate_and_create_obj(Org.new(org_seed.merge(props)))
+ end
+ def init_funder(**props)
+ hash = { name: 'Test Funder', abbreviation: 'TSTFNDR', org_type: Org.org_type_values_for(:funder).min }
+ validate_and_create_obj(Org.new(org_seed.merge(hash.merge(props))))
+ end
+ def init_organisation(**props)
+ hash = { name: 'Test Organisation', abbreviation: 'TSTORG', org_type: Org.org_type_values_for(:organisation).min }
+ validate_and_create_obj(Org.new(org_seed.merge(hash.merge(props))))
+ end
+ def init_funder_organisation(**props)
+ hash = { name: 'Test Funder/Organisation', abbreviation: 'TSTFNDRORG', org_type: Org.org_type_values_for(:funder, :organisation).min }
+ validate_and_create_obj(Org.new(org_seed.merge(hash.merge(props))))
+ end
+
+ # User initializers
+ def init_researcher(org, **props)
+ validate_and_create_obj(User.new(user_seed.merge({
+ org: org,
+ surname: 'Researcher',
+ email: 'researcher@testing-roadmap.org',
+ }.merge(props))))
+ end
+ def init_org_admin(org, **props)
+ perms = Perm.where.not(name: ['admin', 'add_organisations',
+ 'change_org_affiliation', 'grant_api_to_orgs',
+ 'change_org_details'])
+ validate_and_create_obj(User.new(user_seed.merge({
+ org: org,
+ surname: 'OrgAdmin',
+ email: 'org.admin@testing-roadmap.org',
+ perms: perms,
+ }.merge(props))))
+ end
+ def init_super_admin(org, **props)
+ perms = Perm.all
+ validate_and_create_obj(User.new(user_seed.merge({
+ org: org,
+ surname: 'SuperAdmin',
+ email: 'super.admin@testing-roadmap.org',
+ perms: perms
+ }.merge(props))))
+ end
+
+ # Template initializers
+ def init_template(org, **props)
+ if org.is_a? Org
+ validate_and_create_obj(Template.new(template_seed.merge({ org: org }.merge(props))))
+ else
+ puts "You must supply an Org when creating a template! Got the following instead: #{org.inspect}"
+ nil
+ end
+ end
+ def init_phase(template, **props)
+ if template.is_a? Template
+ validate_and_create_obj(Phase.new(phase_seed.merge({ template: template }.merge(props))))
+ else
+ puts "You must supply a Template when creating a phase! Got the following instead: #{template.inspect}"
+ nil
+ end
+ end
+ def init_section(phase, **props)
+ if phase.is_a? Phase
+ validate_and_create_obj(Section.new(section_seed.merge({ phase: phase }.merge(props))))
+ else
+ puts "You must supply a Phase when creating a section! Got the following instead: #{phase.inspect}"
+ nil
+ end
+ end
+ def init_question_format(**props)
+ validate_and_create_obj(QuestionFormat.new(question_format_seed.merge(props)))
+ end
+ def init_question(section, **props)
+ if section.is_a? Section
+# TODO call init_question_format instead once the seeds.rb has been removed
+ props[:question_format] = QuestionFormat.first unless props[:question_format].present?
+ validate_and_create_obj(Question.new(question_seed.merge({ section: section }.merge(props))))
+ else
+ puts "You must supply a Section when creating a question! Got the following instead: #{section.inspect}"
+ nil
+ end
+ end
+ def init_annotation(org, question, **props)
+ if org.is_a?(Org) && question.is_a?(Question)
+ validate_and_create_obj(Annotation.new(annotation_seed.merge({ org: org, question: question }.merge(props))))
+ else
+ puts "You must supply an Org and Question when creating an annotation! Got the following instead: ORG - #{org.inspect}, QUESTION - #{question.inspect}"
+ nil
+ end
+ end
+ def init_question_option(question, **props)
+ if question.is_a?(Question)
+ validate_and_create_obj(QuestionOption.new(question_option_seed.merge({ question: question }.merge(props))))
+ else
+ puts "You must supply a Question when creating a question option! Got the following instead: QUESTION - #{question.inspect}"
+ nil
+ end
+ end
+ def init_theme(**props)
+ validate_and_create_obj(Theme.new(theme_seed.merge(props)))
+ end
+ def init_guidance_group(org, **props)
+ if org.is_a? Org
+ validate_and_create_obj(GuidanceGroup.new(guidance_group_seed.merge({ org: org }.merge(props))))
+ else
+ puts "You must supply an Org when creating a GuidanceGroup! Got the following instead: ORG: #{org.inspect}"
+ end
+ end
+ def init_guidance(guidance_group, **props)
+ if guidance_group.is_a?(GuidanceGroup)
+ validate_and_create_obj(Guidance.new(guidance_seed.merge({ guidance_group: guidance_group }.merge(props))))
+ else
+ puts "You must supply a GuidanceGroup when creating a Guidance! Got the following instead: GUIDANCE_GROUP: #{guidance_group.inspect}"
+ end
+ end
+ def init_plan(template, **props)
+ if template.is_a? Template
+ validate_and_create_obj(Plan.new(plan_seed.merge({ template: template }.merge(props))))
+ else
+ puts "You must supply a Template when creating a plan! Got the following instead: #{template.inspect}"
+ nil
+ end
+ end
+
+ # equality helpers for complex objects
+ def assert_annotations_equal(annotation1, annotation2)
+ assert_equal annotation1.text, annotation2.text, 'expected the annotations to have the same text'
+ assert_equal annotation1.type, annotation2.type, 'expected the annotations to be of the same type'
+ end
+ def assert_question_options_equal(option1, option2)
+ assert_equal option1.text, option2.text, 'expecetd the question options to have the same text'
+ assert_equal option1.number, option2.number, 'expecetd the question options to have the same number'
+ assert_equal option1.is_default, option2.is_default, 'expecetd the question options to have the same default flag value'
+ end
+ def assert_questions_equal(question1, question2)
+ assert_equal question1.number, question2.number, 'expected the question numbers to match'
+ assert_equal question1.text, question2.text, 'expected the question text to match'
+ assert_equal question1.question_format, question2.question_format, 'expected the question formats to match'
+ assert_equal question1.option_comment_display, question2.option_comment_display, 'expected the question optional comment display flags to match'
+ assert_equal question1.annotations.length, question2.annotations.length, 'expected the questions to have the same number of annotations'
+ assert_equal question1.question_options.length, question2.question_options.length, 'expected the questions to have the same number of options'
+ question1.annotations.each_with_index do |annotation, idx|
+ assert_annotations_equal(annotation, question2.annotations[idx])
+ end
+ question1.question_options.each_with_index do |option, idx|
+ assert_question_options_equal(option, question2.question_options[idx])
+ end
+ end
+ def assert_sections_equal(section1, section2)
+ assert_equal section1.number, section2.number, 'expected the section numbers to match'
+ assert_equal section1.title, section2.title, 'expected the section titles to match'
+ assert_equal section1.description, section2.description, 'expected the section descriptions to match'
+ assert_equal section1.questions.length, section2.questions.length, 'expected the sections to have the same number of questions'
+ section1.questions.each_with_index do |question, idx|
+ assert_questions_equal(question, section2.questions[idx])
+ end
+ end
+ def assert_phases_equal(phase1, phase2)
+ assert_equal phase1.number, phase2.number, 'expected the phase numbers to match'
+ assert_equal phase1.title, phase2.title, 'expected the phase titles to match'
+ assert_equal phase1.description, phase2.description, 'expected the phase descriptions to match'
+ assert_equal phase1.sections.length, phase2.sections.length, 'expected the phase to have the same number of sections'
+ phase1.sections.each_with_index do |section, idx|
+ assert_sections_equal(section, phase2.sections[idx])
+ end
+ end
+
+
# Get the organisational admin for the Org specified or create one
# ----------------------------------------------------------------------
def scaffold_org_admin(org)
@@ -52,7 +349,7 @@
template = Template.new(title: 'Test template',
description: 'My test template',
links: {"funder":[],"sample_plan":[]},
- org: Org.first, migrated: false, dmptemplate_id: "0000009999")
+ org: Org.first, archived: false, family_id: "0000009999")
template.phases << Phase.new(title: 'Test phase',
description: 'My test phase',
@@ -87,7 +384,7 @@
# Version the template
# ----------------------------------------------------------------------
def version_the_template
- @template = @template.get_new_version
+ @template = @template.generate_version!
end
# Scaffold a new Plan based on the scaffolded Template
@@ -155,6 +452,26 @@
end
end
+ def assert_deep_copy(original, copy, **options)
+ if original.class == copy.class
+ relations = options.fetch(:relations, []).map(&:to_sym)
+ assert(original.object_id != copy.object_id)
+ assert_nil(copy.id, "id should be nil for #{copy.class}") if copy.respond_to?(:id)
+ assert_nil(copy.created_at, "created_at should be nil for #{copy.class}") if copy.respond_to?(:created_at)
+ assert_nil(copy.updated_at, "updated_at should be nil for #{copy.class}") if copy.respond_to?(:updated_at)
+ relations.each do |relation|
+ if copy.respond_to?(relation)
+ relation_obj = copy.send(relation)
+ if relation_obj.respond_to?(:each)
+ relation_obj.each do |obj|
+ assert_nil(obj.id, "id should be nil for the relation object from #{obj.class}") if copy.respond_to?(:id)
+ end
+ end
+ end
+ end
+ end
+ end
+
# ----------------------------------------------------------------------
def verify_has_many_relationship(object, new_association, initial_expected_count)
# Assumes that the association name matches the pluralized name of the class
diff --git a/test/unit/concerns/versionable_test.rb b/test/unit/concerns/versionable_test.rb
new file mode 100644
index 0000000..60391ec
--- /dev/null
+++ b/test/unit/concerns/versionable_test.rb
@@ -0,0 +1,257 @@
+require 'test_helper'
+
+class VersionableTest < ActiveSupport::TestCase
+ include Versionable
+
+ setup do
+ @template = create_template
+ end
+ def create_template
+ funder = init_funder
+ template = init_template(funder)
+ phase = init_phase(template)
+ section = init_section(phase)
+ question = init_question(section)
+ init_annotation(funder, question)
+ return template
+ end
+ test "versionable concern is included" do
+ assert(self.respond_to?(:get_modifiable))
+ end
+ test "#find_in_space raises ArgumentError when search_scape does not respond_to to each" do
+ exception = assert_raises(ArgumentError) do
+ find_in_space(nil, nil)
+ end
+ assert_equal(_('The search_space does not respond to each'), exception.message)
+ end
+ test "#find_in_space raises ArgumentError when search_scape does not have elements" do
+ exception = assert_raises(ArgumentError) do
+ find_in_space(nil, [])
+ end
+ assert_equal(_('The search space does not have elements associated'), exception.message)
+ end
+ test "#find_in_space looks for the object in the search_scape that has elements of its same class" do
+ # Looking for phase
+ phase = init_phase(@template)
+ assert_equal(@template.phases.first, find_in_space(phase, @template.phases), 'phase found in the space')
+ phase.number = 2
+ assert_not(find_in_space(phase, @template.phases), 'phase not found in the space')
+ # Looking for section
+ section = init_section(Phase.new)
+ assert_equal(@template.phases.first.sections.first,
+ find_in_space(section, @template.phases.first.sections),
+ 'section found in the space')
+ section.number = 2
+ assert_not(find_in_space(section, @template.phases.first.sections), 'section not found in the space')
+ # Looking for a question
+ question = init_question(Section.new)
+ assert_equal(@template.phases.first.sections.first.questions.first,
+ find_in_space(question, @template.phases.first.sections.first.questions),
+ ' question found in the space')
+ question.number = 2
+ assert_not(find_in_space(question, @template.phases.first.sections.first.questions), 'question not found in the space')
+ # Looking for an annotation
+ annotation = init_annotation(@template.org, Question.new)
+ assert_equal(@template.phases.first.sections.first.questions.first.annotations.first,
+ find_in_space(annotation, @template.phases.first.sections.first.questions.first.annotations), 'annotation found in the space')
+ annotation.text = 'foo'
+ assert_not(find_in_space(annotation, @template.phases.first.sections.first.questions.first.annotations))
+ # Looking for something else
+ assert_not(find_in_space({}, [{}]))
+ end
+ test "#find_in_space looks for the object in the relation" do
+ # Looking for section
+ section = init_section(@template.phases.first)
+ assert_equal(@template.phases.first.sections.first,
+ find_in_space(section, @template.phases), 'section found in the space through its phase number')
+ # Looking for question
+ question = init_question(@template.phases.first.sections.first)
+ assert_equal(@template.phases.first.sections.first.questions.first,
+ find_in_space(question, @template.phases), 'question found in the space through its phase/section number')
+ # Looking for annotation
+ annotation = init_annotation(@template.org, @template.phases.first.sections.first.questions.first)
+ assert_equal(@template.phases.first.sections.first.questions.first.annotations.first,
+ find_in_space(annotation, @template.phases), 'annotation found int the space through its phase/section/question number')
+ # Looking for a question in a not known search_space
+ assert_not(find_in_space(Question.new, [{}]))
+ end
+ test "#find_in_space looks for an object that does not belong to the hierarchy" do
+ question = init_question(@template.phases.first.sections.first)
+ question.phase.number = 2
+ assert_not(find_in_space(question, @template.phases))
+ end
+
+ test "#get_new raises ArgumentError unless the object respond_to template" do
+ exception = assert_raises(ArgumentError) do
+ get_new(@template)
+ end
+ assert_equal(_('obj should be a Phase, Section, Question, or Annotation'), exception.message)
+ end
+
+ test "#get_new raises RuntimeError when template is not latest" do
+ @template.published = true
+ @template.generate_version!
+
+ hierarchy_objects = [
+ Phase.new(template_id: @template.id),
+ Section.new(phase_id: @template.phases.first.id),
+ Question.new(section_id: @template.phases.first.sections.first.id),
+ Annotation.new(question_id: @template.phases.first.sections.first.questions.first.id)
+ ]
+
+ hierarchy_objects.each do |obj|
+ exception = assert_raises(RuntimeError) do
+ get_new(obj)
+ end
+ assert_equal(_('A historical template cannot be retrieved for being modified'), exception.message)
+ end
+ end
+
+ test "#get_new returns same object when template is not published" do
+ # Looking for phase
+ phase = Phase.new(template: @template)
+ new_phase = get_new(phase)
+ assert_equal(phase.template_id, new_phase.template_id, 'returns the phase without generating a new template hierarchy')
+ # Looking for section
+ section = Section.new(phase: @template.phases.first)
+ new_section = get_new(section)
+ assert_equal(section.phase_id, new_section.phase_id, 'returns the section without generating a new template hierarchy')
+ # Looking for question
+ question = Question.new(section: @template.phases.first.sections.first)
+ new_question = get_new(question)
+ assert_equal(question.section_id, new_question.section_id, 'returns the question without generating a new template hierarchy')
+ # Looking for annotation fails
+ annotation = Annotation.new(question: @template.phases.first.sections.first.questions.first)
+ new_annotation = get_new(annotation)
+ assert_equal(annotation.question_id, new_annotation.question_id, 'returns the same annotation without generating a new template hierarchy')
+ end
+
+ test "#get_new returns new phase when template is published" do
+ @template.published = true
+ @template.save!
+ phase = Phase.new(template: @template)
+ new_phase = get_new(phase)
+ assert_not_equal(phase.template_id, new_phase.template_id)
+ end
+
+ test "#get_new returns new section when template is published" do
+ @template.published = true
+ @template.save!
+ section = Section.new(phase: @template.phases.first)
+ new_section = get_new(section)
+ assert_not_equal(section.phase_id, new_section.phase_id)
+ end
+
+ test "#get_new returns new question when template is published" do
+ @template.published = true
+ @template.save!
+ question = Question.new(section: @template.phases.first.sections.first)
+ new_question = get_new(question)
+ assert_not_equal(question.section_id, new_question.section_id)
+ end
+
+ test "#get_new returns new annotation when template is published" do
+ @template.published = true
+ @template.save!
+ annotation = Annotation.new(question: @template.phases.first.sections.first.questions.first)
+ new_annotation = get_new(annotation)
+ assert_not_equal(annotation.question_id, new_annotation.question_id)
+ end
+
+ test "#get_modifiable raises ArgumentError when the object is not template or object responding to template" do
+ exception = assert_raises(ArgumentError) do
+ get_modifiable({})
+ end
+ assert_equal(_('obj should be a Template, Phase, Section, Question, or Annotation'), exception.message)
+ end
+
+ test "#get_modifiable raises RuntimeError when template is not latest" do
+ @template.published = true
+ @template.generate_version!
+
+ hierarchy_objects = [
+ @template.phases.first,
+ @template.phases.first.sections.first,
+ @template.phases.first.sections.first.questions.first,
+ @template.phases.first.sections.first.questions.first.annotations.first
+ ]
+
+ hierarchy_objects.each do |obj|
+ exception = assert_raises(RuntimeError) do
+ get_modifiable(obj)
+ end
+ assert_equal(_('A historical template cannot be retrieved for being modified'), exception.message)
+ end
+ end
+
+ test "#get_modifiable returns same object when template is not published" do
+ # Looking for phase
+ phase = @template.phases.first
+ new_phase = get_modifiable(phase)
+ assert_equal(phase.id, new_phase.id, 'returns the same phase id')
+ assert_equal(phase.template_id, new_phase.template_id, 'returns the phase without generating a new template hierarchy')
+ # Looking for section
+ section = @template.phases.first.sections.first
+ new_section = get_modifiable(section)
+ assert_equal(section.id, new_section.id, 'returns the same section id')
+ assert_equal(section.phase.template, new_section.phase.template, 'returns the section without generating a new template hierarchy')
+ # Looking for a question
+ question = @template.phases.first.sections.first.questions.first
+ new_question = get_modifiable(question)
+ assert_equal(question.id, new_question.id, 'returns the same question id')
+ assert_equal(question.section.phase.template, new_question.section.phase.template, 'returns the question without generating a new template hierarchy')
+ # Looking for an annotation
+ annotation = @template.phases.first.sections.first.questions.first.annotations.first
+ new_annotation = get_modifiable(annotation)
+ assert_equal(annotation.id, new_annotation.id, 'returns the same annotation id')
+ assert_equal(annotation.question.section.phase.template, new_annotation.question.section.phase.template, 'returns the annotation without generating a new template hierarchy')
+ end
+
+ test "#get_modifiable returns new phase when template is published" do
+ @template.published = true
+ @template.save!
+ phase = @template.phases.first
+ new_phase = get_modifiable(phase)
+ assert_not_equal(phase.id, new_phase.id, 'returns different phase id')
+ assert_not_equal(phase.template_id, new_phase.template_id, 'returns different template belonging')
+ end
+
+ test "#get_modifiable returns new section when template is published" do
+ @template.published = true
+ @template.save!
+ section = @template.phases.first.sections.first
+ new_section = get_modifiable(section)
+ assert_not_equal(section.id, new_section.id, 'returns different section id')
+ assert_not_equal(section.phase.template, new_section.phase.template, 'returns different template belonging')
+ end
+
+ test "#get_modifiable returns new question when template is published" do
+ @template.published = true
+ @template.save!
+ question = @template.phases.first.sections.first.questions.first
+ new_question = get_modifiable(question)
+ assert_not_equal(question.id, new_question.id, 'returns different question id')
+ assert_not_equal(question.section.phase.template, new_question.section.phase.template, 'returns different template belonging')
+ end
+
+ test "#get_modifiable returns new annotation when template is published" do
+ @template.published = true
+ @template.save!
+ annotation = @template.phases.first.sections.first.questions.first.annotations.first
+ new_annotation = get_modifiable(annotation)
+ assert_not_equal(annotation.id, new_annotation.id, 'returns different annotation id')
+ assert_not_equal(annotation.question.section.phase.template, new_annotation.question.section.phase.template, 'returns different template belonging')
+ end
+
+ test "#get_modifiable returns new question_option when template is published" do
+ @template.published = true
+ @template.save!
+ question = @template.phases.first.sections.first.questions.first
+ question.question_options << init_question_option(question)
+ question_option = question.question_options.first
+ new_question = get_modifiable(question)
+ new_question_option = new_question.question_options.first
+ assert_not_equal(question_option.id, new_question_option.id, 'returns different question_option id')
+ assert_not_equal(question_option.question.section.phase.template, new_question_option.question.section.phase.template, 'returns different template belonging')
+ end
+end
\ No newline at end of file
diff --git a/test/unit/org_test.rb b/test/unit/org_test.rb
index 0d5e284..645948a 100644
--- a/test/unit/org_test.rb
+++ b/test/unit/org_test.rb
@@ -153,7 +153,7 @@
end
# ---------------------------------------------------
- test "can manage has_many relationship with Dmptemplates" do
+ test "can manage has_many relationship with Templates" do
tmplt = Template.new(title: 'Added through test', version: 1)
verify_has_many_relationship(@org, tmplt, @org.templates.count)
end
diff --git a/test/unit/phase_test.rb b/test/unit/phase_test.rb
index 14ef133..5383b59 100644
--- a/test/unit/phase_test.rb
+++ b/test/unit/phase_test.rb
@@ -3,60 +3,60 @@
class PhaseTest < ActiveSupport::TestCase
setup do
- @org = Org.first
- @template = Template.first
- @phase = Phase.create(title: 'Test Phase 1', number: 1, template: @template)
+ # Need to clear the tables until we get seed.rb out of test_helper.rb
+ Template.delete_all
+ @funder = init_funder
+ @template = init_template(@funder, published: true)
+ @phase = init_phase(@template)
end
- # ---------------------------------------------------
test "required fields are required" do
assert_not Phase.new.valid?
- assert_not Phase.new(title: 'Testing', number: 1).valid?, "expected the dmptemplate field to be required"
+ assert_not Phase.new(title: 'Testing', number: 1).valid?, "expected the template field to be required"
assert_not Phase.new(number: 2, template: @template).valid?, "expected the title field to be required"
assert_not Phase.new(title: 'Testing', template: @template).valid?, "expected the number field to be required"
- # Ensure the bar minimum and complete versions are valid
+ # Ensure the bare minimum and complete versions are valid
a = Phase.new(title: 'Testing', template: @template, number: 2)
assert a.valid?, "expected the 'title', 'number' and 'template' fields to be enough to create an Phase! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
end
- # ---------------------------------------------------
- test "to_s returns the title" do
- assert_equal @phase.title, @phase.to_s
+ test "titles scope returns a list of all phase id with their titles for the specified template" do
+ init_phase(@template, { title: 'test scope 1', number: 2 })
+ init_phase(@template, { title: 'test scope 2', number: 3 })
+ titles = Phase.titles(@template)
+ assert_equal 3, titles.length, 'expected 3 phases, the orignal and 2 new'
+ assert_not titles.select{ |p| p.title == 'test scope 2' }.empty?, "expected to find the second phase"
end
- # ---------------------------------------------------
- test "has_sections returns false if there are NO published versions with sections" do
- # TODO: build out this test if the has_sections method is actually necessary
+ test "titles scope does not return phases from other templates" do
+ init_phase(@template, { title: 'test scope 1', number: 2 })
+ template2 = init_template(@funder, { title: 'template 2' })
+ init_phase(template2, { title: 'other template scope' })
+ titles = Phase.titles(@template)
+ assert titles.select{ |p| p.title == 'other template scope' }.empty?, "expected to not find the other template's phase"
end
- # ---------------------------------------------------
- test "deep copy" do
- verify_deep_copy(@phase, ['id', 'created_at', 'updated_at'])
- end
-
- # ---------------------------------------------------
- test "can CRUD Phase" do
- obj = Phase.create(title: 'Testing CRUD', template: @template, number: 4)
- assert_not obj.id.nil?, "was expecting to be able to create a new Phase! - #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
-
- obj.title = 'Testing an update'
- obj.save!
- obj.reload
- assert_equal 'Testing an update', obj.title, "Was expecting to be able to update the title of the Phase!"
-
- assert obj.destroy!, "Was unable to delete the Phase!"
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Sections" do
- s = Section.new(title: 'Test Section', number: 2)
- verify_has_many_relationship(@phase, s, @phase.sections.count)
+ test "#deep_copy creates a new phase object and attaches new section objects" do
+ assert_deep_copy(@phase, @phase.deep_copy, relations: [:sections])
end
- # ---------------------------------------------------
- test "can manage belongs_to relationship with Template" do
- phase = Phase.new(title: 'Tester', number: 9)
- verify_belongs_to_relationship(phase, @template)
+ test "num_questions returns the total number of questions for the phase" do
+ section = init_section(@phase)
+ section2 = init_section(@phase, { title: 'Section B', number: 2 })
+ init_question(section)
+ init_question(section, { text: 'Question number 2', number: 2 })
+ init_question(section2)
+ assert_equal 3, @phase.num_questions, 'expected 3 questions for the phase, 2 for the 1st section and 1 for the 2nd section'
+ end
+
+ test "num_questions does not count questions that belong to other templates" do
+ section = init_section(@phase)
+ init_question(section)
+ template2 = init_template(@funder, { title: 'template 2' })
+ phase2 = init_phase(template2, { title: 'other template scope' })
+ section2 = init_section(phase2)
+ init_question(section2)
+ assert_equal 1, @phase.num_questions, 'expected 1 question for the phase'
end
end
diff --git a/test/unit/plan_test.rb b/test/unit/plan_test.rb
index a1a82bb..9aec140 100644
--- a/test/unit/plan_test.rb
+++ b/test/unit/plan_test.rb
@@ -42,10 +42,6 @@
=end
end
- # ---------------------------------------------------
- test "dmptemplate returns the template" do
- assert_equal @plan.template, @plan.dmptemplate
- end
# ---------------------------------------------------
test "correctly creates a new answer" do
diff --git a/test/unit/question_test.rb b/test/unit/question_test.rb
index 706a10d..c6b3066 100644
--- a/test/unit/question_test.rb
+++ b/test/unit/question_test.rb
@@ -3,120 +3,79 @@
class QuestionTest < ActiveSupport::TestCase
setup do
- @user = User.last
-
- scaffold_template
-
- @section = @template.phases.first.sections.first
-
- @question = Question.create(text: 'Test question', default_value: 'ABCD',
- number: 999, section: @section,
- question_format: QuestionFormat.where(option_based: false).first,
- option_comment_display: true, modifiable: true,
- themes: [Theme.first],
- annotations: [Annotation.new(org: @user.org,
- text: "just a suggestion")])
+ # Need to clear the tables until we get seed.rb out of test_helper.rb
+ Template.delete_all
+ @funder = init_funder
+ @institution = init_institution
+ @template = init_template(@institution, published: true)
+ @phase = init_phase(@template)
+ @section = init_section(@phase)
+ @question = init_question(@section)
end
- # ---------------------------------------------------
test "required fields are required" do
assert_not Question.new.valid?
assert_not Question.new(section: @section, number: 7).valid?, "expected the 'text' field to be required"
assert_not Question.new(number: 7, text: 'Testing').valid?, "expected the 'section' field to be required"
assert_not Question.new(section: @section, text: 'Testing').valid?, "expected the 'number' field to be required"
- # Ensure the bar minimum and complete versions are valid
+ # Ensure the bare minimum and complete versions are valid
a = Question.new(section: @section, text: 'Testing', number: 7)
assert a.valid?, "expected the 'text', 'section' and 'number' fields to be enough to create an Question! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
end
- # ---------------------------------------------------
test "to_s returns the Question text" do
assert_equal @question.text, @question.to_s
end
- # ---------------------------------------------------
+ test "option_based? returns the correct boolean value" do
+ assert_not @question.option_based?
+# TODO: replace with a call to the init_question_format factory method once seeds.rb is no longer being loaded
+ @question.question_format = QuestionFormat.find_by(option_based: true)
+ @question.save!
+ assert @question.option_based?
+ end
+
+ test "#deep_copy creates a new question object and attaches new annotations/question_options objects" do
+ init_annotation(@institution, @question)
+ init_question_option(@question)
+ assert_deep_copy(@question, @question.deep_copy, relations: [:annotations, :question_options])
+ end
+
+# TODO: This method should get moved to a view helper instead
test "returns the correct themed guidance for the org" do
- all = Theme.first.guidances + Theme.last.guidances
+ theme = init_theme
+ guidance_group = init_guidance_group(@institution)
+ funder_guidance_group = init_guidance_group(@funder, { title: 'Test funder guidance group' } )
+ guidance = init_guidance(guidance_group, { themes: [theme] })
+ funder_guidance = init_guidance(funder_guidance_group, { themes: [theme] })
- # Attach 2 themes to the question
- @question.themes = [Theme.first, Theme.last]
+ @question.themes << theme
@question.save!
- # Attach the first theme's first gudiance's group to the org
- @user.org.guidance_groups << Theme.first.guidances.first.guidance_group
- @user.save!
+ institution_guidances = @question.guidance_for_org(@institution)
+ # method retuns a hash {'descriptive string': 'guidances array'}
+ assert_equal 1, institution_guidances.length
+ assert_equal guidance, institution_guidances.first.last
- assert_not @question.guidance_for_org(@user.org).empty?, "expected guidance to be returned"
-
- assert @question.guidance_for_org(@user.org).first.first.include?(Theme.first.title), "expected the theme.title"
- assert @question.guidance_for_org(@user.org).first.first.include?(Theme.first.guidances.first.guidance_group.name), "expected the guidance_group.name"
- assert_equal Theme.first.guidances.first, @question.guidance_for_org(@user.org).first.last, "expected the guidance object to be returned"
+ funder_guidances = @question.guidance_for_org(@funder)
+ # method retuns a hash {'descriptive string', 'guidances array'}
+ assert_equal 1, funder_guidances.length
+ assert_equal funder_guidance, funder_guidances.first.last
end
-
+
# ---------------------------------------------------
test "returns the correct annotation for the org" do
- @question.annotations = [Annotation.create(org: @user.org, text: 'Test 1', type: Annotation.types[:example_answer]),
- Annotation.create(org: Org.first, text: 'Test 2', type: Annotation.types[:example_answer])]
- @question.save!
-
- assert_equal 'Test 1', @question.annotations.where(org_id: @user.org.id).first.text, "expected the correct annotation"
- assert_equal 'Test 2', @question.annotations.where(org_id: Org.first.id).first.text, "expected the correct annotation"
-
- org = Org.create(name: 'New One', links: {"org":[]})
- assert_equal 0, @question.get_example_answers(org.id).length, "expected no annotation for a new org"
- end
-
- # ---------------------------------------------------
- test "deep copy" do
- verify_deep_copy(@question, ['id', 'created_at', 'updated_at'])
- end
-
- # ---------------------------------------------------
- test "can CRUD Question" do
- obj = Question.create(section: @section, text: 'Test ABC', number: 7)
- assert_not obj.id.nil?, "was expecting to be able to create a new Question: #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
-
- obj.text = 'Testing an update'
- obj.save!
- obj.reload
- assert_equal 'Testing an update', obj.text, "Was expecting to be able to update the text of the Question!"
-
- assert obj.destroy!, "Was unable to delete the Question!"
- end
-
- # ---------------------------------------------------
- test "can manage belongs_to relationship with Section" do
- verify_belongs_to_relationship(@question, @template.phases.first.sections.last)
- end
-
- # ---------------------------------------------------
- test "can manage belongs_to relationship with QuestionFormat" do
- verify_belongs_to_relationship(@question, QuestionFormat.where(option_based: false).last)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Answer" do
- scaffold_plan
- a = Answer.new(user: @user, plan: @plan, text: 'Test Answer')
- verify_has_many_relationship(@question, a, @question.answers.count)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with QuestionOption" do
- qo = QuestionOption.new(text: 'Test', number: 9)
- verify_has_many_relationship(@question, qo, @question.question_options.count)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Annotation" do
- sa = Annotation.new(text: 'Suggested Answer', org: @user.org)
- verify_has_many_relationship(@question, sa, @question.annotations.count)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Themes" do
- t = Theme.new(title: 'Test Theme')
- verify_has_many_relationship(@question, t, @question.themes.count)
+ annotation = init_annotation(@institution, @question, { type: Annotation.types[:example_answer] })
+ annotation2 = init_annotation(@institution, @question)
+ funder_annotation = init_annotation(@funder, @question, { text: 'Test funder example answer', type: Annotation.types[:example_answer] } )
+ funder_annotation2 = init_annotation(@funder, @question, { text: 'Test funder guidance'} )
+
+ institutional_annotations = @question.get_example_answers(@institution)
+ assert_equal 1, institutional_annotations.length
+ assert_equal annotation, institutional_annotations.first
+ funder_annotations = @question.get_example_answers(@funder)
+ assert_equal 1, funder_annotations.length
+ assert_equal funder_annotation, funder_annotations.first
end
end
diff --git a/test/unit/section_test.rb b/test/unit/section_test.rb
index 5a22b5f..b14d556 100644
--- a/test/unit/section_test.rb
+++ b/test/unit/section_test.rb
@@ -3,56 +3,34 @@
class SectionTest < ActiveSupport::TestCase
setup do
- scaffold_template
-
- @section = Section.create(title: 'Test Section', description: 'My test section', number: 99,
- published: true, phase: @template.phases.first, modifiable: false)
+ # Need to clear the tables until we get seed.rb out of test_helper.rb
+ Template.delete_all
+ funder = init_funder
+ template = init_template(funder, published: true)
+ @phase = init_phase(template)
+ @section = init_section(@phase)
end
- # ---------------------------------------------------
test "required fields are required" do
assert_not Section.new.valid?
- assert_not Section.new(phase: @template.phases.last, number: 9).valid?, "expected the 'title' field to be required"
+ assert_not Section.new(phase: @phase, number: 9).valid?, "expected the 'title' field to be required"
assert_not Section.new(title: 'Tester', number: 9).valid?, "expected the 'phase' field to be required"
- assert_not Section.new(phase: @template.phases.last, title: 'Tester').valid?, "expected the 'number' field to be required"
+ assert_not Section.new(phase: @phase, title: 'Tester').valid?, "expected the 'number' field to be required"
# Ensure the bare minimum and complete versions are valid
- a = Section.new(phase: @template.phases.last, title: 'Tester', number: 9)
+ a = Section.new(phase: @phase, title: 'Tester', number: 9)
assert a.valid?, "expected the 'phase', 'title' and 'number' fields to be enough to create an Section! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
end
- # ---------------------------------------------------
test "to_s returns the title" do
assert_equal @section.title, @section.to_s
end
- # ---------------------------------------------------
- test "deep copy" do
- verify_deep_copy(@section, ['id', 'created_at', 'updated_at'])
+ test "#deep_copy creates a new section object and attaches new question objects" do
+ assert_deep_copy(@section, @section.deep_copy, relations: [:questions])
end
-
- # ---------------------------------------------------
- test "can CRUD Section" do
- obj = Section.create(phase: @template.phases.last, title: 'Tester', number: 9)
- assert_not obj.id.nil?, "was expecting to be able to create a new Section: #{obj.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
- obj.description = 'my tester'
- obj.save!
- obj.reload
- assert_equal 'my tester', obj.description, "Was expecting to be able to update the description of the Section!"
-
- assert obj.destroy!, "Was unable to delete the Section!"
- end
-
- # ---------------------------------------------------
- test "can manage belongs_to relationship with Phase" do
- section = Section.new(title: 'Tester', number: 99)
- verify_belongs_to_relationship(section, @template.phases.first)
- end
-
- # ---------------------------------------------------
- test "can manage has_many relationship with Question" do
- question = Question.new(text: 'Testing', number: 1)
- verify_has_many_relationship(@section, question, @section.questions.count)
+ test "default values are properly set on section creation" do
+ assert(@section.modifiable, 'expected a new section to be modifiable')
end
end
\ No newline at end of file
diff --git a/test/unit/template_test.rb b/test/unit/template_test.rb
index 69f2485..78401f0 100644
--- a/test/unit/template_test.rb
+++ b/test/unit/template_test.rb
@@ -3,9 +3,22 @@
class TemplateTest < ActiveSupport::TestCase
setup do
- @org = Org.last
+ # Need to clear the tables until we get seed.rb out of test_helper.rb
+ Template.destroy_all
- scaffold_template
+ @funder = init_funder
+ @org = init_organisation
+ @institution = init_institution
+ @funder_org = init_funder_organisation
+
+ @basic_template = init_template(@funder, published: true)
+ end
+
+ def init_full_template(template)
+ phase = init_phase(template)
+ section = init_section(phase)
+ init_question(section)
+ return template
end
def settings(extras = {})
@@ -18,162 +31,397 @@
def default_formatting
Settings::Template::DEFAULT_SETTINGS[:formatting]
end
+
+ test "default values are properly set on template creation" do
+ template = init_template(@funder)
+ assert_equal false, template.published, 'expected a new template to not be published'
+ assert_equal false, template.archived, 'expected a new template to not be archived'
+ assert_not_nil template.family_id, 'expected a new template to have a family_id'
+ assert_equal false, template.is_default, 'expected a new template to not be the default template'
+ assert template.publicly_visible?, 'expected a new funder template to be publicly visible'
- # ---------------------------------------------------
+ tmplt = init_template(@org)
+ tmplt2 = init_template(@funder_org)
+ assert tmplt.organisationally_visible?, 'expected a new non-funder template to be organisationally visible'
+ assert tmplt2.organisationally_visible?, 'expected a new non-funder template to be organisationally visible'
+ end
+
test "required fields are required" do
assert_not Template.new.valid?
assert_not Template.new(version: 1, title: 'Tester').valid?, "expected the 'org' field to be required"
- assert_not Template.new(org: @org, version: 1).valid?, "expected the 'title' field to be required"
-
- # Ensure the bare minimum and complete versions are valid
- a = Template.new(org: @org, title: 'Tester')
- assert a.valid?, "expected the 'org', 'version' and 'title' fields to be enough to create an Template! - #{a.errors.map{|f, m| f.to_s + ' ' + m}.join(', ')}"
+ assert_not Template.new(org: @funder, version: 1).valid?, "expected the 'title' field to be required"
end
- # ---------------------------------------------------
- test "family_ids scope only returns the dmptemplate_ids for the specific Org" do
- Org.all.each do |org|
- family_ids = Template.valid.all.pluck(:dmptemplate_id).uniq
- scoped = Template.dmptemplate_ids
- assert_equal family_ids.count, scoped.count
-
- family_ids.each do |id|
- assert scoped.include?(id), "expected the family_ids scope to contain #{id} for Org: #{org.id}"
- end
- scoped.each do |id|
- assert family_ids.include?(id), "expected #{id} to be a valid dmptemplate_id for Org: #{org.id}"
- end
+ test "unarchived returns only unarchived templates" do
+ # Create an unarchived and an archived template (set archived after init because it will default to false on creation)
+ archived = init_template(@funder, { title: 'Archived Template' })
+ archived.update_attributes(archived: true)
+ results = Template.unarchived
+ assert_equal 1, results.length, 'expected there to be only 1 unarchived template'
+ assert_equal @basic_template, results.first, 'expected the correct template to have been returned'
+ end
+
+ test "archived returns only archived templates" do
+ # Create an unarchived and an archived template (set archived after init because it will default to false on creation)
+ archived = init_template(@funder, { title: 'Archived Template' })
+ archived.update_attributes(archived: true)
+ results = Template.archived
+ assert_equal 1, results.length, 'expected there to be only 1 archived template'
+ assert_equal archived, results.first, 'expected the correct template to have been returned'
+ end
+
+ test "able to determine the latest version number" do
+ version2 = @basic_template.generate_version!
+ version2.save!
+ results = Template.latest_version_per_family(@basic_template.family_id)
+ assert_equal 1, results.length, 'expected only one version to be returned for the specific family'
+ assert_equal version2.version, results.first.version, 'expected the new version'
+ end
+
+ test "able to retrieve the latest version" do
+ version2 = @basic_template.generate_version!
+ version2.save!
+ result = Template.latest_version(@basic_template.family_id)
+ assert_equal 1, result.length, 'expected only one version to be returned'
+ assert_equal version2, result.first, 'expected the new version'
+ end
+
+ test "able to version a template" do
+ template = init_full_template(@basic_template)
+ assert_equal 0, template.version, 'expected the initial template version to be zero'
+ version2 = template.generate_version!
+ assert_equal 1, version2.version, 'expected the version number to be one more than the original template\'s'
+ assert_equal template.family_id, version2.family_id, 'expected the new version to have the same family_id'
+ assert_equal template.visibility, version2.visibility, 'expected the new version to have the same visibility'
+ assert_equal template.is_default, version2.is_default, 'expected the new version to have the same default flag'
+ assert_equal false, version2.archived, 'expected the new version to no be archived'
+ # All components were transferred over to the new version
+ assert_equal template.phases.length, version2.phases.length, 'expected the new version to have the same number of phases'
+ template.phases.each_with_index do |phase, idx|
+ assert_phases_equal(phase, version2.phases[idx])
end
end
- # ---------------------------------------------------
- test "current scope only returns the most recent version for each dmptemplate_id" do
- Org.all.each do |org|
- Template.dmptemplate_ids.each do |dmptemplate_id|
- latest = Template.where(dmptemplate_id: dmptemplate_id).order(updated_at: :desc).first
-
- assert_equal latest, Template.current(dmptemplate_id), "Expected the template.id #{latest.id} to be the current record for Org: #{org.id}, dmptemplate_id: #{dmptemplate_id}"
- end
+ test "#generate_copy! raises RuntimeError when a non Org object is passed" do
+ init_full_template(@basic_template)
+ exception = assert_raises(RuntimeError) do
+ @basic_template.generate_copy!(nil)
+ end
+ assert_equal(_('generate_copy! requires an organisation target'), exception.message)
+ end
+
+ test "#generate_copy! creates a new copy of a template" do
+ template = init_full_template(@basic_template)
+ template.update_attributes(is_default: true, published: true) # Update these flags to verify that the copy sets them properly
+ copy = template.generate_copy!(@institution)
+ assert_not_equal template.id, copy.id, 'expecetd the copy to have a different id'
+ assert_not_equal template.family_id, copy.family_id, 'expected the copy to have a different family id'
+ assert_equal @institution, copy.org, 'expected the copy to have the correct Org'
+ assert_equal 0, copy.version, 'expected the copy\'s version number to be zero'
+ assert_not copy.published?, 'expected the copy to not be published'
+ assert_not copy.is_default?, 'expected the copy to not be the default template'
+ assert_equal 'organisationally_visible', copy.visibility, 'expected the visibility to be organisational'
+ assert_equal 'Copy of %{template}' % { template: template.title }, copy.title, 'expected the template title to be "Copy of %{template}"'
+ assert_equal template.description, copy.description, 'expected the template descriptions to match'
+ assert_equal template.phases.length, copy.phases.length, 'expected the copy to have the same number of phases'
+ template.phases.each_with_index do |phase, idx|
+ assert_phases_equal(phase, copy.phases[idx])
+ end
+ end
+
+ test "can properly determine if current template is the latest version" do
+ assert @basic_template.latest?, 'expected the initial template to be the latest version'
+ version2 = @basic_template.generate_version!
+ version2.save!
+ assert_not @basic_template.latest?, 'expected the initial template to no longer be the latest version'
+ assert version2.latest?, 'expected the new version to be the latest version'
+ end
+
+ test "#customize! raises RuntimeError when a non Org object is passed" do
+ init_full_template(@basic_template)
+ exception = assert_raises(RuntimeError) do
+ @basic_template.customize!(nil)
+ end
+ assert_equal(_('customize! requires an organisation target'), exception.message)
+ end
+
+ test "#customize! raises RuntimeError when the template belongs to a non funder" do
+ template = init_template(@org, published: true)
+ exception = assert_raises(StandardError) do
+ template.customize!(@institution)
end
end
- # ---------------------------------------------------
- test "published scope only returns the current published version for each dmptemplate_id" do
- Org.all.each do |org|
- Template.dmptemplate_ids.each do |dmptemplate_id|
- latest = Template.where(dmptemplate_id: dmptemplate_id, published: true).order(updated_at: :desc).first
- if latest.nil?
- "Expected the template to have never been published"
- else
- assert_equal latest, Template.live(dmptemplate_id), "Expected the template.id #{latest.id} to be the published record for Org: #{org.id}, dmptemplate_id: #{dmptemplate_id}"
+ test "#customize! allows user to customize the default template" do
+ template = init_template(@org, published: true, is_default: true)
+ customization = template.customize!(@institution)
+ assert_not_nil(customization)
+ end
+
+ test "#customize! generates a new template" do
+ template = init_full_template(@basic_template)
+ customization = template.customize!(@institution)
+ assert(customization.family_id.present?, 'expected a newly family_id value')
+ assert_equal(template.family_id, customization.customization_of, 'expected the customization_of id to match the base template\'s family_id')
+ assert_equal(0, customization.version, 'expected the initial customization version to be zero')
+ assert_equal(@institution, customization.org, 'expected the customizatio\'s org to match the one specified')
+ assert_not(customization.published, 'expected the customization to not be published')
+ assert_equal('organisationally_visible', customization.visibility, 'expected the customization\'s visibility to be organisationally visible')
+ assert_not(customization.is_default, 'expected the customization to not be the default template')
+
+ # Following statements go further than checking that the instance method behaves adequately
+ assert_equal template.phases.length, customization.phases.length, 'expected the customization to have the same number of phases as the base template'
+ template.phases.each_with_index do |phase, idx|
+ assert_phases_equal(phase, customization.phases[idx])
+ end
+ end
+ test "#customize! is thread-safe and therefore only one customization_of/version/org_id record exists in the db" do
+ template = init_template(@funder, published: true)
+ await = true
+ should_assert = true
+ threads = 3.times.map do |i|
+ Thread.new do
+ while await do ; end
+ begin
+ template.customize!(@org)
+ rescue ActiveRecord::StatementInvalid => e
+ # SQLite only supports one writer at a time. (e.g. https://www.sqlite.org/rescode.html#busy)
+ should_assert = false if e.message.include?("SQLite3::BusyException")
end
end
end
+ await = false
+ threads.map(&:join)
+ # ActiveRecord::Base.connection.adapter_name != 'SQLite'
+ assert_equal(1, Template.where(customization_of: template.family_id, version: 0, org_id: @org.id).count) if should_assert
+ end
+
+ test "template customizations can be transferred after base template changes" do
+ init_full_template(@basic_template)
+ customization = @basic_template.customize!(@institution)
+ first_question = customization.phases.first.sections.first.questions.first
+ init_annotation(customization.org, first_question)
+ customization.save!
+ end
+
+ test "base_org returns the current template org if the template is not customized" do
+ assert_equal @basic_template.org, @basic_template.base_org, 'expected an uncustomized template to consider its own org the base_org'
+ end
+ test "base_org returns the parent template org if the template is customized" do
+ customization = @basic_template.customize!(@institution)
+ assert_equal @basic_template.org, customization.base_org, 'expected a customized template to consider the parent template\'s org the base_org'
+ end
+
+ test "#generate_version! raises RuntimeError when the template is not published" do
+ template = init_template(@org, published: false)
+ exception = assert_raises(RuntimeError) do
+ template.generate_version!
+ end
+ assert_equal(_('generate_version! requires a published template'), exception.message)
+ end
+
+ test "#generate_version! creates a new version for a published and non-customised template" do
+ template = init_template(@org, published: true)
+ new_template = template.generate_version!
+ assert_equal(@basic_template.version + 1, new_template.version)
+ assert_not(new_template.published)
+ end
+
+ test "#generate_version! is thread-safe and therefore only one family_id/version record exists in the db" do
+ template = init_template(@org, published: true)
+ await = true
+ should_assert = true
+ threads = 3.times.map do |i|
+ Thread.new do
+ while await do ; end
+ begin
+ template.generate_version!
+ rescue ActiveRecord::StatementInvalid => e
+ # SQLite only supports one writer at a time. (e.g. https://www.sqlite.org/rescode.html#busy)
+ should_assert = false if e.message.include?("SQLite3::BusyException")
+ end
+ end
+ end
+ await = false
+ threads.map(&:join)
+ assert_equal(1, Template.where(family_id: template.family_id, version: 1).count) if should_assert
+ end
+
+ test "#upgrade_customization! raises RuntimeError when the template is not a customisation of another template" do
+ template = init_template(@org, published: true)
+ exception = assert_raises(RuntimeError) do
+ template.upgrade_customization!
+ end
+ assert_equal(_('upgrade_customization! requires a customised template'), exception.message)
+ end
+
+ test "#upgrade_customization! creates a new version" do
+ customization = @basic_template.customize!(@institution)
+ customization.published = true
+ transferred = customization.upgrade_customization!
+ assert_equal(customization.version + 1, transferred.version, 'expected the version number to have been incremented when the current cusomization was published')
+ assert_equal(customization.family_id, transferred.family_id, 'expected the family_id to be retained when upgrade_customization! is called')
+ end
+
+ test "#upgrade_customization! appends modifiable phases to the new customisation" do
+ init_full_template(@basic_template)
+ customization = @basic_template.customize!(@institution)
+ customization.phases << Phase.new(title: 'New customised phase', number: 2, modifiable: true)
+ customization.phases << Phase.new(title: 'New customised phase 2', number: 3, modifiable: true)
+
+ transferred = customization.upgrade_customization!
+ assert_not_equal(customization.object_id, transferred.object_id, 'customization and transferred are distinct objects')
+ assert_equal(3, transferred.phases.length, 'expected 3 phases after upgrading a customised template')
+ end
+
+ test "#upgrade_customization! appends modifiable sections into an unmodifiable phase" do
+ init_full_template(@basic_template)
+ customization = @basic_template.customize!(@institution)
+ customization.phases.first.sections << Section.new(title: 'New customised section', number: 2, modifiable: true)
+ customization.phases.first.sections << Section.new(title: 'New customised section 2', number: 3, modifiable: true)
+
+ transferred = customization.upgrade_customization!
+ assert_not_equal(customization.object_id, transferred.object_id, 'customization and transferred are distinct objects')
+ assert_equal(3, transferred.phases.first.sections.length, 'expected 3 sections after upgrading a customised template')
+ end
+
+ test "#upgrade_customization! appends modifiable questions into an unmodifiable section" do
+ init_full_template(@basic_template)
+ customization = @basic_template.customize!(@institution)
+ customization.phases.first.sections.first.questions << Question.new(text: 'New customised question', number: 2, modifiable: true)
+ customization.phases.first.sections.first.questions << Question.new(text: 'New customised question 2', number: 3, modifiable: true)
+
+ transferred = customization.upgrade_customization!
+ assert_not_equal(customization.object_id, transferred.object_id, 'customization and transferred are distinct objects')
+ assert_equal(3, transferred.phases.first.sections.first.questions.length, 'expected 3 questions after upgrading a customised template')
+ end
+
+ test "#upgrade_customization! appends annotations added to an unmodifiable question" do
+ init_full_template(@basic_template)
+ customization = @basic_template.customize!(@institution)
+ customization.phases.first.sections.first.questions.first.annotations <<
+ Annotation.new(text: 'New customised guidance', type: Annotation.types[:guidance], org: customization.org)
+ customization.phases.first.sections.first.questions.first.annotations <<
+ Annotation.new(text: 'New customised example_answer', type: Annotation.types[:example_answer], org: customization.org)
+
+ @basic_template.phases.first.sections.first.questions.first.annotations <<
+ Annotation.new(text: 'New funder guidance', type: Annotation.types[:guidance], org: @basic_template.org)
+ @basic_template.phases.first.sections.first.questions.first.annotations <<
+ Annotation.new(text: 'New funder example_answer', type: Annotation.types[:example_answer], org: @basic_template.org)
+
+ transferred = customization.upgrade_customization!
+ assert_not_equal(customization.object_id, transferred.object_id, 'customization and transferred are distinct objects')
+ assert_equal(4, transferred.phases.first.sections.first.questions.first.annotations.length, 'expected 4 annotations after upgrading a customised template')
+ end
+
+ test "#generate_version? returns true when the template is published" do
+ @basic_template.published = true
+ assert(@basic_template.generate_version?)
+ end
+
+ test "#generate_version? returns false when the template is not published" do
+ @basic_template.published = false
+ assert_not(@basic_template.generate_version?)
+ end
+
+ test "#customize? returns false when no org is passed" do
+ assert_not(@basic_template.customize?(nil))
+ end
+
+ test "#customize? returns false when the template is not owned by a funder or is not the default template" do
+ template = init_template(@institution, { title: 'institutional template', is_default: false })
+ assert_not template.customize?(@funder)
+ end
+
+ test "#customize? returns true when the org does not have a customization of the template" do
+ assert(@basic_template.customize?(@institution))
+ end
+
+ test "#customize? returns false when the org has already a customization of the template" do
+ @basic_template.customize!(@institution)
+ assert_not(@basic_template.customize?(@institution))
+ end
+
+ test "#upgrade_customization? returns false when the template is not a customization of another template" do
+ assert_not(@basic_template.upgrade_customization?)
+ end
+
+ test "#upgrade_customization? returns false when the template is already according to the latest published funder template" do
+ @basic_template.published = true
+ customization = @basic_template.customize!(@institution)
+ assert_not(customization.upgrade_customization?)
+ end
+
+ test "#upgrade_customization? returns true when the template is stale, i.e a new version from funder has been published" do
+ @basic_template.published = true
+ customization = @basic_template.customize!(@institution)
+ customization.created_at = customization.created_at.yesterday
+ new_version = @basic_template.generate_version!
+ new_version.published = true
+ new_version.save!
+ assert(customization.upgrade_customization?)
+ end
+
+ test "default template retains the correct flags when versioned" do
+ @basic_template.update!({ org: @org, published: true, is_default: true, visibility: Template.visibilities[:publicly_visible] })
+ new_version = @basic_template.generate_version!
+ assert_not new_version.published?, 'expected the new version to not be published'
+ assert new_version.is_default?, 'expected the new version to be flagged as the default template'
+ assert new_version.publicly_visible?, 'expected the new version to be publicly visible'
end
- # ---------------------------------------------------
- test "deep copy" do
- verify_deep_copy(@template, ['id', 'created_at', 'updated_at'])
+ test " a customization of the default template is not marked as the default" do
+ @basic_template.update!({ org: @org, published: true, is_default: true, visibility: Template.visibilities[:publicly_visible] })
+ customization = @basic_template.customize!(@institution)
+ assert_not customization.published?, 'expected the customization to not be published'
+ assert_not customization.is_default?, 'expected the customization to not be flagged as the default template'
+ assert_not customization.publicly_visible?, 'expected the customization to not be publicly visible'
end
- # ---------- has_customisations? ----------
- test "has_customisations? correctly identifies if a given org has customised the template" do
- @template.phases.first.modifiable = false
- assert @template.has_customisations?(@org.id, @template), "expected the template to have customisations if it's phase is NOT modifiable"
-
- @template.phases.first.modifiable = true
- assert_not @template.has_customisations?(@org.id, @template), "expected the template to NOT have customisations if it's phase is modifiable"
-
- @template.phases << Phase.new(title: 'New phase test', modifiable: false)
- assert @template.has_customisations?(@org.id, @template), "expected the template to have customisations if all of its phases is NOT modifiable"
-
- @template.phases.last.modifiable = true
- assert_not @template.has_customisations?(@org.id, @template), "expected the template to NOT have customisations if one of its phases is modifiable"
+ test "::find_or_generate_version! raises RuntimeError when attempting to retrieve a historical version for being modified" do
+ @basic_template.generate_version!
+ exception = assert_raises(RuntimeError) do
+ Template.find_or_generate_version!(@basic_template)
+ end
+ assert_equal(_('A historical template cannot be retrieved for being modified'), exception.message)
end
-
- # ---------------------------------------------------
- test "can CRUD Template" do
- tmplt = Template.create(org: @org, version: 1, title: 'Tester')
- assert_not tmplt.id.nil?, "was expecting to be able to create a new Template!"
+ test "::find_or_generate_version! does not generate a new version" do
+ new_template = @basic_template.generate_version!
+ template = Template.find_or_generate_version!(new_template)
+ assert_equal(new_template, template)
+ end
- tmplt.description = 'Testing an update'
- tmplt.save!
- tmplt.reload
- assert_equal 'Testing an update', tmplt.description, "Was expecting to be able to update the description of the Template!"
-
- assert tmplt.destroy!, "Was unable to delete the Template!"
+ test "::find_or_generate_version! generates a new version" do
+ template = Template.find_or_generate_version!(@basic_template)
+ assert_not_equal(@basic_template, template)
+ end
+
+ test "publishing a template automatically unpublishes other versions" do
+ @basic_template.published = true
+ @basic_template.save!
+ v2 = @basic_template.generate_version!
+ v2.published = true
+ v2.save!
+ assert v2.reload.published?, 'expected the new version to be published'
+ assert_not @basic_template.reload.published?, 'expected the old version to be unpublished'
+ end
+
+ test "draft? returns false for a published template" do
+ @basic_template.published = true
+ assert_not @basic_template.draft?
end
- # ---------------------------------------------------
- test "can manage has_many relationship with Phase" do
- phase = Phase.new(title: 'Test Phase', number: 2)
- verify_has_many_relationship(@template, phase, @template.phases.count)
+ test "draft? returns true for an unpublished version of a template that has a published version" do
+ @basic_template.published = true
+ version = @basic_template.generate_version!
+ assert version.draft?
end
- # ---------------------------------------------------
- test "can manage has_many relationship with Plan" do
- plan = Plan.new(title: 'Test Plan', visibility: :is_test)
- verify_has_many_relationship(@template, plan, @template.plans.count)
- end
-
- # ---------------------------------------------------
- test "can manage belongs_to relationship with Org" do
- tmplt = Template.new(title: 'My test', version: 1)
- verify_belongs_to_relationship(tmplt, @org)
- end
-
- test 'should be invalid when links is not a hash' do
- t = Template.new(title: 'My test', version: 1, org: @org)
- t.links = []
- refute(t.valid?)
- assert_equal(['A hash is expected for links'], t.errors.messages[:links])
- end
-
- test 'should be invalid when links hash does not have the expected keys' do
- t = Template.new(title: 'My test', version: 1, org: @org)
- t.links = { "foo" => [], "bar" => [] }
- refute(t.valid?)
- assert_equal(['A key funder is expected for links hash', 'A key sample_plan is expected for links hash'], t.errors.messages[:links])
- end
-
- test 'should be invalid when links hash keys are not compliant to object links format' do
- t = Template.new(title: 'My test', version: 1, org: @org)
- t.links = { "funder" => [{}], "sample_plan" => [{}] }
- refute(t.valid?)
- assert_equal(['The key funder does not have a valid set of object links', 'The key sample_plan does not have a valid set of object links'], t.errors.messages[:links])
- end
-
- test 'should be valid when links hash keys are compliant to object links format' do
- t = Template.new(title: 'My test', version: 1, org: @org)
- t.links = { "funder" => [{ "link" => "foo", "text" => "bar" }], "sample_plan" => [] }
- assert(t.valid?)
- assert_nil t.errors.messages[:links]
- end
-
- test 'should return the latest customizations for the Org' do
- tA = Template.create!(title: 'My test A', version: 0, org: @org)
- tB = Template.create!(title: 'My test B', version: 0, org: @org)
- tC = Template.create!(title: 'My test C', version: 0, org: @org)
-
- # Test 1 - Multiple versions
- cAv0 = Template.create!(title: 'My test customization A', version: 0, customization_of: tA.dmptemplate_id, org: Org.first)
- cAv1 = Template.deep_copy(cAv0)
- cAv1.update_attributes(version: 1)
-
- # Test 2 - Only one version
- cBv0 = Template.create!(title: 'My test customization B', version: 0, customization_of: tB.dmptemplate_id, org: Org.first)
-
- # Test 3 - Make sure it always returns the latest version regardless of published statuses
- cCv0 = Template.create!(title: 'My test customization C', version: 0, customization_of: tC.dmptemplate_id, org: Org.first)
- cCv1 = Template.deep_copy(cCv0)
- cCv1.update_attributes(version: 1, published: true)
- cCv2 = Template.deep_copy(cCv1)
- cCv2.update_attributes(version: 2)
-
- latest = Template.org_customizations([tA, tB, tC].collect(&:dmptemplate_id), Org.first.id)
- assert latest.include?(cAv1), 'expected to get customization A - version 1.'
- assert latest.include?(cBv0), 'expected to get customization B - version 0.'
- assert latest.include?(cCv2), 'expected to get customization C - version 2.'
+ test "draft? returns false for a template that has no published versions" do
+ @basic_template.published = true
+ version = @basic_template.generate_version!
+ @basic_template.update(published: false)
+ assert_not version.draft?
end
end