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
3 changes: 2 additions & 1 deletion .review_apps/ecs_task_definition.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ locals {
{ name = "SETTINGS__AUTH_PROVIDER", value = "developer" },
{ name = "SETTINGS__FORMS_ENV", value = "review" },
{ name = "SETTINGS__FORMS_RUNNER__URL", value = "https://forms.service.gov.uk" },
{ name = "SETTINGS__FEATURES__SEND_FILLER_ANSWERS", value = "true" }
{ name = "SETTINGS__FEATURES__SEND_FILLER_ANSWERS", value = "true" },
{ name = "SETTINGS__FEATURES__SHOW_RELEVANT_ORGANISATIONS", value = "true" }
]
}

Expand Down
25 changes: 18 additions & 7 deletions app/controllers/account/organisations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,42 @@ class OrganisationsController < WebController
skip_before_action :redirect_if_account_not_completed

def edit
@organisation_input = OrganisationInput.new(user: current_user).assign_form_values
@organisation_input = OrganisationInput.new(user: current_user, allowed_organisations:).assign_form_values
end

def update
@organisation_input = OrganisationInput.new(account_organisation_input_params(current_user))
@organisation_input = OrganisationInput.new(account_organisation_input_params)

if @organisation_input.submit
if @organisation_input.not_listed_selected?
render :not_listed
elsif @organisation_input.submit
redirect_to next_path
else
render :edit, status: :unprocessable_content
end
end

def account_organisation_input_params(user)
params.require(:account_organisation_input).permit(:organisation_id).merge(user:)
end

private

def account_organisation_input_params
params.fetch(:account_organisation_input, {}).permit(:organisation_id)
.merge({ user: current_user, allowed_organisations: })
end

def redirect_if_organisation_exists
redirect_to root_path if current_user.organisation.present?
end

def next_path
after_sign_in_next_path
end

def allowed_organisations
if FeatureService.enabled?(:show_relevant_organisations)
Organisation.not_closed.for_domain(current_user.email_domain).order(:name)
else
Organisation.not_closed.order(:name)
end
end
end
end
18 changes: 16 additions & 2 deletions app/input_objects/account/organisation_input.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
class Account::OrganisationInput < BaseInput
attr_accessor :user, :organisation_id
attr_accessor :user, :allowed_organisations, :organisation_id

validates :organisation_id, presence: true
validates :organisation_id, presence: true, inclusion: { in: ->(record) { record.allowed_organisation_ids } }

NOT_LISTED_OPTION_VALUE = "not_listed".freeze

def submit
return false if invalid?
Expand All @@ -19,6 +21,18 @@ def assign_form_values
self
end

def radios?
FeatureService.enabled?(:show_relevant_organisations) && allowed_organisations.size <= 30
end

def not_listed_selected?
organisation_id == NOT_LISTED_OPTION_VALUE
end

def allowed_organisation_ids
allowed_organisations.pluck(:id).map(&:to_s)
end

private

def log_organisation_chosen_event
Expand Down
5 changes: 5 additions & 0 deletions app/models/organisation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ class Organisation < ApplicationRecord
end
}

scope :for_domain, lambda { |domain|
joins(:organisation_domains)
.where(organisation_domains: { domain: domain })
}

