From ded06dacf5c110189323a19a7c7995fda1e621d8 Mon Sep 17 00:00:00 2001 From: Cristina <579522+CristinaRO@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:42:43 +0100 Subject: [PATCH] Allow admins to delete a site and all its data This doesn't have to be the final shape of this feature, but it should be enough to enable us to think about where to go next. Allows admins to delete a site via the interface. In the next iteration we will use a custom permission, but Joe might already be working as part of his story, so we should coordinate this. I've opted for a two-step, JavaScript-free process, for simplicity. I've also opted for a GitHub-style confirmation prompt, where rather than a yes/no question, the user has to input some text (the site slug AKA abbreviation in our case) to confirm a destructive action. --- app/controllers/sites_controller.rb | 21 +++++++++++ app/views/sites/confirm_destroy.html.erb | 36 +++++++++++++++++++ app/views/sites/show.html.erb | 6 ++++ config/routes.rb | 5 ++- features/site.feature | 22 ++++++++++++ .../step_definitions/site_assertion_steps.rb | 12 +++++++ .../site_interaction_steps.rb | 14 ++++++++ spec/controllers/sites_controller_spec.rb | 21 +++++++++++ 8 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 app/views/sites/confirm_destroy.html.erb diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index 67385105a..fd2033228 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -1,6 +1,9 @@ +require "./lib/transition/import/revert_entirely_unsafe" + class SitesController < ApplicationController before_action :find_site before_action :check_user_is_gds_editor, only: %i[edit update] + before_action :check_user_is_admin, only: %i[confirm_destroy destroy] def edit; end @@ -18,6 +21,17 @@ def show @unresolved_mappings_count = @site.mappings.unresolved.count end + def confirm_destroy; end + + def destroy + if params[:confirm_destroy] == @site.abbr + Transition::Import::RevertEntirelyUnsafe::RevertSite.new(@site).revert_all_data! + redirect_to organisation_path(@site.organisation), flash: { success: "The site and all its data have been successfully deleted" } + else + redirect_to confirm_destroy_site_path(@site), flash: { alert: "The confirmation did not match" } + end + end + private def find_site @@ -34,4 +48,11 @@ def check_user_is_gds_editor redirect_to site_path(@site), alert: message end end + + def check_user_is_admin + unless current_user.admin? + message = "Only admins can access that." + redirect_to site_path(@site), alert: message + end + end end diff --git a/app/views/sites/confirm_destroy.html.erb b/app/views/sites/confirm_destroy.html.erb new file mode 100644 index 000000000..09c356f23 --- /dev/null +++ b/app/views/sites/confirm_destroy.html.erb @@ -0,0 +1,36 @@ +<% content_for(:page_title, @site.default_host.hostname) %> + +
+

+ <%= @site.default_host.hostname %> +
+ Delete this site and all its associated data +

