From e6899d46d8884ad94dbc9374f8c995815d7c8d2e Mon Sep 17 00:00:00 2001
From: SamSeed-Softwire <63662292+SamSeed-Softwire@users.noreply.github.com>
Date: Mon, 6 Nov 2023 17:37:17 +0000
Subject: [PATCH] CLDC-2862: Prepare maintenance page for PaaS app (#2006)
* CLDC-2862: first attempt at creating maintenance page
* CLDC-2907: try turning off maintenance mode to see if tests pass
* CLDC-2862: write tests for MaintenanceController
* CLDC-2862: test header bar links hidden in maintenance mode
* CLDC-2862: lint
* CLDC-2862: add requests tests
* CLDC-2862: try disabling schduled job in maintenance mode
* CLDC-2862: turn on maintenance mode temporarily
* CLDC-2862: turn off maintenance mode again
* CLDC-2862: ensure cookies, notices etc still available in maintenance mode
* CLDC-2862: update content on maintenance page
* CLDC-2862: destroy sidekiq cron jobs on shutdown
* CLDC-2862: turn maintenance mode back on
* CLDC-2862: try destroying cron jobs on startup
* CLDC-2862: try destroying cron jobs on shutdown again, but with fix
* CLDC-2862: turn maintenance mode off again
* CLDC-2862: move job destruction to sidekiq server startup
* CLDC-2862: turn MM back on
* CLDC-2862: turn MM off again
* CLDC-2862: update 'contact the helpdesk' content
* CLDC-2862: check notices/statements still viewable in MM
* CLDC-2862: check cookies page still viewable in MM
* CLDC-2862: confirm cookie banner visible regardless of MM
* CLDC-2862: reenable MM
* CLDC-2862: turn maintenance mode off again
---
app/controllers/application_controller.rb | 9 ++
app/controllers/maintenance_controller.rb | 7 ++
app/services/feature_toggle.rb | 4 +
app/views/layouts/application.html.erb | 12 +--
.../maintenance/service_unavailable.html.erb | 11 +++
config/initializers/sidekiq.rb | 5 +-
config/routes.rb | 1 +
.../maintenance_controller_spec.rb | 27 ++++++
spec/features/user_spec.rb | 13 +++
spec/requests/content_controller_spec.rb | 84 ++++++++++++------
spec/requests/cookies_controller_spec.rb | 42 +++++++++
spec/requests/maintenance_controller_spec.rb | 85 +++++++++++++++++++
12 files changed, 270 insertions(+), 30 deletions(-)
create mode 100644 app/controllers/maintenance_controller.rb
create mode 100644 app/views/maintenance/service_unavailable.html.erb
create mode 100644 spec/controllers/maintenance_controller_spec.rb
create mode 100644 spec/requests/cookies_controller_spec.rb
create mode 100644 spec/requests/maintenance_controller_spec.rb
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index ff085e6dc..ae9e1beb9 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -3,8 +3,17 @@ class ApplicationController < ActionController::Base
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
+ before_action :check_maintenance
before_action :set_paper_trail_whodunnit
+ def check_maintenance
+ if FeatureToggle.maintenance_mode_enabled? && !%w[service-unavailable accessibility-statement privacy-notice cookies].include?(request.fullpath.split("?")[0].delete("/"))
+ redirect_to service_unavailable_path
+ elsif !FeatureToggle.maintenance_mode_enabled? && request.fullpath.split("?")[0].delete("/") == "service-unavailable"
+ redirect_back(fallback_location: root_path)
+ end
+ end
+
def render_not_found
render "errors/not_found", status: :not_found
end
diff --git a/app/controllers/maintenance_controller.rb b/app/controllers/maintenance_controller.rb
new file mode 100644
index 000000000..bb6ae1f80
--- /dev/null
+++ b/app/controllers/maintenance_controller.rb
@@ -0,0 +1,7 @@
+class MaintenanceController < ApplicationController
+ def service_unavailable
+ if current_user
+ sign_out
+ end
+ end
+end
diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb
index 379f51905..3cad5dadb 100644
--- a/app/services/feature_toggle.rb
+++ b/app/services/feature_toggle.rb
@@ -37,4 +37,8 @@ class FeatureToggle
def self.duplicate_summary_enabled?
!Rails.env.production?
end
+
+ def self.maintenance_mode_enabled?
+ false
+ end
end
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index ead90793a..d70c1e09a 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -91,11 +91,13 @@
navigation_classes: "govuk-header__navigation--end",
) do |component|
component.product_name(name: t("service_name"))
- if current_user.nil?
- component.navigation_item(text: "Sign in", href: user_session_path)
- else
- component.navigation_item(text: "Your account", href: account_path)
- component.navigation_item(text: "Sign out", href: destroy_user_session_path)
+ unless FeatureToggle.maintenance_mode_enabled?
+ if current_user.nil?
+ component.navigation_item(text: "Sign in", href: user_session_path)
+ else
+ component.navigation_item(text: "Your account", href: account_path)
+ component.navigation_item(text: "Sign out", href: destroy_user_session_path)
+ end
end
end %>
diff --git a/app/views/maintenance/service_unavailable.html.erb b/app/views/maintenance/service_unavailable.html.erb
new file mode 100644
index 000000000..cb106ce8d
--- /dev/null
+++ b/app/views/maintenance/service_unavailable.html.erb
@@ -0,0 +1,11 @@
+
+ Sorry, the service is unavailable
+
+
+
+
+
You will be able to use the service from 9am on Thursday 16 November 2023.
+
Changes from the page you were on have not been saved. Changes on pages where you have selected 'save and continue' have been saved.
+
<%= govuk_link_to "Contact the helpdesk", "https://dluhcdigital.atlassian.net/servicedesk/customer/portal/6/group/11" %> if you need help.
+
+
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 74e6ce9a2..60cc29b3a 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -32,7 +32,10 @@ Redis.silence_deprecations = true
Sidekiq.configure_server do |config|
config.on(:startup) do
- Sidekiq::Cron::Job.load_from_hash YAML.load_file("config/sidekiq_cron_schedule.yml")
+ Sidekiq::Cron::Job.all.each(&:destroy)
+ unless FeatureToggle.maintenance_mode_enabled?
+ Sidekiq::Cron::Job.load_from_hash YAML.load_file("config/sidekiq_cron_schedule.yml")
+ end
end
config.on(:shutdown) do
diff --git a/config/routes.rb b/config/routes.rb
index 621ee820c..498e7d9a2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -35,6 +35,7 @@ Rails.application.routes.draw do
get "/accessibility-statement", to: "content#accessibility_statement"
get "/privacy-notice", to: "content#privacy_notice"
get "/data-sharing-agreement", to: "content#data_sharing_agreement"
+ get "/service-unavailable", to: "maintenance#service_unavailable"
get "/download-23-24-lettings-form", to: "start#download_23_24_lettings_form"
get "/download-22-23-lettings-form", to: "start#download_22_23_lettings_form"
diff --git a/spec/controllers/maintenance_controller_spec.rb b/spec/controllers/maintenance_controller_spec.rb
new file mode 100644
index 000000000..032ac4858
--- /dev/null
+++ b/spec/controllers/maintenance_controller_spec.rb
@@ -0,0 +1,27 @@
+require "rails_helper"
+
+RSpec.describe MaintenanceController do
+ let(:user) { FactoryBot.create(:user) }
+
+ describe "GET #service_unavailable" do
+ context "when maintenance mode is enabled" do
+ it "logs the user out" do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(true)
+ sign_in user
+ expect(controller).to be_user_signed_in
+ get :service_unavailable
+ expect(controller).not_to be_user_signed_in
+ end
+ end
+
+ context "when maintenance mode is disabled" do
+ it "doesn't log the user out" do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(false)
+ sign_in user
+ expect(controller).to be_user_signed_in
+ get :service_unavailable
+ expect(controller).to be_user_signed_in
+ end
+ end
+ end
+end
diff --git a/spec/features/user_spec.rb b/spec/features/user_spec.rb
index 39327a75a..ca4e01ac6 100644
--- a/spec/features/user_spec.rb
+++ b/spec/features/user_spec.rb
@@ -139,6 +139,12 @@ RSpec.describe "User Features" do
visit("/users/#{user.id}")
expect(page).to have_content("Sign in to your account to submit CORE data")
end
+
+ it "does not show 'Sign in' link if maintenance mode is enabled" do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(true)
+ visit("/lettings-logs")
+ expect(page).not_to have_link("Sign in")
+ end
end
context "when the user is trying to log in with incorrect credentials" do
@@ -324,6 +330,13 @@ RSpec.describe "User Features" do
expect(page).to have_selector('[data-qa="change-data-protection-officer"]')
expect(page).to have_selector('[data-qa="change-key-contact"]')
end
+
+ it "does not show 'Your account' or 'Sign out' links if maintenance mode is enabled" do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(true)
+ visit("/lettings-logs")
+ expect(page).not_to have_link("Your account")
+ expect(page).not_to have_link("Sign out")
+ end
end
context "when adding a new user" do
diff --git a/spec/requests/content_controller_spec.rb b/spec/requests/content_controller_spec.rb
index 07be4256b..c978ecaa9 100644
--- a/spec/requests/content_controller_spec.rb
+++ b/spec/requests/content_controller_spec.rb
@@ -4,45 +4,81 @@ RSpec.describe ContentController, type: :request do
let(:headers) { { "Accept" => "text/html" } }
let(:page) { Capybara::Node::Simple.new(response.body) }
- describe "render privacy notice content page" do
- before do
- get "/privacy-notice", headers:, params: {}
- end
+ describe "when maintenance mode is disabled" do
+ describe "render privacy notice content page" do
+ before do
+ get "/privacy-notice", headers:, params: {}
+ end
- it "returns a 200" do
- expect(response).to have_http_status(:success)
- end
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
- it "returns the page" do
- expect(page).to have_title("Privacy notice")
+ it "returns the page" do
+ expect(page).to have_title("Privacy notice")
+ end
end
- end
- describe "render accessibility statement content page" do
- before do
- get "/accessibility-statement", headers:, params: {}
- end
+ describe "render accessibility statement content page" do
+ before do
+ get "/accessibility-statement", headers:, params: {}
+ end
+
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
- it "returns a 200" do
- expect(response).to have_http_status(:success)
+ it "returns the page" do
+ expect(page).to have_title("Accessibility statement")
+ end
end
- it "returns the page" do
- expect(page).to have_title("Accessibility statement")
+ describe "render data sharing agreement" do
+ before do
+ get "/data-sharing-agreement", headers:, params: {}
+ end
+
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "returns the page" do
+ expect(page).to have_title("Data sharing agreement")
+ end
end
end
- describe "render data sharing agreement" do
+ describe "when maintenance mode is enabled" do
before do
- get "/data-sharing-agreement", headers:, params: {}
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(true)
end
- it "returns a 200" do
- expect(response).to have_http_status(:success)
+ describe "render privacy notice content page" do
+ before do
+ get "/privacy-notice", headers:, params: {}
+ end
+
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "returns the page" do
+ expect(page).to have_title("Privacy notice")
+ end
end
- it "returns the page" do
- expect(page).to have_title("Data sharing agreement")
+ describe "render accessibility statement content page" do
+ before do
+ get "/accessibility-statement", headers:, params: {}
+ end
+
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "returns the page" do
+ expect(page).to have_title("Accessibility statement")
+ end
end
end
end
diff --git a/spec/requests/cookies_controller_spec.rb b/spec/requests/cookies_controller_spec.rb
new file mode 100644
index 000000000..82cf06a10
--- /dev/null
+++ b/spec/requests/cookies_controller_spec.rb
@@ -0,0 +1,42 @@
+require "rails_helper"
+
+RSpec.describe CookiesController, type: :request do
+ let(:headers) { { "Accept" => "text/html" } }
+ let(:page) { Capybara::Node::Simple.new(response.body) }
+
+ describe "when maintenance mode is disabled" do
+ describe "render cookies page" do
+ before do
+ get "/cookies", headers:, params: {}
+ end
+
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "returns the page" do
+ expect(page).to have_title("Cookies")
+ end
+ end
+ end
+
+ describe "when maintenance mode is enabled" do
+ before do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(true)
+ end
+
+ describe "render cookies page" do
+ before do
+ get "/cookies", headers:, params: {}
+ end
+
+ it "returns a 200" do
+ expect(response).to have_http_status(:success)
+ end
+
+ it "returns the page" do
+ expect(page).to have_title("Cookies")
+ end
+ end
+ end
+end
diff --git a/spec/requests/maintenance_controller_spec.rb b/spec/requests/maintenance_controller_spec.rb
new file mode 100644
index 000000000..d900df3c5
--- /dev/null
+++ b/spec/requests/maintenance_controller_spec.rb
@@ -0,0 +1,85 @@
+require "rails_helper"
+
+RSpec.describe MaintenanceController, type: :request do
+ let(:page) { Capybara::Node::Simple.new(response.body) }
+ let(:user) { FactoryBot.create(:user) }
+
+ before do
+ sign_in user
+ end
+
+ describe "when maintenance mode is enabled" do
+ before do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(true)
+ end
+
+ context "when a user visits a page other than the maintenance page" do
+ before do
+ get "/lettings-logs"
+ end
+
+ it "redirects the user to the maintenance page" do
+ expect(response).to redirect_to(service_unavailable_path)
+ follow_redirect!
+ expect(page).to have_content("Sorry, the service is unavailable")
+ end
+
+ it "the cookie banner is visible" do
+ follow_redirect!
+ expect(page).to have_content("We’d like to use analytics cookies so we can understand how you use the service and make improvements.")
+ end
+ end
+
+ context "when a user visits the maintenance page" do
+ before do
+ get "/service-unavailable"
+ end
+
+ it "keeps the user on the maintenance page" do
+ expect(response).not_to redirect_to(service_unavailable_path)
+ expect(page).to have_content("Sorry, the service is unavailable")
+ end
+
+ it "the cookie banner is visible" do
+ expect(page).to have_content("We’d like to use analytics cookies so we can understand how you use the service and make improvements.")
+ end
+ end
+ end
+
+ describe "when maintenance mode is disabled" do
+ before do
+ allow(FeatureToggle).to receive(:maintenance_mode_enabled?).and_return(false)
+ end
+
+ context "when a user visits a page other than the maintenance page" do
+ before do
+ get "/lettings-logs"
+ end
+
+ it "doesn't redirect the user to the maintenance page" do
+ expect(response).not_to redirect_to(service_unavailable_path)
+ expect(page).to have_content("Create a new lettings log")
+ end
+
+ it "the cookie banner is visible" do
+ expect(page).to have_content("We’d like to use analytics cookies so we can understand how you use the service and make improvements.")
+ end
+ end
+
+ context "when a user visits the maintenance page" do
+ before do
+ get "/service-unavailable"
+ end
+
+ it "redirects the user to the start page" do
+ expect(response).to redirect_to(root_path)
+ end
+
+ it "the cookie banner is visible" do
+ follow_redirect!
+ follow_redirect!
+ expect(page).to have_content("We’d like to use analytics cookies so we can understand how you use the service and make improvements.")
+ end
+ end
+ end
+end