Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions app/controllers/organisation_brands_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,31 @@ def destroy
authorize organisation, :can_manage_organisation_brands?

organisation_brand = organisation.organisation_brands.find_by!(brand_id: params[:id])

if organisation.default_brand_id == organisation_brand.brand_id
return redirect_to organisation_path(organisation), status: :see_other
end

organisation_brand.destroy!

redirect_to organisation_path(organisation), success: t(".success", brand_name: organisation_brand.brand.name)
end

def update_default
authorize organisation, :can_manage_organisation_brands?

if params[:brand_id].present?
brand = organisation.brands.find(params[:brand_id])
organisation.update!(default_brand: brand)

redirect_to organisation_path(organisation), success: t(".success", brand_name: brand.name)
else
organisation.update!(default_brand: nil)

redirect_to organisation_path(organisation), success: t(".success_govuk")
end
end

private

def organisation
Expand Down
13 changes: 13 additions & 0 deletions app/models/organisation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class Organisation < ApplicationRecord
has_many :organisation_brands, dependent: :destroy
has_many :brands, -> { order(:name) }, through: :organisation_brands

belongs_to :default_brand, class_name: "Brand", optional: true

validate :default_brand_is_available, if: :default_brand_id_changed?

scope :not_closed, -> { where(closed: false) }
scope :with_users, -> { joins(:users).distinct.order(:name) }

Expand Down Expand Up @@ -73,4 +77,13 @@ def as_json(options = {})
options[:methods] ||= %i[organisation_admin_users]
super(options)
end

private

def default_brand_is_available
return if default_brand_id.nil?
return if organisation_brands.exists?(brand_id: default_brand_id)

errors.add(:default_brand, :not_available)
end
end
10 changes: 9 additions & 1 deletion app/services/create_form_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,19 @@ def create!(creator:, group:, name:)
if event.form_id.present?
form = Form.find(event.form_id)
else
form = Form.create!(creator_id: creator.id, name:)
form = Form.create!(creator_id: creator.id, name:, brand_id: default_brand_id(group))
GroupForm.create!(group:, form_id: form.id)
event.update!(form_id: form.id)
end

form
end

private

def default_brand_id(group)
return nil unless FeatureService.new(group:).enabled?(:custom_branding)

group.organisation.default_brand&.slug
end
end
57 changes: 39 additions & 18 deletions app/views/organisations/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -113,30 +113,51 @@

<h2 class="govuk-heading-m"><%= t("organisations.show.brands.heading") %></h2>
<p class="govuk-body"><%= t("organisations.show.brands.guidance") %></p>
<% if @organisation.brands.any? %>
<%= render ScrollingWrapperComponent::View.new(aria_label: t("organisations.show.brands.heading")) do %>
<%= govuk_table do |table| %>
<%= table.with_head do |head|
head.with_row do |row|
row.with_cell(header: true, text: t("organisations.show.brands.table_headings.name"))
row.with_cell(header: true, text: t("organisations.show.brands.table_headings.actions"))
end
end %>

<%= table.with_body do |body| %>
<% @organisation.brands.each do |brand| %>
<%= body.with_row do |row| %>
<%= row.with_cell { govuk_link_to(brand.name, brand_path(brand)) } %>
<%= row.with_cell do %>
<%= govuk_button_to(t("organisations.show.brands.remove"), organisation_brand_path(@organisation, brand), method: :delete, secondary: true) %>
<%= render ScrollingWrapperComponent::View.new(aria_label: t("organisations.show.brands.heading")) do %>
<%= govuk_table do |table| %>
<%= table.with_head do |head|
head.with_row do |row|
row.with_cell(header: true, text: t("organisations.show.brands.table_headings.name"))
row.with_cell(header: true, text: t("organisations.show.brands.table_headings.actions"))
end
end %>

<%= table.with_body do |body| %>
<%= body.with_row do |row| %>
<%= row.with_cell do %>
<%= t("organisations.show.brands.govuk_brand_name") %>
<% if @organisation.default_brand_id.nil? %>
<%= govuk_tag(text: t("organisations.show.brands.default_tag"), colour: "green") %>
<% end %>
<% end %>
<%= row.with_cell do %>
<% if @organisation.default_brand_id.present? %>
<%= govuk_button_to(t("organisations.show.brands.make_default"), organisation_default_brand_path(@organisation), method: :patch, secondary: true, visually_hidden_suffix: t("organisations.show.brands.govuk_brand_name"), class: "govuk-!-margin-bottom-0") %>
<% end %>
<% end %>
<% end %>
<% @organisation.brands.each do |brand| %>
<%= body.with_row do |row| %>
<%= row.with_cell do %>
<%= govuk_link_to(brand.name, brand_path(brand)) %>
<% if brand.id == @organisation.default_brand_id %>
<%= govuk_tag(text: t("organisations.show.brands.default_tag"), colour: "green") %>
<% end %>
<% end %>
<%= row.with_cell do %>
<% if brand.id == @organisation.default_brand_id %>
<%= govuk_button_to(t("organisations.show.brands.remove"), organisation_brand_path(@organisation, brand), method: :delete, secondary: true, disabled: true, visually_hidden_suffix: brand.name, class: "govuk-!-margin-bottom-0") %>
<% else %>
<div class="govuk-button-group govuk-!-margin-bottom-0">
<%= govuk_button_to(t("organisations.show.brands.make_default"), organisation_default_brand_path(@organisation), method: :patch, params: { brand_id: brand.id }, secondary: true, visually_hidden_suffix: brand.name, class: "govuk-!-margin-bottom-0") %>
<%= govuk_button_to(t("organisations.show.brands.remove"), organisation_brand_path(@organisation, brand), method: :delete, secondary: true, visually_hidden_suffix: brand.name, class: "govuk-!-margin-bottom-0") %>
</div>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% else %>
<p class="govuk-body"><%= t("organisations.show.brands.none") %></p>
<% end %>