+
+ +
+
+ WAIT! +
+
+ This will delete all data that is associated with this site. +
+
+ +<%= form_for @site, method: :delete, html: { role: 'form' } do |f| %> +
+
+
+
+
+ <%= label_tag :confirm_destroy, 'Please enter the site slug to confirm that you want to delete this site and all its data.' %> +
+
+ <%= text_field_tag(:confirm_destroy, {}, { class: 'form-control input' }) %> +
+
+
+ <%= f.submit 'Delete', class: 'add-top-margin btn btn-danger' %> +
+
+<% end %> diff --git a/app/views/sites/show.html.erb b/app/views/sites/show.html.erb index 4404c7b76..951668603 100644 --- a/app/views/sites/show.html.erb +++ b/app/views/sites/show.html.erb @@ -30,5 +30,11 @@ <%= link_to 'Edit date', edit_site_path(@site), class: 'link-inherit' %> <% end %> + + <% if current_user.admin? %> +
+ <%= link_to 'Delete', confirm_destroy_site_path(@site) %> +
+ <% end %> diff --git a/config/routes.rb b/config/routes.rb index fa5ba4951..9a9273411 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,7 +27,10 @@ get "leaderboard", to: "leaderboard#index" - resources :sites, only: %i[edit update show] do + resources :sites, only: %i[edit update show destroy] do + member do + get :confirm_destroy + end get "mappings/find", as: "mapping_find" resources :mappings, only: %i[index edit update] do resources :versions, only: [:index] diff --git a/features/site.feature b/features/site.feature index 485257052..e3bdcb8ca 100644 --- a/features/site.feature +++ b/features/site.feature @@ -120,3 +120,25 @@ Scenario: Editing a site's transition date as a non-GDS Editor When I visit the path /sites/dclg/edit Then I should be redirected to the site dashboard And I should see "Only GDS Editors can access that." + +Scenario: Deleting a site as an admin + Given I have logged in as an admin + And a site bis exists + And I visit this site page + When I delete this site + Then I should be prompted to confirm the deletion + When I fail to confirm the deletion + Then I should see "The confirmation did not match" + And I should be prompted to confirm the deletion + When I confirm the deletion + Then I should be redirected to the organisation dashboard + And I should see the deletion confirmation message + +Scenario: Deleting a site as a non-admin + Given I have logged in as a member of DCLG + And a site dclg exists + And I visit this site page + Then I should not see "Delete" + When I visit the path /sites/dclg/confirm_destroy + Then I should be redirected to the site dashboard + And I should see "Only admins can access that." diff --git a/features/step_definitions/site_assertion_steps.rb b/features/step_definitions/site_assertion_steps.rb index a569744f5..d432de127 100644 --- a/features/step_definitions/site_assertion_steps.rb +++ b/features/step_definitions/site_assertion_steps.rb @@ -86,3 +86,15 @@ end end end + +Then(/^I should be prompted to confirm the deletion$/) do + step("I should see \"confirm that you want to delete this site and all its data\"") +end + +Then(/^I should see the deletion confirmation message$/) do + expect(page).to have_content("The site and all its data have been successfully deleted") +end + +Then(/^I should be redirected to the organisation dashboard$/) do + i_should_be_on_the_path organisation_path(@site.organisation) +end diff --git a/features/step_definitions/site_interaction_steps.rb b/features/step_definitions/site_interaction_steps.rb index 5c3e09bd7..6069a4e3d 100644 --- a/features/step_definitions/site_interaction_steps.rb +++ b/features/step_definitions/site_interaction_steps.rb @@ -9,3 +9,17 @@ select("20", from: "site_launch_date_3i") click_button "Save" end + +When(/^I delete this site$/) do + click_link "Delete" +end + +When(/^I confirm the deletion$/) do + fill_in :confirm_destroy, with: @site.abbr + click_button "Delete" +end + +When(/^I fail to confirm the deletion$/) do + fill_in :confirm_destroy, with: "bogus" + click_button "Delete" +end diff --git a/spec/controllers/sites_controller_spec.rb b/spec/controllers/sites_controller_spec.rb index 91731622e..90d466a19 100644 --- a/spec/controllers/sites_controller_spec.rb +++ b/spec/controllers/sites_controller_spec.rb @@ -3,6 +3,7 @@ describe SitesController do let(:site) { create :site, abbr: "moj" } let(:gds_bob) { create(:gds_editor, name: "Bob Terwhilliger") } + let(:admin) { create(:admin) } describe "#edit" do context "when the user does have permission" do @@ -24,4 +25,24 @@ def make_request it_behaves_like "disallows editing by non-GDS Editors" end end + + describe "#confirm_destroy" do + context "when the user does have permission" do + before { login_as admin } + + it "displays the form" do + get :confirm_destroy, params: { id: site.abbr } + expect(response.status).to eql(200) + end + end + + context "when the user does not have permission" do + before { login_as stub_user } + + it "disallows deleting by non-admins" do + get :confirm_destroy, params: { id: site.abbr } + expect(response.status).to eql(302) + end + end + end end