<%= render partial: "users/user_filters" %>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index 7f42107f8..a43b03f82 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -11,6 +11,15 @@
<% end %>
<% end %>
+<% if display_pending_email_change_banner?(@user) %>
+ <%= govuk_notification_banner(title_text: "Important") do %>
+
+ <%= pending_email_change_banner_text(current_user) %>
+ <% end %>
+<% end %>
+
diff --git a/db/migrate/20240905092332_add_organisation_id_to_bulk_uploads.rb b/db/migrate/20240905092332_add_organisation_id_to_bulk_uploads.rb
new file mode 100644
index 000000000..d9f4f16da
--- /dev/null
+++ b/db/migrate/20240905092332_add_organisation_id_to_bulk_uploads.rb
@@ -0,0 +1,5 @@
+class AddOrganisationIdToBulkUploads < ActiveRecord::Migration[7.0]
+ def change
+ add_column :bulk_uploads, :organisation_id, :integer
+ end
+end
diff --git a/db/migrate/20240923145326_add_validation_checked_field.rb b/db/migrate/20240923145326_add_validation_checked_field.rb
new file mode 100644
index 000000000..899992974
--- /dev/null
+++ b/db/migrate/20240923145326_add_validation_checked_field.rb
@@ -0,0 +1,5 @@
+class AddValidationCheckedField < ActiveRecord::Migration[7.0]
+ def change
+ add_column :log_validations, :checked, :boolean
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 80463eaad..4d6f18b84 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2024_09_18_112702) do
+ActiveRecord::Schema[7.0].define(version: 2024_09_23_145326) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -42,6 +42,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_09_18_112702) do
t.text "choice"
t.integer "total_logs_count"
t.string "rent_type_fix_status", default: "not_applied"
+ t.integer "organisation_id"
t.integer "moved_user_id"
t.index ["identifier"], name: "index_bulk_uploads_on_identifier", unique: true
t.index ["user_id"], name: "index_bulk_uploads_on_user_id"
@@ -410,6 +411,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_09_18_112702) do
t.string "other_validated_models"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.boolean "checked"
end
create_table "logs_exports", force: :cascade do |t|
diff --git a/spec/factories/bulk_upload.rb b/spec/factories/bulk_upload.rb
index c848fb071..cefe95c2b 100644
--- a/spec/factories/bulk_upload.rb
+++ b/spec/factories/bulk_upload.rb
@@ -9,6 +9,7 @@ FactoryBot.define do
sequence(:filename) { |n| "bulk-upload-#{n}.csv" }
needstype { 1 }
rent_type_fix_status { BulkUpload.rent_type_fix_statuses.values.sample }
+ organisation_id { user.organisation_id }
trait(:sales) do
log_type { BulkUpload.log_types[:sales] }
diff --git a/spec/features/organisation_spec.rb b/spec/features/organisation_spec.rb
index 1867285eb..3d65cda87 100644
--- a/spec/features/organisation_spec.rb
+++ b/spec/features/organisation_spec.rb
@@ -139,6 +139,10 @@ RSpec.describe "User Features" do
expect(page).to have_button("Create a new lettings log for this organisation")
end
+ it "shows a upload lettings logs in bulk link" do
+ expect(page).to have_link("Upload lettings logs in bulk")
+ end
+
context "when creating a log for that organisation" do
it "pre-fills the value for owning organisation for that log" do
click_button("Create a new lettings log for this organisation")
@@ -230,6 +234,10 @@ RSpec.describe "User Features" do
expect(page).to have_button("Create a new sales log for this organisation")
end
+ it "shows a upload sales logs in bulk link" do
+ expect(page).to have_link("Upload sales logs in bulk")
+ end
+
context "when creating a log for that organisation" do
it "pre-fills the value for owning organisation for that log" do
click_button("Create a new sales log for this organisation")
diff --git a/spec/helpers/user_helper_spec.rb b/spec/helpers/user_helper_spec.rb
index c88790aa0..eb0a672db 100644
--- a/spec/helpers/user_helper_spec.rb
+++ b/spec/helpers/user_helper_spec.rb
@@ -105,6 +105,32 @@ RSpec.describe UserHelper do
end
end
+ describe "display_pending_email_change_banner?" do
+ context "when the user doesn't have an unconfirmed email" do
+ let(:user) { FactoryBot.create(:user, :data_provider, unconfirmed_email: nil) }
+
+ it "does not display pending email change banner" do
+ expect(display_pending_email_change_banner?(user)).to be false
+ end
+ end
+
+ context "when the user has the same unconfirmed email as current email" do
+ let(:user) { FactoryBot.create(:user, :data_provider, unconfirmed_email: "updated_email@example.com", email: "updated_email@example.com") }
+
+ it "does not display pending email change banner" do
+ expect(display_pending_email_change_banner?(user)).to be false
+ end
+ end
+
+ context "when the user has a different unconfirmed email" do
+ let(:user) { FactoryBot.create(:user, :data_provider, unconfirmed_email: "updated_email@example.com", email: "old_email@example.com") }
+
+ it "displays pending email change banner" do
+ expect(display_pending_email_change_banner?(user)).to be true
+ end
+ end
+ end
+
describe "organisation_change_confirmation_warning" do
context "when user owns logs" do
before do
@@ -147,4 +173,39 @@ RSpec.describe UserHelper do
end
end
end
+
+ describe "pending_email_change_title_text" do
+ let(:user) { FactoryBot.create(:user, :data_provider, unconfirmed_email: "updated_email@example.com", email: "old_email@example.com") }
+ let(:current_user) { FactoryBot.create(:user, :support) }
+
+ context "when viewing own profile" do
+ it "returns the correct text" do
+ expect(pending_email_change_title_text(user, user)).to eq("You have requested to change your email address to updated_email@example.com.")
+ end
+ end
+
+ context "when viewing another user's profile" do
+ it "returns the correct text" do
+ expect(pending_email_change_title_text(current_user, user)).to eq("There has been a request to change this user’s email address to updated_email@example.com.")
+ end
+ end
+ end
+
+ describe "pending_email_change_banner_text" do
+ context "with provider user" do
+ let(:user) { FactoryBot.create(:user, :data_provider) }
+
+ it "returns the correct text" do
+ expect(pending_email_change_banner_text(user)).to eq("A confirmation link has been sent to the new email address. The current email will continue to work until the change is confirmed.")
+ end
+ end
+
+ context "with support user" do
+ let(:user) { FactoryBot.create(:user, :support) }
+
+ it "returns the correct text" do
+ expect(pending_email_change_banner_text(user)).to eq("A confirmation link has been sent to the new email address. The current email will continue to work until the change is confirmed. Deactivating this user will cancel the email change request.")
+ end
+ end
+ end
end
diff --git a/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
index 3faa0a699..68de5d22b 100644
--- a/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
+++ b/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
@@ -815,6 +815,23 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
end
+ context "when blank and bulk upload user is support" do
+ let(:bulk_upload) { create(:bulk_upload, :sales, user: create(:user, :support), year: 2024) }
+
+ let(:attributes) { setup_section_params.merge(bulk_upload:, field_3: nil) }
+
+ it "is not permitted" do
+ parser.valid?
+ expect(parser.errors[:field_3]).to be_present
+ expect(parser.errors[:field_3]).to include("You must answer what is the CORE username of the account this letting log should be assigned to?")
+ end
+
+ it "blocks log creation" do
+ parser.valid?
+ expect(parser).to be_block_log_creation
+ end
+ end
+
context "when user could not be found" do
let(:attributes) { { bulk_upload:, field_3: "idonotexist@example.com" } }
@@ -1439,6 +1456,43 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.errors[:field_10]).to include(/Enter a date when the owning and managing organisation was active/)
end
end
+
+ context "when user is an unaffiliated non-support user and bulk upload organisation is affiliated with the owning organisation" do
+ let(:affiliated_org) { create(:organisation, :with_old_visible_id) }
+ let(:unaffiliated_user) { create(:user, organisation: create(:organisation)) }
+ let(:attributes) { { bulk_upload:, field_1: affiliated_org.old_visible_id } }
+ let(:organisation_id) { unaffiliated_user.organisation_id }
+
+ before do
+ create(:organisation_relationship, parent_organisation: owning_org, child_organisation: affiliated_org)
+ bulk_upload.update!(organisation_id:, user: unaffiliated_user)
+ end
+
+ it "blocks log creation and adds an error to field_1" do
+ parser = described_class.new(attributes)
+ parser.valid?
+ expect(parser).to be_block_log_creation
+ expect(parser.errors[:field_1]).to include("You do not have permission to add logs for this owning organisation")
+ end
+ end
+
+ context "when user is an unaffiliated support user and bulk upload organisation is affiliated with the owning organisation" do
+ let(:affiliated_org) { create(:organisation, :with_old_visible_id) }
+ let(:unaffiliated_support_user) { create(:user, :support, organisation: create(:organisation)) }
+ let(:attributes) { { bulk_upload:, field_1: affiliated_org.old_visible_id } }
+ let(:organisation_id) { affiliated_org.id }
+
+ before do
+ create(:organisation_relationship, parent_organisation: owning_org, child_organisation: affiliated_org)
+ bulk_upload.update!(organisation_id:, user: unaffiliated_support_user)
+ end
+
+ it "does not block log creation and does not add an error to field_1" do
+ parser = described_class.new(attributes)
+ parser.valid?
+ expect(parser.errors[:field_1]).not_to include("You do not have permission to add logs for this owning organisation")
+ end
+ end
end
describe "#field_2" do # managing org
diff --git a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
index e428f7792..ca8f29e92 100644
--- a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
+++ b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
@@ -554,6 +554,43 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
expect(parser.errors[:field_6]).to include(/Enter a date when the owning organisation was active/)
end
end
+
+ context "when user is an unaffiliated non-support user and bulk upload organisation is affiliated with the owning organisation" do
+ let(:affiliated_org) { create(:organisation, :with_old_visible_id) }
+ let(:unaffiliated_user) { create(:user, organisation: create(:organisation)) }
+ let(:attributes) { { bulk_upload:, field_1: affiliated_org.old_visible_id } }
+ let(:organisation_id) { unaffiliated_user.organisation_id }
+
+ before do
+ create(:organisation_relationship, parent_organisation: owning_org, child_organisation: affiliated_org)
+ bulk_upload.update!(organisation_id:, user: unaffiliated_user)
+ end
+
+ it "blocks log creation and adds an error to field_1" do
+ parser = described_class.new(attributes)
+ parser.valid?
+ expect(parser).to be_block_log_creation
+ expect(parser.errors[:field_1]).to include("You do not have permission to add logs for this owning organisation")
+ end
+ end
+
+ context "when user is an unaffiliated support user and bulk upload organisation is affiliated with the owning organisation" do
+ let(:affiliated_org) { create(:organisation, :with_old_visible_id) }
+ let(:unaffiliated_support_user) { create(:user, :support, organisation: create(:organisation)) }
+ let(:attributes) { { bulk_upload:, field_1: affiliated_org.old_visible_id } }
+ let(:organisation_id) { affiliated_org.id }
+
+ before do
+ create(:organisation_relationship, parent_organisation: owning_org, child_organisation: affiliated_org)
+ bulk_upload.update!(organisation_id:, user: unaffiliated_support_user)
+ end
+
+ it "does not block log creation and does not add an error to field_1" do
+ parser = described_class.new(attributes)
+ parser.valid?
+ expect(parser.errors[:field_1]).not_to include("You do not have permission to add logs for this owning organisation")
+ end
+ end
end
describe "#field_3" do # username for assigned_to
@@ -576,6 +613,23 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
end
end
+ context "when blank and bulk upload user is support" do
+ let(:bulk_upload) { create(:bulk_upload, :sales, user: create(:user, :support), year: 2024) }
+
+ let(:attributes) { setup_section_params.merge(bulk_upload:, field_3: nil) }
+
+ it "is not permitted" do
+ parser.valid?
+ expect(parser.errors[:field_3]).to be_present
+ expect(parser.errors[:field_3]).to include("You must answer what is the CORE username of the account this sales log should be assigned to?")
+ end
+
+ it "blocks log creation" do
+ parser.valid?
+ expect(parser).to be_block_log_creation
+ end
+ end
+
context "when user could not be found" do
let(:attributes) { { bulk_upload:, field_3: "idonotexist@example.com" } }