Browse Source
* CLDC-3387: Allow support users to create notifications * Refactor rendering * Adjust notifications helper * Add rubocop ignore * Fix path checks around notification viewing * Notification path regex should work on review apps * Tidy * Remove unused function * Reference external url in link to markdown syntax guide * CLDC-3614: Allow markdown page content when creating notifications (#2622) * CLDC-3614: Allow markdown page content when creating notifications * Try using beginning of day for time in failing test * Remove ignored breaks * Add paper trail to notifications * CLDC-3607: Allow support users to delete notifications (by setting their end date) (#2630) * CLDC-3607: Allow support users to delete notifications (by setting their end date) * Refactor render_for_page helper * Move db queries to homepage presenter * Fix lint * Use a before_action to find notification in controller * Make delete notification links red * Tweak link to markdown guide * Open markdown guide in new tabpull/2634/head^2
Rachael Booth
4 months ago
committed by
GitHub
27 changed files with 592 additions and 47 deletions
@ -1,19 +1,93 @@
|
||||
class NotificationsController < ApplicationController |
||||
before_action :authenticate_user!, except: %i[show] |
||||
before_action :authenticate_scope!, except: %i[show dismiss] |
||||
before_action :find_notification, except: %i[new create] |
||||
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found |
||||
|
||||
def dismiss |
||||
if current_user.blank? |
||||
redirect_to root_path |
||||
else |
||||
current_user.newest_active_unread_notification.mark_as_read! for: current_user if current_user.newest_active_unread_notification.present? |
||||
redirect_back(fallback_location: root_path) |
||||
end |
||||
@notification.mark_as_read! for: current_user |
||||
redirect_back(fallback_location: root_path) |
||||
end |
||||
|
||||
def show |
||||
@notification = current_user&.newest_active_unread_notification || Notification.newest_active_unauthenticated_notification |
||||
if @notification&.page_content |
||||
if !@notification.show_on_unauthenticated_pages && !current_user |
||||
render_not_found and return |
||||
end |
||||
|
||||
if @notification.show_additional_page |
||||
render "show" |
||||
else |
||||
redirect_back(fallback_location: root_path) |
||||
end |
||||
end |
||||
|
||||
def new |
||||
@notification = Notification.new |
||||
end |
||||
|
||||
def create |
||||
@notification = Notification.new(notification_model_params) |
||||
|
||||
if @notification.errors.empty? && @notification.save |
||||
redirect_to notification_check_answers_path(@notification) |
||||
else |
||||
render :new, status: :unprocessable_entity |
||||
end |
||||
end |
||||
|
||||
def update |
||||
start_now = params[:notification][:start_now] |
||||
|
||||
if @notification.errors.empty? && @notification.update(notification_model_params) |
||||
if start_now |
||||
flash[:notice] = "The notification has been created" |
||||
redirect_to root_path |
||||
else |
||||
redirect_to notification_check_answers_path(@notification) |
||||
end |
||||
elsif start_now |
||||
render :check_answers, status: :unprocessable_entity |
||||
else |
||||
render :edit, status: :unprocessable_entity |
||||
end |
||||
end |
||||
|
||||
def delete |
||||
@notification.update!(end_date: Time.zone.now) |
||||
flash[:notice] = "The notification has been deleted" |
||||
redirect_to root_path |
||||
end |
||||
|
||||
private |
||||
|
||||
def notification_params |
||||
params.require(:notification).permit(:title, :show_on_unauthenticated_pages, :show_additional_page, :link_text, :page_content, :start_now) |
||||
end |
||||
|
||||
def authenticate_scope! |
||||
render_not_found unless current_user.support? |
||||
end |
||||
|
||||
def notification_model_params |
||||
model_params = notification_params.except(:start_now) |
||||
|
||||
if notification_params[:show_additional_page] == "0" |
||||
model_params[:link_text] = nil |
||||
model_params[:page_content] = nil |
||||
end |
||||
|
||||
model_params[:start_date] = Time.zone.now if notification_params[:start_now] |
||||
|
||||
model_params |
||||
end |
||||
|
||||
def find_notification |
||||
id = params[:id] || params[:notification_id] |
||||
@notification = current_user&.support? ? Notification.find_by(id:) : Notification.active.find_by(id:) |
||||
|
||||
raise ActiveRecord::RecordNotFound unless @notification |
||||
|
||||
@notification |
||||
end |
||||
end |
||||
|
@ -0,0 +1,33 @@
|
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-two-thirds"> |
||||
<%= f.govuk_error_summary %> |
||||
|
||||
<% content_for :page_title, "Create a new notification" %> |
||||
|
||||
<% content_for :before_content do %> |
||||
<%= govuk_back_link(href: :back) %> |
||||
<% end %> |
||||
|
||||
<h1 class="govuk-heading-l"> |
||||
<%= content_for(:page_title) %> |
||||
</h1> |
||||
|
||||
<span class="govuk-caption-m govuk-!-margin-bottom-6">This notification will be visible to all users until you delete it</span> |
||||
|
||||
<%= f.govuk_text_field :title, |
||||
label: { text: "Title", size: "m" }, |
||||
hint: { text: "Use markdown for links to existing pages" } %> |
||||
|
||||
<%= f.govuk_check_boxes_fieldset :display_options, multiple: false, legend: { text: "Display Options" } do %> |
||||
<%= f.govuk_check_box :show_on_unauthenticated_pages, 1, 0, multiple: false, label: { text: "Show this notification on unauthenticated pages, for example the start page" } %> |
||||
<%= f.govuk_check_box :show_additional_page, 1, 0, multiple: false, label: { text: "Include a link to a separate page with additional information" } do %> |
||||
<%= f.govuk_text_field :link_text, label: { text: "Link text" }, hint: { text: "Use descriptive language and relevant terms. The link text should make sense out of context." } %> |
||||
<%= f.govuk_text_area :page_content, label: { text: "Page content" }, hint: { text: "Use markdown to format the page content. The page title will be the notification title by default. Use a heading level one if you want to override it." } %> |
||||
<% end %> |
||||
<% end %> |
||||
|
||||
<span class="govuk-caption-m govuk-!-margin-bottom-6"><%= govuk_link_to "Find out more about using Markdown at Markdown Guide", "https://www.markdownguide.org/basic-syntax/", new_tab: true %></span> |
||||
|
||||
<%= f.govuk_submit "Continue" %> |
||||
</div> |
||||
</div> |
@ -0,0 +1,17 @@
|
||||
<div class="govuk-grid-row"> |
||||
<p class="govuk-!-font-weight-bold"><%== I18n.t("active_notifications", count: active_notifications.count) %></p> |
||||
<% active_notifications.each do |notification| %> |
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-three-quarters"> |
||||
<%== render_for_home(notification) %> |
||||
</div> |
||||
<div class="govuk-grid-column-one-quarter"> |
||||
<%= govuk_link_to("Delete notification", notification_delete_confirmation_path(notification), class: "app-!-colour-red") %> |
||||
</div> |
||||
</div> |
||||
<% end %> |
||||
</div> |
||||
|
||||
<div class="govuk-grid-row"> |
||||
<%= govuk_button_link_to "Create a new notification", new_notification_path %> |
||||
</div> |
@ -0,0 +1,61 @@
|
||||
<% content_for :title, "Create a notification" %> |
||||
|
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-three-quarters-from-desktop"> |
||||
<% content_for :before_content do %> |
||||
<%= govuk_back_link(href: :back) %> |
||||
<% end %> |
||||
|
||||
<h1 class="govuk-heading-l"> |
||||
<span class="govuk-caption-l">Create a notification</span> |
||||
Check your answers |
||||
</h1> |
||||
|
||||
<span class="govuk-caption-m govuk-!-margin-bottom-6">This notification will be visible to all users until you delete it</span> |
||||
|
||||
<%= form_for(@notification, method: :patch) do |f| %> |
||||
<%= f.govuk_error_summary %> |
||||
|
||||
<div class="govuk-summary-card"> |
||||
<div class="govuk-summary-card__content"> |
||||
<%= govuk_summary_list do |summary_list| %> |
||||
<% summary_list.with_row do |row| %> |
||||
<% row.with_key { "Title" } %> |
||||
<% row.with_value do %> |
||||
<%== render_for_summary(@notification.title) %> |
||||
<% end %> |
||||
<% row.with_action(text: "Change", href: edit_notification_path(@notification)) %> |
||||
<% end %> |
||||
<% summary_list.with_row do |row| %> |
||||
<% row.with_key { "Show on unauthenticated pages?" } %> |
||||
<% row.with_value { @notification.show_on_unauthenticated_pages ? "Yes" : "No" } %> |
||||
<% row.with_action(text: "Change", href: edit_notification_path(@notification)) %> |
||||
<% end %> |
||||
<% summary_list.with_row do |row| %> |
||||
<% row.with_key { "Link to additional information?" } %> |
||||
<% row.with_value { @notification.show_additional_page ? "Yes" : "No" } %> |
||||
<% row.with_action(text: "Change", href: edit_notification_path(@notification)) %> |
||||
<% end %> |
||||
<% if @notification.show_additional_page %> |
||||
<% summary_list.with_row do |row| %> |
||||
<% row.with_key { "Link text" } %> |
||||
<% row.with_value { @notification.link_text } %> |
||||
<% row.with_action(text: "Change", href: edit_notification_path(@notification)) %> |
||||
<% end %> |
||||
<% summary_list.with_row do |row| %> |
||||
<% row.with_key { "Page content" } %> |
||||
<% row.with_value do %> |
||||
<%= govuk_link_to "View page preview", notification_path(@notification), new_tab: true %> |
||||
<% end %> |
||||
<% row.with_action(text: "Change", href: edit_notification_path(@notification)) %> |
||||
<% end %> |
||||
<% end %> |
||||
<% end %> |
||||
</div> |
||||
</div> |
||||
|
||||
<%= f.hidden_field :start_now, value: true %> |
||||
<%= f.govuk_submit "Create notification" %> |
||||
<% end %> |
||||
</div> |
||||
</div> |
@ -0,0 +1,27 @@
|
||||
<% content_for :before_content do %> |
||||
<% content_for :title, "Are you sure you want to delete this notification?" %> |
||||
<%= govuk_back_link(href: :back) %> |
||||
<% end %> |
||||
|
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-two-thirds-from-desktop"> |
||||
<h1 class="govuk-heading-xl"> |
||||
<%= content_for(:title) %> |
||||
</h1> |
||||
|
||||
<p class="govuk-body"><%== render_for_summary("**Notification:** #{@notification.title}") %></p> |
||||
|
||||
<p class="govuk-body">Users will no longer see this notification.</p> |
||||
|
||||
<%= govuk_warning_text(text: "You will not be able to undo this action.") %> |
||||
|
||||
<div class="govuk-button-group"> |
||||
<%= govuk_button_to( |
||||
"Delete notification", |
||||
notification_delete_path(@notification), |
||||
method: :delete, |
||||
) %> |
||||
<%= govuk_button_link_to "Cancel", root_path, html: { method: :get }, secondary: true %> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,3 @@
|
||||
<%= form_for(@notification, as: :notification, method: :patch) do |f| %> |
||||
<% render partial: "form", locals: { notification: @notification, f: } %> |
||||
<% end %> |
@ -0,0 +1,3 @@
|
||||
<%= form_for(@notification, as: :notification, method: :post) do |f| %> |
||||
<% render partial: "form", locals: { notification: @notification, f: } %> |
||||
<% end %> |
@ -0,0 +1,5 @@
|
||||
class AddShowAdditionalPageColumnToNotifications < ActiveRecord::Migration[7.0] |
||||
def change |
||||
add_column :notifications, :show_additional_page, :boolean |
||||
end |
||||
end |
@ -0,0 +1,37 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe Notification, type: :model do |
||||
describe "#valid?" do |
||||
context "when show additional page is true" do |
||||
context "and page_content is blank" do |
||||
let(:notification) { build(:notification, show_additional_page: true, page_content: "") } |
||||
|
||||
it "adds an error to page_content" do |
||||
notification.valid? |
||||
|
||||
expect(notification.errors[:page_content]).to include("Enter the page content") |
||||
end |
||||
end |
||||
|
||||
context "and link_text is blank" do |
||||
let(:notification) { build(:notification, show_additional_page: true, link_text: nil) } |
||||
|
||||
it "adds an error to link_text" do |
||||
notification.valid? |
||||
|
||||
expect(notification.errors[:link_text]).to include("Enter the link text") |
||||
end |
||||
end |
||||
end |
||||
|
||||
context "when show additional page is false" do |
||||
context "and page_content and link_text are blank" do |
||||
let(:notification) { build(:notification, show_additional_page: false, link_text: nil, page_content: nil) } |
||||
|
||||
it "is valid" do |
||||
expect(notification).to be_valid |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,163 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe NotificationsController, type: :request do |
||||
context "when user is signed in as a support user" do |
||||
let(:support_user) { create(:user, :support) } |
||||
|
||||
before do |
||||
allow(support_user).to receive(:need_two_factor_authentication?).and_return(false) |
||||
sign_in support_user |
||||
end |
||||
|
||||
describe "#create" do |
||||
let(:request) { post notifications_path, params: params } |
||||
|
||||
context "with valid parameters" do |
||||
let(:params) { { "notification": { title: "Test Create", show_on_unauthenticated_pages: "1", show_additional_page: "1", link_text: "link", page_content: "page" } } } |
||||
|
||||
it "creates a new notification with no start date set" do |
||||
request |
||||
notification = Notification.find_by(title: "Test Create") |
||||
expect(notification.show_on_unauthenticated_pages).to be(true) |
||||
expect(notification.show_additional_page).to be(true) |
||||
expect(notification.link_text).to eq("link") |
||||
expect(notification.page_content).to eq("page") |
||||
expect(notification.start_date).to be_nil |
||||
end |
||||
|
||||
it "redirects to check answers page" do |
||||
request |
||||
notification = Notification.find_by(title: "Test Create") |
||||
expect(response).to redirect_to(notification_check_answers_path(notification)) |
||||
end |
||||
end |
||||
|
||||
context "with invalid parameters" do |
||||
let(:params) { { "notification": { title: "", show_on_unauthenticated_pages: "1" } } } |
||||
|
||||
it "gives an error response" do |
||||
request |
||||
expect(response).to have_http_status(:unprocessable_entity) |
||||
end |
||||
end |
||||
|
||||
context "when show additional page is false" do |
||||
let(:params) { { "notification": { title: "No Additional Page", show_on_unauthenticated_pages: "1", show_additional_page: "0", link_text: "text", page_content: "content" } } } |
||||
|
||||
it "ignores values for link_text and page_content" do |
||||
request |
||||
notification = Notification.find_by(title: "No Additional Page") |
||||
expect(notification.link_text).to be_nil |
||||
expect(notification.page_content).to be_nil |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "#update" do |
||||
let(:notification) { create(:notification, title: "Initial Title", start_date: nil, end_date: nil) } |
||||
let(:request) { patch notification_path(notification), params: params } |
||||
|
||||
context "when start_now is set to true" do |
||||
let(:params) { { "notification": { start_now: true } } } |
||||
|
||||
it "sets the start date on the notification" do |
||||
request |
||||
notification.reload |
||||
expect(notification.start_date).not_to be_nil |
||||
expect(notification.start_date).to be < Time.zone.now |
||||
end |
||||
|
||||
it "redirects to the home page" do |
||||
request |
||||
expect(response).to redirect_to(root_path) |
||||
end |
||||
end |
||||
|
||||
context "when start_now is not set" do |
||||
let(:params) { { "notification": { title: "Updated Title", show_on_unauthenticated_pages: "1" } } } |
||||
|
||||
it "sets the relevant values on the notification" do |
||||
request |
||||
notification.reload |
||||
expect(notification.title).to eql("Updated Title") |
||||
expect(notification.start_date).to be_nil |
||||
end |
||||
|
||||
it "redirects to check answers" do |
||||
request |
||||
expect(response).to redirect_to(notification_check_answers_path(notification)) |
||||
end |
||||
end |
||||
|
||||
context "when show additional page is false" do |
||||
let(:notification) { create(:notification, show_additional_page: "0", link_text: "link", page_content: "page") } |
||||
let(:params) { { "notification": { show_additional_page: "0", link_text: "text", page_content: "content" } } } |
||||
|
||||
it "removes values for link_text and page_content" do |
||||
request |
||||
notification.reload |
||||
expect(notification.link_text).to be_nil |
||||
expect(notification.page_content).to be_nil |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "#delete" do |
||||
let(:notification) { create(:notification, end_date: nil) } |
||||
let(:request) { delete notification_delete_path(notification) } |
||||
|
||||
it "sets end_date on the notification" do |
||||
request |
||||
notification.reload |
||||
expect(notification.end_date).to be < Time.zone.now |
||||
end |
||||
end |
||||
end |
||||
|
||||
context "when user is signed in as a non-support user" do |
||||
let(:user) { create(:user, :data_coordinator) } |
||||
|
||||
before do |
||||
sign_in user |
||||
end |
||||
|
||||
describe "#create" do |
||||
let(:request) { post notifications_path, params: { "notification": { title: "Test Create" } } } |
||||
|
||||
it "returns not found" do |
||||
request |
||||
expect(response).to have_http_status(:not_found) |
||||
end |
||||
|
||||
it "does not create a notification" do |
||||
expect { request }.not_to change(Notification, :count) |
||||
end |
||||
end |
||||
|
||||
describe "#update" do |
||||
let(:notification) { create(:notification) } |
||||
let(:request) { patch notification_path(notification), params: { "notification": { title: "Test Update" } } } |
||||
|
||||
it "returns not found" do |
||||
request |
||||
expect(response).to have_http_status(:not_found) |
||||
end |
||||
end |
||||
|
||||
describe "#delete" do |
||||
let(:notification) { create(:notification, end_date: nil) } |
||||
let(:request) { delete notification_delete_path(notification) } |
||||
|
||||
it "returns not found" do |
||||
request |
||||
expect(response).to have_http_status(:not_found) |
||||
end |
||||
|
||||
it "does not set end_date on the notification" do |
||||
request |
||||
notification.reload |
||||
expect(notification.end_date).to be_nil |
||||
end |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue