diff --git a/app/controllers/super_admin/themes_controller.rb b/app/controllers/super_admin/themes_controller.rb index f1fbc6c..0dee094 100644 --- a/app/controllers/super_admin/themes_controller.rb +++ b/app/controllers/super_admin/themes_controller.rb @@ -52,6 +52,18 @@ redirect_to(action: :index) end + def destroy + authorize(Theme) + begin + Theme.find(params[:id]).destroy! + flash[:notice] = _('Theme destroyed successfully') + rescue ActiveRecord::RecordNotFound + flash[:alert] = _('There is no theme associated with id %{id}') % { :id => params[:id] } + rescue ActiveRecord::RecordNotDestroyed # Unlikely to happen since we don't have callback associated to destroy! but put for safety + flash[:alert] = _('The theme with id %{id} could not be destroyed') % { :id => params[:id] } + end + redirect_to(action: :index) + end # Private instance methods private diff --git a/app/policies/theme_policy.rb b/app/policies/theme_policy.rb index d7b7895..3767696 100644 --- a/app/policies/theme_policy.rb +++ b/app/policies/theme_policy.rb @@ -18,4 +18,7 @@ def update? @user.can_super_admin? end + def destroy? + @user.can_super_admin? + end end diff --git a/app/views/paginable/plans/_privately_visible.html.erb b/app/views/paginable/plans/_privately_visible.html.erb index 1deafb2..326118a 100644 --- a/app/views/paginable/plans/_privately_visible.html.erb +++ b/app/views/paginable/plans/_privately_visible.html.erb @@ -33,8 +33,9 @@ <%= display_role(plan.roles.find_by(user: current_user)) %> <% if plan.administerable_by?(current_user.id) then %> - <%= form_for plan, url: set_test_plan_path(plan), html: {method: :post, id: 'update-test-plan'} do |f| %> + <%= form_for plan, url: set_test_plan_path(plan), html: { method: :post, class: 'set_test_plan', remote: true } do |f| %> <%= check_box_tag(:is_test, "1", (plan.visibility === 'is_test')) %> + <%= f.submit(_('Update'), style: 'display:none') %> <% end %> <% else %> <%= plan.visibility === 'is_test' ? _('Yes') : _('No') %> @@ -68,8 +69,7 @@
  • <%= link_to _('Download'), download_plan_path(plan) %>
  • -
  • <%= link_to _('Make a copy'), duplicate_plan_path(plan), - method: :post, remote: true %>
  • +
  • <%= link_to(_('Make a copy'), duplicate_plan_path(plan), data: { method: :post }) %>
  • <% else %>
  • <%= link_to _('View'), plan_path(plan) %>
  • @@ -78,7 +78,7 @@ <% role = plan.roles.where(user_id: current_user.id).first %> <% conf = (role.creator? && plan.publicly_visible?) ? _("Are you sure you wish to remove this public plan? This will remove it from the Public DMPs page but any collaborators will still be able to access it.") : _("Are you sure you wish to remove this plan? Any collaborators will still be able to access it.") %>
  • <%= link_to _('Remove'), deactivate_role_path(role), - method: :put, data: {confirm: conf} %>
  • + method: :put, data: { confirm: conf } %> diff --git a/app/views/plans/_share_form.html.erb b/app/views/plans/_share_form.html.erb index 8d5f202..0cff2c1 100644 --- a/app/views/plans/_share_form.html.erb +++ b/app/views/plans/_share_form.html.erb @@ -1,7 +1,7 @@

    <%= _('Set plan visibility') %>

    <%= _('Public or organisational visibility is intended for finished plans. You must answer at least one question to enable these options.') %>

    <% allow_visibility = @plan.visibility_allowed? %> -<%= form_for(@plan, url: visibility_plan_path, method: :post, html: { id: 'set_visibility'}) do |f| %> +<%= form_for(@plan, url: visibility_plan_path, method: :post, html: { id: 'set_visibility', remote: true }) do |f| %> >
    @@ -15,6 +15,9 @@ <%= f.label :visibility_publicly_visible, raw("#{f.radio_button :visibility, :publicly_visible} #{_('Public: anyone can view')}") %>
    +
    + <%= f.submit(_('Update'), style: 'display:none') %> +
    <% end %> diff --git a/app/views/super_admin/themes/new_edit.html.erb b/app/views/super_admin/themes/new_edit.html.erb index 16a3b35..ca5c4a2 100644 --- a/app/views/super_admin/themes/new_edit.html.erb +++ b/app/views/super_admin/themes/new_edit.html.erb @@ -16,6 +16,13 @@
    <%= f.button(_('Save'), class: "btn btn-default", type: "submit") %> + <%= link_to( + _('Delete'), + super_admin_theme_path(theme), + class: 'btn btn-default', + rel: 'nofollow', + 'data-method': 'delete', + 'data-confirm': _("Are you sure you want to delete the theme \"%{title}\"?") %{ :title => theme.title }) if options[:method] == :PUT %> <%= link_to(_('Cancel'), super_admin_themes_path, class: 'btn btn-default', role: 'button') %>
    <% end %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index c66fa7d..310794e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -287,6 +287,6 @@ end namespace :super_admin do - resources :themes, only: [:index, :new, :create, :edit, :update] + resources :themes, only: [:index, :new, :create, :edit, :update, :destroy] end end diff --git a/lib/assets/javascripts/application.js b/lib/assets/javascripts/application.js index 415992b..5730159 100644 --- a/lib/assets/javascripts/application.js +++ b/lib/assets/javascripts/application.js @@ -1,7 +1,6 @@ // Generic JS that is applicable across multiple pages import './utils/paginable'; import './utils/panelHeading'; -import './utils/linkHelper'; import './utils/links'; import './utils/tabHelper'; import './utils/tableHelper'; @@ -44,5 +43,5 @@ import './views/shared/create_account_form'; import './views/shared/my_org'; import './views/shared/sign_in_form'; -import './views/themes/new_edit'; +import './views/super_admin/themes/new_edit'; import './views/users/notification_preferences'; diff --git a/lib/assets/javascripts/utils/linkHelper.js b/lib/assets/javascripts/utils/linkHelper.js deleted file mode 100644 index 43236ce..0000000 --- a/lib/assets/javascripts/utils/linkHelper.js +++ /dev/null @@ -1,25 +0,0 @@ -import { isString } from './isType'; - -$(() => { - const restfulLinks = $('a[data-method]'); - - restfulLinks.map((idx, el) => { - const method = $(el).attr('data-method'); - const target = $(el).attr('href'); - const token = $('meta[name="csrf-token"]').attr('content'); - - if (isString(method) && isString(target)) { - const html = `
    - - -
    `; - $(el).append(html); - - $(el).click((e) => { - e.preventDefault(); - $(e.currentTarget).find('form').submit(); - }); - } - return true; - }); -}); diff --git a/lib/assets/javascripts/views/plans/index.js b/lib/assets/javascripts/views/plans/index.js index 1429bba..8e9bf88 100644 --- a/lib/assets/javascripts/views/plans/index.js +++ b/lib/assets/javascripts/views/plans/index.js @@ -7,37 +7,30 @@ } from '../../constants'; $(() => { - const checkboxHandler = (el) => { - const form = $(el).closest('form'); + $('.set_test_plan input[type="checkbox"]').on('click, change', (e) => { + const form = $(e.target).closest('form'); + form.submit(); + }); + $('.set_test_plan').on('ajax:success', (e, data) => { + const form = $(e.target); + if (data.code === 1 && data.msg && data.msg !== '') { + notifier.renderNotice(data.msg); + } else { + notifier.renderAlert(data.msg); + } - $.ajax({ - method: $(form).attr('method'), - url: $(form).attr('action'), - data: $(form).serializeArray(), - }).done((data) => { - if (data.code === 1 && data.msg && data.msg !== '') { - notifier.renderNotice(data.msg); - } else { - notifier.renderAlert(data.msg); - } - - if ($(el).is(':checked')) { - $(form).parent().siblings('.plan-visibility').html(PLAN_VISIBILITY_WHEN_TEST) - .attr('title', ''); - } else { - $(form).parent().siblings('.plan-visibility').html(PLAN_VISIBILITY_WHEN_NOT_TEST) - .attr('title', PLAN_VISIBILITY_WHEN_NOT_TEST_TOOLTIP); - } - }, () => { - // TODO adequate error handling for network error - }); - }; - - $("#my-plans input[type='checkbox']").on('click, change', (e) => { - checkboxHandler(e.currentTarget); + if (form.find('input[type="checkbox"]').is(':checked')) { + form.parent().siblings('.plan-visibility').html(PLAN_VISIBILITY_WHEN_TEST) + .attr('title', ''); + } else { + form.parent().siblings('.plan-visibility').html(PLAN_VISIBILITY_WHEN_NOT_TEST) + .attr('title', PLAN_VISIBILITY_WHEN_NOT_TEST_TOOLTIP); + } + }); + $('.set_test_plan').on('ajax:error', () => { + // TODO adequate error handling for network error }); }); - // Attach the tablesorter and filter to all tables with those selectors $(() => { collateTable({ selector: 'table.tablesorter' }); diff --git a/lib/assets/javascripts/views/plans/share.js b/lib/assets/javascripts/views/plans/share.js index b061775..fcc018c 100644 --- a/lib/assets/javascripts/views/plans/share.js +++ b/lib/assets/javascripts/views/plans/share.js @@ -6,27 +6,19 @@ // Invite Collaborators form on the Share page ariatiseForm({ selector: '#new_role' }); - const request = (el) => { - const form = $(el).closest('form'); - return $.ajax({ - method: $(form).attr('method'), - url: $(form).attr('action'), - data: $(form).serializeArray(), - dataType: 'json', - }); - }; - $('#set_visibility [name="plan[visibility]"]').click((e) => { - request(e.target).then((data) => { - if (isObject(data) && isString(data.msg)) { - notifier.renderNotice(data.msg); - } - }, (jqXHR, textStatus) => { - if (isObject(jqXHR.responseJSON)) { - notifier.renderAlert(jqXHR.responseJSON.msg); - } else { - notifier.renderAlert(textStatus); - } - }); + $(e.target).closest('form').submit(); + }); + $('#set_visibility').on('ajax:success', (e, data) => { + if (isObject(data) && isString(data.msg)) { + notifier.renderNotice(data.msg); + } + }); + $('#set_visibility').on('ajax:error', (e, xhr) => { + if (isObject(xhr.responseJSON)) { + notifier.renderAlert(xhr.responseJSON.msg); + } else { + notifier.renderAlert(`${xhr.statusCode} - ${xhr.statusText}`); + } }); }); diff --git a/lib/assets/javascripts/views/super_admin/themes/new_edit.js b/lib/assets/javascripts/views/super_admin/themes/new_edit.js new file mode 100644 index 0000000..d5cd530 --- /dev/null +++ b/lib/assets/javascripts/views/super_admin/themes/new_edit.js @@ -0,0 +1,7 @@ +import ariatiseForm from '../../../utils/ariatiseForm'; +import { Tinymce } from '../../../utils/tinymce'; + +$(() => { + ariatiseForm({ selector: 'form.theme' }); + Tinymce.init({ selector: '#theme_description' }); +}); diff --git a/lib/assets/javascripts/views/themes/new_edit.js b/lib/assets/javascripts/views/themes/new_edit.js deleted file mode 100644 index 0ee3315..0000000 --- a/lib/assets/javascripts/views/themes/new_edit.js +++ /dev/null @@ -1,7 +0,0 @@ -import ariatiseForm from '../../utils/ariatiseForm'; -import { Tinymce } from '../../utils/tinymce'; - -$(() => { - ariatiseForm({ selector: 'form.theme' }); - Tinymce.init({ selector: '#theme_description' }); -}); diff --git a/test/functional/super_admin/themes_controller.test.rb b/test/functional/super_admin/themes_controller.test.rb index 815fdb4..b31559e 100644 --- a/test/functional/super_admin/themes_controller.test.rb +++ b/test/functional/super_admin/themes_controller.test.rb @@ -98,4 +98,20 @@ assert_response :redirect assert_equal(_('Theme updated successfully'), flash[:notice]) end + test 'destroy action responds redirect when user is not super_admin' do + delete(super_admin_theme_path({ id: Theme.first.id })) + assert_response :redirect + end + test 'destroy action responds redirect when theme id does not exist' do + sign_in @user + delete(super_admin_theme_path({ id: 'foo' })) + assert_response :redirect + assert_equal(_('There is no theme associated with id %{id}') % { :id => 'foo' }, flash[:alert]) + end + test 'destroy action responds redirect with flash notice' do + sign_in @user + delete(super_admin_theme_path({ id: Theme.first.id })) + assert_response :redirect + assert_equal(_('Theme destroyed successfully'), flash[:notice]) + end end \ No newline at end of file