scope :order_by_user_count, lambda {
order(Arel.sql("(SELECT COUNT(*) FROM users WHERE users.organisation_id = organisations.id) DESC"))
.order(:name)
Expand Down
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ def as_json(options = {})
super(options)
end

def email_domain
email.split("@").last.downcase.strip
end

private

def requires_name?
Expand Down
72 changes: 55 additions & 17 deletions app/views/account/organisations/edit.html.erb
Original file line number Diff line number Diff line change
@@ -1,29 +1,67 @@
<% set_page_title(title_with_error_prefix(t('page_titles.account_organisation'), @organisation_input.errors.any?)) %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<%= form_with(model: @organisation_input , url: account_organisation_path, method: :patch) do |f| %>
<% if @organisation_input &.errors.any? %>
<%= form_with(model: @organisation_input, url: account_organisation_path, method: :patch) do |f| %>
<% if @organisation_input&.errors.any? %>
<%= f.govuk_error_summary %>
<% end %>

<%= render DfE::Autocomplete::View.new(
f,
attribute_name: :organisation_id,
form_field: f.govuk_collection_select(:organisation_id,
Organisation.not_closed.order(:name),
:id,
:name_with_abbreviation,
class: ['govuk-!-width-three-quarters'],
options: { prompt: t('users.edit.organisation_prompt') },
label: { size: 'xl', tag: 'h1' },
),
html_attributes: { 'data-show-all-values' => 'true'},
)%>
<% show_relevant_organisations_enabled = FeatureService.enabled?(:show_relevant_organisations) %>
<% if show_relevant_organisations_enabled %>
<h1 class="govuk-heading-l">
<%= t("page_titles.account_organisation") %>
</h1>

<p><%= t("account.organisation.you_created_account_with", email_domain: @organisation_input.user.email_domain) %></p>
<% end %>

<% if @organisation_input.radios? %>
<%= f.govuk_radio_buttons_fieldset(:organisation_id, legend: { size: 'm', tag: 'h2' }) do %>
<% @organisation_input.allowed_organisations.each.with_index do |organisation, index| %>
<%= f.govuk_radio_button(
:organisation_id,
organisation.id,
label: { text: organisation.name_with_abbreviation },
link_errors: index.zero?) %>
<% end %>

<%= f.govuk_radio_divider %>
<%= f.govuk_radio_button(
:organisation_id,
Account::OrganisationInput::NOT_LISTED_OPTION_VALUE,
label: { text: t("account.organisation.not_listed_option") },
link_errors: false
) %>
<% end %>
<% else %>
<% label_options = if show_relevant_organisations_enabled
{ size: 'm', tag: 'h2', text: t("helpers.legend.account_organisation_input.organisation_id") }
else
{ size: 'xl', tag: 'h1' }
end %>

<%= render DfE::Autocomplete::View.new(
f,
attribute_name: :organisation_id,
form_field: f.govuk_collection_select(
:organisation_id,
@organisation_input.allowed_organisations,
:id,
:name_with_abbreviation,
class: ['govuk-!-width-three-quarters'],
options: { prompt: t('users.edit.organisation_prompt') },
label: label_options,
),
html_attributes: { 'data-show-all-values' => 'true' },
) %>
<% end %>
<%= f.govuk_submit t("save_and_continue") %>
<% end %>

<%= govuk_section_break(visible:true, size: "l") %>
<%= govuk_details(summary_text: t('account.organisation_details_summary'), text: t('account.organisation_text_html', contact_link: contact_link)) %>
<% unless @organisation_input.radios? %>
<%= govuk_section_break(visible: true, size: "l") %>
<%= govuk_details(summary_text: t('account.organisation.details_summary'), text: t('account.organisation.not_listed_html', contact_link: contact_link)) %>
<% end %>
</div>
</div>

Expand Down
7 changes: 7 additions & 0 deletions app/views/account/organisations/not_listed.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<% set_page_title(t("page_titles.organisation_not_listed")) %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l"><%= t('page_titles.organisation_not_listed') %></h1>
<%= t('account.organisation.not_listed_html', contact_link: contact_link) %>
</div>
</div>
17 changes: 11 additions & 6 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
---
en:
account:
organisation_details_summary: If your organisation is not listed
organisation_text_html: |
<p>If you’re from a central government organisation that publishes content on the GOV.UK website but your organisation is not listed, please %{contact_link}.</p>
<p>If you’re from a public sector organisation that does not publish content on GOV.UK you cannot use GOV.UK Forms yet. You can <a href="https://www.forms.service.gov.uk/forthcoming-features">read about our forthcoming features and sign up to our mailing list</a> for updates.</p>
organisation:
details_summary: If your organisation is not listed
not_listed_html: |
<p>If you’re from a central government organisation that’s not listed, %{contact_link}.</p>
<p>At the moment, GOV.UK Forms is only available to central government organisations. If you’re from an organisation outside central government, you can <a href="https://www.forms.service.gov.uk/forthcoming-features">read about future plans for GOV.UK Forms</a>.</p>
not_listed_option: The organisation I work for is not listed
you_created_account_with: You created your account using an @%{email_domain} email address.
terms_of_use:
accessibility:
heading: Make forms that are easy to use and accessible
Expand Down Expand Up @@ -68,6 +71,7 @@ en:
attributes:
organisation_id:
blank: Select your organisation
inclusion: Select your organisation
account/terms_of_use_input:
attributes:
agreed:
Expand Down Expand Up @@ -964,8 +968,6 @@ en:
hint:
account_name_input:
name: You do not need to include a title or any middle names.
account_organisation_input:
organisation_id: Currently, GOV.UK Forms is only available for central government organisations that publish content on the GOV.UK website.
forms_copy_input:
name: The form name will be shown at the top of each page of the form. Use a name that describes what the form will help people to do. For example ‘Apply for a juggling licence’.
page:
Expand Down Expand Up @@ -1203,6 +1205,8 @@ en:
'false': One or more options
'true': One option only
legend:
account_organisation_input:
organisation_id: Which of these organisations do you work for?
account_terms_of_use_input:
agreed: Do you agree to these terms?
forms_batch_submissions_input:
Expand Down Expand Up @@ -1713,6 +1717,7 @@ en:
non_crown_agreement_confirmation: You’ve agreed to the GOV.UK Forms agreement
non_crown_agreement_new: GOV.UK Forms agreement
not_found: Page not found
organisation_not_listed: What to do if your organisation is not listed
organisations: Organisations
payment_link: Add a link to a payment page on GOV.UK Pay
privacy_policy: Provide a link to privacy information for this form
Expand Down
1 change: 1 addition & 0 deletions config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ features:
enabled_by_group: true
send_filler_answers:
enabled_by_group: true
show_relevant_organisations: false

forms_api:
# Authentication key to authenticate with forms-api
Expand Down
1 change: 1 addition & 0 deletions spec/config/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
include_examples expected_value_test, :exit_pages, features, { "enabled_by_group" => true }
include_examples expected_value_test, :multiple_branches, features, { "enabled_by_group" => true }
include_examples expected_value_test, :send_filler_answers, features, { "enabled_by_group" => true }
include_examples expected_value_test, :show_relevant_organisations, features, false
end

describe "forms_api" do
Expand Down
1 change: 1 addition & 0 deletions spec/factories/models/organisations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
name { slug.titleize }
abbreviation { name.split.collect(&:chr).join }
internal { false }
closed { false }

trait :with_signed_mou do
after(:build) do |organisation|
Expand Down
16 changes: 12 additions & 4 deletions spec/input_objects/account/organisation_input_spec.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
require "rails_helper"

describe Account::OrganisationInput do
subject(:organisation_input) { described_class.new(user:) }
subject(:organisation_input) { described_class.new(user:, allowed_organisations:) }

let(:user) { create(:user, :with_no_org) }
let(:organisation) { create(:organisation) }
let(:allowed_organisations) { [organisation, *create_list(:organisation, 2)] }

describe "validations" do
it "is valid with a valid organisation_id" do
organisation_input.organisation_id = organisation.id
organisation_input.organisation_id = organisation.id.to_s
expect(organisation_input).to be_valid
end

Expand All @@ -18,12 +19,19 @@
expect(organisation_input).to be_invalid
expect(organisation_input.errors[:organisation_id]).to include(error_message)
end

it "is invalid when the organisation is not in the allowed_organisations list" do
organisation_input.organisation_id = create(:organisation).id.to_s
error_message = I18n.t("activemodel.errors.models.account/organisation_input.attributes.organisation_id.inclusion")
expect(organisation_input).to be_invalid
expect(organisation_input.errors[:organisation_id]).to include(error_message)
end
end

describe "#submit" do
context "with valid attributes" do
before do
organisation_input.organisation_id = organisation.id
organisation_input.organisation_id = organisation.id.to_s
end

it "updates the user organisation_id" do
Expand All @@ -36,7 +44,7 @@

it "logs the organisation_chosen event" do
expect(Rails.logger).to receive(:info).with("User chose their organisation", {
organisation_id: organisation.id,
organisation_id: organisation.id.to_s,
})
organisation_input.submit
end
Expand Down
31 changes: 31 additions & 0 deletions spec/models/organisation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,37 @@
end
end

describe ".for_domain" do
it "returns all organisations with matching domain" do
matched_org = create(:organisation, organisation_domains: [
create(:organisation_domain, domain: "example.com"),
create(:organisation_domain, domain: "example.gov.uk"),
])
other_matched_org = create(:organisation, organisation_domains: [
create(:organisation_domain, domain: "example.com"),
])
create(:organisation, organisation_domains: [
create(:organisation_domain, domain: "example.gov.uk"),
])
create(:organisation)

expect(described_class.for_domain("example.com")).to contain_exactly(matched_org, other_matched_org)
end

it "does not return organisations with no domains set" do
create(:organisation)
expect(described_class.for_domain("example.com")).to be_empty
end

it "does not match an email with a subdomain of a domain associated with an organisation" do
create(:organisation, organisation_domains: [
create(:organisation_domain, domain: "example.com"),
])

expect(described_class.for_domain("subdomain.example.com")).to be_empty
end
end

describe ".order_by_live_form_count" do
let!(:organisation_with_two_live_forms) { create :organisation, slug: "org-with-two-live-forms" }
let!(:organisation_with_one_live_form) { create :organisation, slug: "org-with-one-live-form" }
Expand Down
12 changes: 12 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -597,4 +597,16 @@
}.to change(user, :last_signed_in_at).to(Time.zone.now)
end
end

describe "#email_domain" do
it "returns the domain part of the email" do
user = create(:user, email: "user@example.com")
expect(user.email_domain).to eq("example.com")
end

it "strips whitespace" do
user = create(:user, email: " user@example.com ")
expect(user.email_domain).to eq("example.com")
end
end
end
Loading