<%= govuk_button_link_to t("organisations.show.brands.add"), new_organisation_brand_path(@organisation), secondary: true %>
Expand Down
13 changes: 11 additions & 2 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ en:
agreed:
crown: You must agree to the memorandum of understanding
non_crown: You must agree to the agreement to continue
organisation:
attributes:
default_brand:
not_available: The default brand must be one of the organisation’s available brands
organisation_domain:
attributes:
domain:
Expand Down Expand Up @@ -1501,6 +1505,9 @@ en:
prompt: Select a brand
submit: Add brand
title: Add a brand
update_default:
success: "%{brand_name} is now the default brand for new forms in this organisation"
success_govuk: New forms in this organisation will use GOV.UK branding
organisations:
boolean:
'false': 'No'
Expand Down Expand Up @@ -1545,9 +1552,11 @@ en:
none: This organisation does not have any organisation admins.
brands:
add: Add a brand
guidance: Add brands to make them available for forms in this organisation to use. Forms that already use a brand will continue to use it, even if you remove the brand from this organisation.
default_tag: Default
govuk_brand_name: GOV.UK
guidance: Add brands to make them available for forms in this organisation to use. New forms will use the default brand, and people editing a form can change its brand. Forms that already use a brand will continue to use it, even if you remove the brand from this organisation.
heading: Available brands
none: This organisation does not have any available brands. Forms use the default GOV.UK branding.
make_default: Make default
remove: Remove
table_headings:
actions: Actions
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@

resources :organisations, only: %i[index show] do
resources :brands, controller: :organisation_brands, only: %i[new create destroy]
patch "default-brand", to: "organisation_brands#update_default", as: :default_brand
end

resources :brands, only: %i[index show new create edit update]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddDefaultBrandToOrganisations < ActiveRecord::Migration[8.1]
def change
add_reference :organisations, :default_brand, null: true, foreign_key: { to_table: :brands }
end
end
5 changes: 4 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions spec/models/organisation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,43 @@
end
end

describe "default brand" do
let(:organisation) { create :organisation }
let(:brand) { create :brand }

it "is valid when the default brand is one of the organisation's brands" do
create(:organisation_brand, organisation:, brand:)

organisation.default_brand = brand

expect(organisation).to be_valid
end

it "is invalid when the default brand is not one of the organisation's brands" do
organisation.default_brand = brand

expect(organisation).to be_invalid
expect(organisation.errors.of_kind?(:default_brand, :not_available)).to be true
end

it "is valid to clear the default brand" do
create(:organisation_brand, organisation:, brand:)
organisation.update!(default_brand: brand)

organisation.default_brand = nil

expect(organisation).to be_valid
end

it "does not validate the default brand unless it is changing" do
create(:organisation_brand, organisation:, brand:)
organisation.update!(default_brand: brand)
organisation.organisation_brands.delete_all

expect { organisation.update!(name: "Renamed Organisation") }.not_to raise_error
end
end

describe "scopes" do
describe ".with_users" do
it "returns organisations with distinct users" do
Expand Down
97 changes: 97 additions & 0 deletions spec/requests/organisation_brands_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,103 @@
expect(response).to have_http_status(:not_found)
end
end

context "when the brand is the organisation's default brand" do
before do
organisation.update!(default_brand: brand)
end

it "does not remove the brand from the organisation" do
expect {
delete path
}.not_to(change { organisation.brands.count })
end

it "redirects to the organisation page without a success message" do
delete path

expect(response).to redirect_to(organisation_path(organisation))
expect(flash[:success]).to be_nil
end
end
end
end

describe "#update_default" do
let(:path) { organisation_default_brand_path(organisation) }
let(:params) { { brand_id: brand.id } }

before do
create :organisation_brand, organisation:, brand:
end

context "when the user is not a super admin" do
before do
login_as_standard_user

patch(path, params:)
end

it "returns http code 403 and renders forbidden" do
expect(response).to have_http_status(:forbidden)
expect(response).to render_template("errors/forbidden")
end

it "does not change the organisation's default brand" do
expect(organisation.reload.default_brand).to be_nil
end
end

context "when the user is a super admin" do
before do
login_as_super_admin_user
end

it "sets the organisation's default brand" do
patch(path, params:)

expect(organisation.reload.default_brand).to eq(brand)
end

it "redirects to the organisation page with a success message" do
patch(path, params:)

expect(response).to redirect_to(organisation_path(organisation))
expect(flash[:success]).to eq(I18n.t("organisation_brands.update_default.success", brand_name: brand.name))
end

context "when no brand is given" do
let(:params) { {} }

before do
organisation.update!(default_brand: brand)
end

it "clears the organisation's default brand" do
patch(path, params:)

expect(organisation.reload.default_brand).to be_nil
end

it "redirects to the organisation page with a success message" do
patch(path, params:)

expect(response).to redirect_to(organisation_path(organisation))
expect(flash[:success]).to eq(I18n.t("organisation_brands.update_default.success_govuk"))
end
end

context "when the brand is not one of the organisation's brands" do
let(:other_brand) { create :brand }
let(:params) { { brand_id: other_brand.id } }

it "returns http code 404 and does not change the default brand" do
patch(path, params:)

expect(response).to have_http_status(:not_found)
expect(organisation.reload.default_brand).to be_nil
end
end
end
end
end
Loading